AlarmManager流程

1 类型 【AlarmManager流程】在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;
2 用法

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); }

3 AlarmManager
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) { } }

4 AlarmManagerService
@Override public void onStart() { mNativeData = https://www.it610.com/article/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(); } }

5 JNI 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(ret);
}
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);
}

6 驱动
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 =https://www.it610.com/article/= 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 = https://www.it610.com/article/(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; }

7 RTC 就是如果系统没有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里面还有电,寄存器里面数据还是有的(掉电就会丢失数据),所以闹钟到了,通过硬件中断机制就可以唤醒系统。

    推荐阅读