Android的aralm可以唤醒系统,先看ararm调用过程
http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/app/AlarmManager.java
public void set(@AlarmType int type, long triggerAtMillis, PendingIntent operation) {
setImpl(type, triggerAtMillis, legacyExactLength(), 0, 0, operation, null, null,
null, null, null);
}
private void setImpl(@AlarmType int type, long triggerAtMillis, long windowMillis,long intervalMillis, int flags, PendingIntent operation, final OnAlarmListener listener,String listenerTag, Handler targetHandler, WorkSource workSource,AlarmClockInfo alarmClock) {
mService.set(mPackageName, type, triggerAtMillis, windowMillis, intervalMillis, flags,
operation, recipientWrapper, listenerTag, workSource, alarmClock);
}
private final IBinder mService = new IAlarmManager.Stub() {
@Override
public void set(String callingPackage,
int type, long triggerAtTime, long windowLength, long interval, int flags,
PendingIntent operation, IAlarmListener directReceiver, String listenerTag,
WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock) {
setImpl(type, triggerAtTime, windowLength, interval, operation, directReceiver,
listenerTag, flags, workSource, alarmClock, callingUid, callingPackage);
}
}
void setImpl(int type, long triggerAtTime, long windowLength, long interval,
PendingIntent operation, IAlarmListener directReceiver, String listenerTag,
int flags, WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock,
int callingUid, String callingPackage) {
setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed,
interval, operation, directReceiver, listenerTag, flags, true, workSource,
alarmClock, callingUid, callingPackage);
}
private void setImplLocked(int type, long when, long whenElapsed, long windowLength,
long maxWhen, long interval, PendingIntent operation, IAlarmListener directReceiver,
String listenerTag, int flags, boolean doValidate, WorkSource workSource,
AlarmManager.AlarmClockInfo alarmClock, int callingUid, String callingPackage) {
Alarm a = new Alarm(type, when, whenElapsed, windowLength, maxWhen, interval,
operation, directReceiver, listenerTag, workSource, flags, alarmClock,
callingUid, callingPackage);
setImplLocked(a, false, doValidate);
}
private void setImplLocked(Alarm a, boolean rebatching, boolean doValidate) {
rescheduleKernelAlarmsLocked();
}
void rescheduleKernelAlarmsLocked() {
setLocked(ELAPSED_REALTIME, nextNonWakeup);
}
private void setLocked(int type, long when) {
final int result = set(mNativeData, type, alarmSeconds, alarmNanoseconds);
}
private native int set(long nativeData, int type, long seconds, long nanoseconds);
static const JNINativeMethod sMethods[] = {
{"set", "(JIJJ)I", (void*)android_server_AlarmManagerService_set},
}
static jint android_server_AlarmManagerService_set(JNIEnv*, jobject, jlong nativeData, jint type, jlong seconds, jlong nanoseconds)
{
const int result = impl->set(type, &ts);
}
int AlarmImpl::set(int type, struct timespec *ts)
{
return timerfd_settime(fds[type], TFD_TIMER_ABSTIME, &spec, NULL);
}
通过系统调用设置内核时间
SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags,
const struct itimerspec __user *, utmr,
struct itimerspec __user *, otmr)
{
struct itimerspec new, old;
int ret;
if (copy_from_user(&new, utmr, sizeof(new)))
return -EFAULT;
ret = do_timerfd_settime(ufd, flags, &new, &old);
if (ret)
return ret;
if (otmr && copy_to_user(otmr, &old, sizeof(old)))
return -EFAULT;
return ret;
}
找最近的一个唤醒闹钟,设置到rtc里,时间到了,rtc产生中断唤醒cpu
static const struct dev_pm_ops alarmtimer_pm_ops = {
.suspend = alarmtimer_suspend,
};
static struct platform_driver alarmtimer_driver = {
.driver = {
.name = "alarmtimer",
.pm = &alarmtimer_pm_ops,
},
.shutdown = alarmtimer_shutdown,
};
static int alarmtimer_suspend(struct device *dev)
{
struct rtc_time tm, tm_set;
ktime_t min, now, set_time;
unsigned long flags;
struct rtc_device *rtc;
struct rtc_wkalrm alarm;
int i, ret = 0;
spin_lock_irqsave(&freezer_delta_lock, flags);
min = freezer_delta;
freezer_delta = ktime_set(0, 0);
spin_unlock_irqrestore(&freezer_delta_lock, flags);
rtc = alarmtimer_get_rtcdev();
/* If we have no rtcdev, just return */
if (!rtc)
return 0;
/* Find the soonest timer to expire*/
for (i = 0; i < ALARM_NUMTYPE; i++) {
struct alarm_base *base = &alarm_bases[i];
struct timerqueue_node *next;
ktime_t delta;
spin_lock_irqsave(&base->lock, flags);
next = timerqueue_getnext(&base->timerqueue);
spin_unlock_irqrestore(&base->lock, flags);
if (!next)
continue;
delta = ktime_sub(next->expires, base->gettime());
if (!min.tv64 || (delta.tv64 < min.tv64))
min = delta;
}
if (min.tv64 == 0)
return 0;
if (ktime_to_ns(min) < 2 * NSEC_PER_SEC) {
__pm_wakeup_event(ws, 2 * MSEC_PER_SEC);
return -EBUSY;
}
/* Setup an rtc timer to fire that far in the future */
rtc_timer_cancel(rtc, &rtctimer);
rtc_read_time(rtc, &tm);
now = rtc_tm_to_ktime(tm);
set_time = ktime_add(now, min);
tm_set = rtc_ktime_to_tm(set_time);
pr_info("Suspend alarm: %d-%d-%d %d:%d:%d\n", tm_set.tm_year + 1900,
tm_set.tm_mon + 1, tm_set.tm_mday, tm_set.tm_hour,
tm_set.tm_min, tm_set.tm_sec);
alarm.time = tm_set;
alarm.enabled = 1;
if (rtc->ops && rtc->ops->set_alarm) {
ret = rtc->ops->ioctl(rtc->dev.parent,
SET_WAKE_ALARM, (unsigned long)&alarm);
/* Set alarm, if in the past reject suspend briefly to handle */
if (ret < 0) {
pr_err("Suspend alarm setting error %d\n", ret);
__pm_wakeup_event(ws, MSEC_PER_SEC);
}
}
return ret;
}
某次抓的log如下,也就是说ararm的唤醒都是可预期的(Suspend ararm是格林威治时间,转换成北京时间需+8)
[09-24 17:35:00.017] <6>[ 53.283769] c0 Suspend alarm: 2019-9-24 9:35:0
[09-24 17:35:06.009] <6>[ 55.383820] c0 Suspend alarm: 2019-9-24 9:35:6
[09-24 17:35:12.010] <6>[ 57.593710] c0 Suspend alarm: 2019-9-24 9:35:12
[09-24 17:39:03.010] <6>[ 59.693765] c0 Suspend alarm: 2019-9-24 9:39:3
[09-24 17:45:00.024] <6>[ 61.804539] c0 Suspend alarm: 2019-9-24 9:45:0
[09-24 18:00:00.024] <6>[ 64.024533] c0 Suspend alarm: 2019-9-24 10:0:0
[09-24 18:15:00.023] <6>[ 66.244466] c0 Suspend alarm: 2019-9-24 10:15:0
[09-24 18:30:00.024] <6>[ 68.364377] c0 Suspend alarm: 2019-9-24 10:30:0
[09-24 18:33:47.025] <6>[ 70.584263] c0 Suspend alarm: 2019-9-24 10:45:0
[09-24 18:33:57.023] <6>[ 72.104397] c0 Suspend alarm: 2019-9-24 10:45:0
[09-24 18:38:08.025] <6>[ 72.724177] c0 Suspend alarm: 2019-9-24 10:45:0
[09-24 17:35:00.041] <6>[ 53.298469] c0 RTC ***** interrupt happen
[09-24 17:35:06.015] <6>[ 55.397274] c0 RTC ***** interrupt happen
[09-24 17:35:12.015] <6>[ 57.607150] c0 RTC ***** interrupt happen
[09-24 17:39:03.015] <6>[ 59.707245] c0 RTC ***** interrupt happen
[09-24 17:45:00.068] <6>[ 61.827663] c0 RTC ***** interrupt happen
[09-24 18:00:00.030] <6>[ 64.047574] c0 RTC ***** interrupt happen
[09-24 18:15:00.030] <6>[ 66.267515] c0 RTC ***** interrupt happen
Android上层通过poll一直在监听ararm,接收到通知后,将相应的事件进行分发。只有type类型为0或者2的alarm客户唤醒系统。可以根据打印信息查找唤醒系统的闹钟,如
09-19 15:00:05.968 813 952 D AlarmManager: sending alarm.type = 2, action = com.android.providers.calendar.intent.CalendarProvider2, cn = ComponentInfo{com.android.providers.calendar/com.android.providers.calendar.CalendarProviderBroadcastReceiver}, operation = PendingIntent{3eaf5c8: PendingIntentRecord{29dc661 com.android.providers.calendar broadcastIntent}}
09-19 15:01:46.941 813 952 D AlarmManager: sending alarm.type = 0, action = null, cn = ComponentInfo{cn.showmac.vsimservice/cn.jpush.android.service.AlarmReceiver}, operation = PendingIntent{ec569d7: PendingIntentRecord{c33696d cn.showmac.vsimservice broadcastIntent}}
public class AlarmManager {
public static final int RTC_WAKEUP = 0;
public static final int RTC = 1;
public static final int ELAPSED_REALTIME_WAKEUP = 2;
public static final int ELAPSED_REALTIME = 3;
}
private class AlarmThread extends Thread
{
public AlarmThread()
{
super("AlarmManager");
}
public void run()
{
ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
while (true)
{
int result = waitForAlarm(mNativeData);
deliverAlarmsLocked();
}
}
此外,休眠后,系统默认每10min(展讯的15min,看代码定义)唤醒一次系统,更新电池状态,也是通过定时器实现的,代码如下
http://androidxref.com/9.0.0_r3/xref/hardware/interfaces/health/2.0/default/healthd_common.cpp
static void wakealarm_init(void) {
wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK);
wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);
}
static int healthd_init() {
wakealarm_init();
}
设置成15分钟,从上面的唤醒时间9.45,10:00,10:15,10:30也跟代码的一致。
// Periodic chores fast interval in seconds
#define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (60 * 1)
// Periodic chores fast interval in seconds
#define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (60 * 10)
void healthd_battery_update_internal(bool charger_online) {
int new_wake_interval = charger_online ? healthd_config.periodic_chores_interval_fast
: healthd_config.periodic_chores_interval_slow;
if (new_wake_interval != wakealarm_wake_interval) wakealarm_set_interval(new_wake_interval);
}