在M版本里,Alarm有以下几种方式
/**
* Alarm time in {@link System#currentTimeMillis System.currentTimeMillis()}
* (wall clock time in UTC), which will wake up the device when
* it goes off.
*/
public static final int RTC_WAKEUP = 0;
/**
* Alarm time in {@link System#currentTimeMillis System.currentTimeMillis()}
* (wall clock time in UTC). This alarm does not wake the
* device up; if it goes off while the device is asleep, it will not be
* delivered until the next time the device wakes up.
*/
public static final int RTC = 1;
/**
* Alarm time in {@link android.os.SystemClock#elapsedRealtime
* SystemClock.elapsedRealtime()} (time since boot, including sleep),
* which will wake up the device when it goes off.
*/
public static final int ELAPSED_REALTIME_WAKEUP = 2;
/**
* Alarm time in {@link android.os.SystemClock#elapsedRealtime
* SystemClock.elapsedRealtime()} (time since boot, including sleep).
* This alarm does not wake the device up; if it goes off while the device
* is asleep, it will not be delivered until the next time the device
* wakes up.
*/
public static final int ELAPSED_REALTIME = 3;
public static void enableAlert(Context context, final Alarm alarm, final long atTimeInMillis) {
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Log.iRelease(TAG, "enableAlert : setAlert id = " + alarm.id + " atTime = " + formatDate(atTimeInMillis)
+ " alarmType = " + alarm.daysOfWeekType);
Intent intent = new Intent(ALARM_ALERT_ACTION);
Parcel out = Parcel.obtain();
alarm.writeToParcel(out, 0);
out.setDataPosition(0);
intent.putExtra(ALARM_RAW_DATA, out.marshall());
int userid= UserHandle.getUserId(Binder.getCallingUid());
intent.putExtra(USER_DATA, userid == UserHandle.USER_OWNER);
PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
if (Utils.isKitKatOrLater()) {
am.setExact(AlarmManager.RTC_WAKEUP, atTimeInMillis, sender);
} else {
am.set(AlarmManager.RTC_WAKEUP, atTimeInMillis, sender);
}
Calendar c = Calendar.getInstance();
c.setTimeInMillis(atTimeInMillis);
String timeString = formatDayAndTime(context, c);
saveNextAlarm(context, timeString);
saveNextHwAlarm(context, timeString, atTimeInMillis);
setStatusBarIcon(context, true);
setNowAlertAlarmId(context, alarm.id);
out.recycle();
}
public static void disableAlert(Context context) {
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(ALARM_ALERT_ACTION);
/**
* remove_poweroff_alarm_anyway : has not alarm in database, or not alarm enable.
* will remove poweroff alarm.
*/
int userid= UserHandle.getUserId(Binder.getCallingUid());
if (userid == UserHandle.USER_OWNER) {
intent.putExtra(Config.REMOVE_POWEROFF_ALARM_ANYWAY, true);
}
PendingIntent sender = PendingIntent.getBroadcast(context, 0,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
am.cancel(sender);
saveNextAlarm(context, "");
saveNextHwAlarm(context, "", 0);
setStatusBarIcon(context, false);
}
public void set(int type, long triggerAtMillis, PendingIntent operation) {
setImpl(type, triggerAtMillis, legacyExactLength(), 0, operation, null, null);
}
private void setImpl(int type, long triggerAtMillis, long windowMillis, long intervalMillis,
PendingIntent operation, WorkSource workSource, AlarmClockInfo alarmClock) {
if (triggerAtMillis < 0) {
/* NOTYET
if (mAlwaysExact) {
// Fatal error for KLP+ apps to use negative trigger times
throw new IllegalArgumentException("Invalid alarm trigger time "
+ triggerAtMillis);
}
*/
triggerAtMillis = 0;
}
try {
mService.set(type, triggerAtMillis, windowMillis, intervalMillis, operation,
workSource, alarmClock);
} catch (RemoteException ex) {
}
}
@Override
public void onStart() {
mNativeData = init();
........
if (mNativeData != 0) {
AlarmThread waitThread = new AlarmThread();
waitThread.start();
} else {
Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler.");
}
publishBinderService(Context.ALARM_SERVICE, mService);
}
private class AlarmThread extends Thread
{
public AlarmThread()
{
super("AlarmManager");
}
public void run()
{
ArrayList triggerList = new ArrayList();
while (true)
{
int result = waitForAlarm(mNativeData);
......
Message msg = Message.obtain();
msg.what =AlarmHandler.HANDLE_DELIVERALARMS;
msg.obj = triggerList; mHandler.removeMessages(AlarmHandler.HANDLE_DELIVERALARMS); mHandler.sendMessageDelayed(msg, 50);
}
@Override
protected void finalize() throws Throwable {
try {
close(mNativeData);
} finally {
super.finalize();
}
}
com_android_server_AlarmManagerService.cpp
static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject)
{
jlong ret = init_alarm_driver();
if (ret) {
return ret;
}
return init_timerfd();
}
static jlong init_alarm_driver()
{
int fd = open("/dev/alarm", O_RDWR);
if (fd < 0) {
ALOGV("opening alarm driver failed: %s", strerror(errno));
return 0;
}
AlarmImpl *ret = new AlarmImplAlarmDriver(fd);
return reinterpret_cast
}
int AlarmImplAlarmDriver::set(int type, struct timespec *ts)
{
return ioctl(fds[0], ANDROID_ALARM_SET(type), ts);
}
int AlarmImplAlarmDriver::waitForAlarm()
{
return ioctl(fds[0], ANDROID_ALARM_WAIT);
}
static long alarm_do_ioctl(struct file *file, unsigned int cmd,
struct timespec *ts)
{
int rv = 0;
unsigned long flags;
enum android_alarm_type alarm_type = ANDROID_ALARM_IOCTL_TO_TYPE(cmd);
if (alarm_type >= ANDROID_ALARM_TYPE_COUNT)
return -EINVAL;
if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_GET_TIME(0)) {
if ((file->f_flags & O_ACCMODE) == O_RDONLY)
return -EPERM;
if (file->private_data == NULL &&
cmd != ANDROID_ALARM_SET_RTC) {
spin_lock_irqsave(&alarm_slock, flags);
if (alarm_opened) {
spin_unlock_irqrestore(&alarm_slock, flags);
return -EBUSY;
}
alarm_opened = 1;
file->private_data = (void *)1;
spin_unlock_irqrestore(&alarm_slock, flags);
}
}
switch (ANDROID_ALARM_BASE_CMD(cmd)) {
case ANDROID_RTC_ALARM_SET: /* add for poweroff alarm */
rv = alarm_set_rtc_alarm(ts->tv_sec, true);
break;
case ANDROID_ALARM_CLEAR(0):
alarm_clear(alarm_type);
break;
case ANDROID_ALARM_SET(0):
alarm_set(alarm_type, ts);
break;
case ANDROID_ALARM_SET_AND_WAIT(0):
alarm_set(alarm_type, ts);
/* fall though */
case ANDROID_ALARM_WAIT:
rv = alarm_wait();
break;
case ANDROID_ALARM_SET_RTC:
rv = alarm_set_rtc(ts);
break;
case ANDROID_ALARM_GET_TIME(0):
rv = alarm_get_time(alarm_type, ts);
break;
default:
rv = -EINVAL;
}
return rv;
}
就是如果系统没有suspend的时候,设置闹钟并不会往rtc 芯片的寄存器上写数据,因为不需要唤醒系统,所以闹钟数据时间什么的就通过上层写到设备文件/dev/alarm
里面就可以了,AlarmThread 会不停的去轮寻下一个时间有没有闹钟,直接从设备文件 /dev/alarm 里面读取
第二种,系统要是进入susupend的话,alarm 的alarm_suspend 就会写到下层的rtc芯片的寄存器上去, 然后即使系统suspend之后,闹钟通过rtc 也能唤醒系统。
这里就调用到了interface.c 里面 //这里面 int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) 差不多 也是跟下面一样
int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
{
....
err = rtc->ops->set_time(rtc->dev.parent, tm);
....
}
然后set_time 就看到具体的是那个RTC芯片,这边我们是rtc-hym8563.c
然后就到了
static int hym8563_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[], __u16 len)
{
int ret;
ret = i2c_master_reg8_send(client, reg, buf, (int)len, RTC_SPEED);
return ret;
}
到此,闹钟时间就已经写到rtc 芯片的寄存器里面,第二个参数就是寄存器的名字,后面的buf就是要写入的时间,rtc芯片是额外供电的,所以系统suspend之后,系统kernel都关了,但是rtc里面还有电,寄存器里面数据还是有的(掉电就会丢失数据),所以闹钟到了,通过硬件中断机制就可以唤醒系统。