当前位置:   article > 正文

alarm唤醒系统过程分析_wakealarm编写

wakealarm编写

Android的aralm可以唤醒系统,先看ararm调用过程

http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/app/AlarmManager.java

  1. public void set(@AlarmType int type, long triggerAtMillis, PendingIntent operation) {
  2.         setImpl(type, triggerAtMillis, legacyExactLength(), 0, 0, operation, null, null,
  3.                 null, null, null);
  4. }
  1. 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) {
  2. mService.set(mPackageName, type, triggerAtMillis, windowMillis, intervalMillis, flags,
  3. operation, recipientWrapper, listenerTag, workSource, alarmClock);
  4. }

http://androidxref.com/9.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/AlarmManagerService.java

  1. private final IBinder mService = new IAlarmManager.Stub() {
  2. @Override
  3. public void set(String callingPackage,
  4. int type, long triggerAtTime, long windowLength, long interval, int flags,
  5. PendingIntent operation, IAlarmListener directReceiver, String listenerTag,
  6. WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock) {
  7. setImpl(type, triggerAtTime, windowLength, interval, operation, directReceiver,
  8. listenerTag, flags, workSource, alarmClock, callingUid, callingPackage);
  9. }
  10. }
  1. void setImpl(int type, long triggerAtTime, long windowLength, long interval,
  2. PendingIntent operation, IAlarmListener directReceiver, String listenerTag,
  3. int flags, WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock,
  4. int callingUid, String callingPackage) {
  5. setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed,
  6. interval, operation, directReceiver, listenerTag, flags, true, workSource,
  7. alarmClock, callingUid, callingPackage);
  8. }
  1. private void setImplLocked(int type, long when, long whenElapsed, long windowLength,
  2. long maxWhen, long interval, PendingIntent operation, IAlarmListener directReceiver,
  3. String listenerTag, int flags, boolean doValidate, WorkSource workSource,
  4. AlarmManager.AlarmClockInfo alarmClock, int callingUid, String callingPackage) {
  5. Alarm a = new Alarm(type, when, whenElapsed, windowLength, maxWhen, interval,
  6. operation, directReceiver, listenerTag, workSource, flags, alarmClock,
  7. callingUid, callingPackage);
  8. setImplLocked(a, false, doValidate);
  9. }
  1. private void setImplLocked(Alarm a, boolean rebatching, boolean doValidate) {
  2. rescheduleKernelAlarmsLocked();
  3. }
  1. void rescheduleKernelAlarmsLocked() {
  2. setLocked(ELAPSED_REALTIME, nextNonWakeup);
  3. }
  1. private void setLocked(int type, long when) {
  2. final int result = set(mNativeData, type, alarmSeconds, alarmNanoseconds);
  3. }
private native int set(long nativeData, int type, long seconds, long nanoseconds);

http://androidxref.com/9.0.0_r3/xref/frameworks/base/services/core/jni/com_android_server_AlarmManagerService.cpp

  1. static const JNINativeMethod sMethods[] = {
  2. {"set", "(JIJJ)I", (void*)android_server_AlarmManagerService_set},
  3. }
  4. static jint android_server_AlarmManagerService_set(JNIEnv*, jobject, jlong nativeData, jint type, jlong seconds, jlong nanoseconds)
  5. {
  6. const int result = impl->set(type, &ts);
  7. }
  8. int AlarmImpl::set(int type, struct timespec *ts)
  9. {
  10. return timerfd_settime(fds[type], TFD_TIMER_ABSTIME, &spec, NULL);
  11. }

通过系统调用设置内核时间

  1. SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags,
  2. const struct itimerspec __user *, utmr,
  3. struct itimerspec __user *, otmr)
  4. {
  5. struct itimerspec new, old;
  6. int ret;
  7. if (copy_from_user(&new, utmr, sizeof(new)))
  8. return -EFAULT;
  9. ret = do_timerfd_settime(ufd, flags, &new, &old);
  10. if (ret)
  11. return ret;
  12. if (otmr && copy_to_user(otmr, &old, sizeof(old)))
  13. return -EFAULT;
  14. return ret;
  15. }

找最近的一个唤醒闹钟,设置到rtc里,时间到了,rtc产生中断唤醒cpu 

  1. static const struct dev_pm_ops alarmtimer_pm_ops = {
  2. .suspend = alarmtimer_suspend,
  3. };
  4. static struct platform_driver alarmtimer_driver = {
  5. .driver = {
  6. .name = "alarmtimer",
  7. .pm = &alarmtimer_pm_ops,
  8. },
  9. .shutdown = alarmtimer_shutdown,
  10. };
  11. static int alarmtimer_suspend(struct device *dev)
  12. {
  13. struct rtc_time tm, tm_set;
  14. ktime_t min, now, set_time;
  15. unsigned long flags;
  16. struct rtc_device *rtc;
  17. struct rtc_wkalrm alarm;
  18. int i, ret = 0;
  19. spin_lock_irqsave(&freezer_delta_lock, flags);
  20. min = freezer_delta;
  21. freezer_delta = ktime_set(0, 0);
  22. spin_unlock_irqrestore(&freezer_delta_lock, flags);
  23. rtc = alarmtimer_get_rtcdev();
  24. /* If we have no rtcdev, just return */
  25. if (!rtc)
  26. return 0;
  27. /* Find the soonest timer to expire*/
  28. for (i = 0; i < ALARM_NUMTYPE; i++) {
  29. struct alarm_base *base = &alarm_bases[i];
  30. struct timerqueue_node *next;
  31. ktime_t delta;
  32. spin_lock_irqsave(&base->lock, flags);
  33. next = timerqueue_getnext(&base->timerqueue);
  34. spin_unlock_irqrestore(&base->lock, flags);
  35. if (!next)
  36. continue;
  37. delta = ktime_sub(next->expires, base->gettime());
  38. if (!min.tv64 || (delta.tv64 < min.tv64))
  39. min = delta;
  40. }
  41. if (min.tv64 == 0)
  42. return 0;
  43. if (ktime_to_ns(min) < 2 * NSEC_PER_SEC) {
  44. __pm_wakeup_event(ws, 2 * MSEC_PER_SEC);
  45. return -EBUSY;
  46. }
  47. /* Setup an rtc timer to fire that far in the future */
  48. rtc_timer_cancel(rtc, &rtctimer);
  49. rtc_read_time(rtc, &tm);
  50. now = rtc_tm_to_ktime(tm);
  51. set_time = ktime_add(now, min);
  52. tm_set = rtc_ktime_to_tm(set_time);
  53. pr_info("Suspend alarm: %d-%d-%d %d:%d:%d\n", tm_set.tm_year + 1900,
  54. tm_set.tm_mon + 1, tm_set.tm_mday, tm_set.tm_hour,
  55. tm_set.tm_min, tm_set.tm_sec);
  56. alarm.time = tm_set;
  57. alarm.enabled = 1;
  58. if (rtc->ops && rtc->ops->set_alarm) {
  59. ret = rtc->ops->ioctl(rtc->dev.parent,
  60. SET_WAKE_ALARM, (unsigned long)&alarm);
  61. /* Set alarm, if in the past reject suspend briefly to handle */
  62. if (ret < 0) {
  63. pr_err("Suspend alarm setting error %d\n", ret);
  64. __pm_wakeup_event(ws, MSEC_PER_SEC);
  65. }
  66. }
  67. return ret;
  68. }

 某次抓的log如下,也就是说ararm的唤醒都是可预期的(Suspend ararm是格林威治时间,转换成北京时间需+8)

  1. [09-24 17:35:00.017] <6>[ 53.283769] c0 Suspend alarm: 2019-9-24 9:35:0
  2. [09-24 17:35:06.009] <6>[ 55.383820] c0 Suspend alarm: 2019-9-24 9:35:6
  3. [09-24 17:35:12.010] <6>[ 57.593710] c0 Suspend alarm: 2019-9-24 9:35:12
  4. [09-24 17:39:03.010] <6>[ 59.693765] c0 Suspend alarm: 2019-9-24 9:39:3
  5. [09-24 17:45:00.024] <6>[ 61.804539] c0 Suspend alarm: 2019-9-24 9:45:0
  6. [09-24 18:00:00.024] <6>[ 64.024533] c0 Suspend alarm: 2019-9-24 10:0:0
  7. [09-24 18:15:00.023] <6>[ 66.244466] c0 Suspend alarm: 2019-9-24 10:15:0
  8. [09-24 18:30:00.024] <6>[ 68.364377] c0 Suspend alarm: 2019-9-24 10:30:0
  9. [09-24 18:33:47.025] <6>[ 70.584263] c0 Suspend alarm: 2019-9-24 10:45:0
  10. [09-24 18:33:57.023] <6>[ 72.104397] c0 Suspend alarm: 2019-9-24 10:45:0
  11. [09-24 18:38:08.025] <6>[ 72.724177] c0 Suspend alarm: 2019-9-24 10:45:0
  12. [09-24 17:35:00.041] <6>[ 53.298469] c0 RTC ***** interrupt happen
  13. [09-24 17:35:06.015] <6>[ 55.397274] c0 RTC ***** interrupt happen
  14. [09-24 17:35:12.015] <6>[ 57.607150] c0 RTC ***** interrupt happen
  15. [09-24 17:39:03.015] <6>[ 59.707245] c0 RTC ***** interrupt happen
  16. [09-24 17:45:00.068] <6>[ 61.827663] c0 RTC ***** interrupt happen
  17. [09-24 18:00:00.030] <6>[ 64.047574] c0 RTC ***** interrupt happen
  18. [09-24 18:15:00.030] <6>[ 66.267515] c0 RTC ***** interrupt happen

Android上层通过poll一直在监听ararm,接收到通知后,将相应的事件进行分发。只有type类型为0或者2的alarm客户唤醒系统。可以根据打印信息查找唤醒系统的闹钟,如

  1. 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}}
  2. 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}}
  1. public class AlarmManager {
  2. public static final int RTC_WAKEUP = 0;
  3. public static final int RTC = 1;
  4. public static final int ELAPSED_REALTIME_WAKEUP = 2;
  5. public static final int ELAPSED_REALTIME = 3;
  6. }
  1. private class AlarmThread extends Thread
  2. {
  3. public AlarmThread()
  4. {
  5. super("AlarmManager");
  6. }
  7. public void run()
  8. {
  9. ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
  10. while (true)
  11. {
  12. int result = waitForAlarm(mNativeData);
  13. deliverAlarmsLocked();
  14. }

此外,休眠后,系统默认每10min(展讯的15min,看代码定义)唤醒一次系统,更新电池状态,也是通过定时器实现的,代码如下

http://androidxref.com/9.0.0_r3/xref/hardware/interfaces/health/2.0/default/healthd_common.cpp

  1. static void wakealarm_init(void) {
  2. wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK);
  3. wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);
  4. }
  5. static int healthd_init() {
  6. wakealarm_init();
  7. }

设置成15分钟,从上面的唤醒时间9.45,10:00,10:15,10:30也跟代码的一致。

  1. // Periodic chores fast interval in seconds
  2. #define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (60 * 1)
  3. // Periodic chores fast interval in seconds
  4. #define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (60 * 10)
  5. void healthd_battery_update_internal(bool charger_online) {
  6. int new_wake_interval = charger_online ? healthd_config.periodic_chores_interval_fast
  7. : healthd_config.periodic_chores_interval_slow;
  8. if (new_wake_interval != wakealarm_wake_interval) wakealarm_set_interval(new_wake_interval);
  9. }

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/817981
推荐阅读
相关标签
  

闽ICP备14008679号