Alarm的触发过程
下图1是alarm触发的一个大致流程。
首先应用会调用AlarmManager提供的set接口,将一个含有触发时间和触发事件的alarm对象添加到一个由AlarmManager服务维护的alarm列表中,同时alarm列表会计算出最优先的alarm对象(最先起来)设置到底层RTC设备中。但这个时间点到了,RTC会上发信息并通知AlarmManager服务去触发相应的事件。
Alarm管理机制的变化
Android4.4以及后面的版本对Alarm的管理发生了比较大的变化,首先来看下AlarmManager的构造方法。
AlarmManager(IAlarmManager service, Context ctx) {
mService = service;
final int sdkVersion = ctx.getApplicationInfo().targetSdkVersion;
mAlwaysExact = (sdkVersion < Build.VERSION_CODES.KITKAT);
}
private long legacyExactLength() {
return (mAlwaysExact ? WINDOW_EXACT : WINDOW_HEURISTIC);
}
从Android 4.4版本开始引入了Exact闹钟的概念,既然有Exact(精确),那自然有非精确,但为了兼容旧版本,可以看到legacyExactLength方法中,如果sdkVersion是API19(Android4.4)之前的,所有的闹钟都是精确的闹钟,否则是Heuristic的。
接下来看看set方法的注释:
* Beginning in API 19, the trigger time passed to this method
* is treated as inexact: the alarm will not be delivered before this time, but
* may be deferred and delivered some time later. The OS will use
* this policy in order to "batch" alarms together across the entire system,
* minimizing the number of times the device needs to "wake up" and minimizing
* battery use. In general, alarms scheduled in the near future will not
* be deferred as long as alarms scheduled far in the future.
* With the new batching policy, delivery ordering guarantees are not as
* strong as they were previously. If the application sets multiple alarms,
* it is possible that these alarms' <em>actual</em> delivery ordering may not match
* the order of their <em>requested</em> delivery times. If your application has
* strong ordering requirements there are other APIs that you can use to get
* the necessary behavior; see {@link #setWindow(int, long, long, PendingIntent)}
* and {@link #setExact(int, long, PendingIntent)}.
* Applications whose {@code targetSdkVersion} is before API 19 will
* continue to get the previous alarm behavior: all of their scheduled alarms
* will be treated as exact.
翻译:从API19开始,通过这个方法设置的alarm都被认为是非精确的,这个alarm不会再设置的时间点之前触发,但可能会再设置的时间点后适当延迟触发。Android系统会根据一套规则,将一组触发时间类似的alarm以batch的形式保存下来,一旦batch的时间到了,便会将这个batch中的alarm一起触发,这样做的目的是将系统唤醒(如果是wake up类型的闹钟,首先需要唤醒系统)的次数降到最低,以达到省电的目的。
Batch的结构如图2: