Android 7系统休眠唤醒(八)内核层—Alarm定时唤醒与硬件唤醒源
系列目录第一篇电源管理架构全景图 | 第二篇开机全链路 | 第三篇关机/重启全链路 | 第四篇休眠唤醒与开关机对比 | 第五篇休眠全链路 | 第六篇唤醒全链路 | 第七篇wakelock与autosleep |第八篇Alarm定时唤醒与硬件唤醒源| 第九篇libsuspend与Power HAL | 第十篇实战调试一、为什么要深入理解 Alarm 唤醒你可能遇到过这些问题闹钟设置后设备休眠了还能准时响吗内核休眠时谁在计时为什么有些定时任务在 Doze 模式下不执行Alarm 被延迟了吗除了 RTC 闹钟还有哪些硬件能唤醒系统它们在内核中如何注册第七篇分析了 wakelock 如何阻止系统休眠本篇分析另一个方向——Alarm 系统如何定时唤醒系统。此外还将枚举 Android 设备中所有的硬件唤醒源以及它们在内核和驱动层的实现原理。二、定时唤醒的需求场景Alarm 是 Android 定时唤醒机制的核心支撑着以下典型场景闹钟用户在特定时间点被唤醒Doze 维护窗口Android 6 的 Doze 模式定期退出深度休眠以同步数据周期性任务JobScheduler / AlarmManager 的定时任务网络协议保活TCP keepalive、推送通道心跳系统维护定期检查更新、清理缓存这些场景的共同需求设备在指定时间点精确到毫秒从休眠中醒来。三、Android Alarm 的完整架构在深入源码之前先看整体架构。Alarm 系统从应用层到硬件层分为五个层次应用层 AlarmManager API (set / setExact / setRepeating / setAlarmClock) 框架层 AlarmManagerService (AMS的Alarm) 维护 Alarm 优先队列按触发时间排序 Native层 alarm_driver (timerfd / /dev/alarm / RTC_WAKEUP ioctl) 内核层 RTC (Real-Time Clock) 驱动 alarmtimer 子系统 → rtc_timer → 编程 RTC 硬件定时器 硬件层 RTC 芯片 PMIC (Power Management IC) 在 CPU 休眠期间持续运行 到达设定时间 → 产生硬件中断 → 唤醒 CPU关键设计Alarm 系统的核心是 RTC 硬件定时器。即使 CPU 进入 deep sleepRTC 芯片仍由独立电源供电持续计时到达设定时间后触发中断唤醒系统。四、AlarmManagerService — 框架层 Alarm 管理4.1 数据结构源码路径frameworks/base/services/core/java/com/android/server/AlarmManagerService.javaAlarmManagerService简称 AMS注意不是 ActivityManagerService维护一个按触发时间排序的批次队列// frameworks/base/services/core/java/com/android/server/AlarmManagerService.javapublicclassAlarmManagerServiceextendsSystemService{// ...finalArrayListBatchmAlarmBatchesnewArrayList();// 按触发时间排序的批次finalclassBatch{longstart;// 批次最早触发时间基于 elapsedRealtimelongend;// 批次最晚触发时间允许的最大延迟intflags;// 标志位如 FLAG_STANDALONEfinalArrayListAlarmalarmsnewArrayListAlarm();// 本批次的 Alarm 列表// ...}privatestaticclassAlarm{publicfinalinttype;// RTC_WAKEUP / RTC / ELAPSED_REALTIME_WAKEUP / ELAPSED_REALTIMEpublicfinallongwhenElapsed;// 触发时间基于 elapsedRealtimepublicfinallongmaxWhenElapsed;// 最晚触发时间publicfinalPendingIntentoperation;// 触发后执行的 PendingIntentpublicfinalStringpackageName;// 发起者包名publicfinalbooleanwakeup;// 是否唤醒设备// ...}}关键设计Batch将触发时间相近的 Alarm 合并为一个批次减少 CPU 唤醒次数。start和end定义了批次的触发窗口非精确闹钟可以在窗口内任意时刻触发。4.2 Alarm 类型类型时间基准是否唤醒设备RTC_WAKEUPSystem.currentTimeMillis() (墙上时间)✅ 唤醒RTCSystem.currentTimeMillis() (墙上时间)❌ 不唤醒ELAPSED_REALTIME_WAKEUPSystemClock.elapsedRealtime() (启动时间)✅ 唤醒ELAPSED_REALTIMESystemClock.elapsedRealtime() (启动时间)❌ 不唤醒_WAKEUP后缀表示设备休眠时仍需触发。不带_WAKEUP的仅在设备已经清醒时触发。4.3 时间基准的选择RTC 类型使用墙上时间wall clock受用户修改系统时间影响ELAPSED_REALTIME 类型使用开机以来的时间单调递增不受用户修改时间影响对于闹钟场景用 RTC 类型用户期望在确定的墙钟时间响起。对于每 30 分钟执行一次的周期性任务用 ELAPSED_REALTIME 更合适。4.4 Alarm 触发流程源码路径frameworks/base/services/core/java/com/android/server/AlarmManagerService.javaAlarmThread是AlarmManagerService的内部线程负责等待和分发 Alarm// frameworks/base/services/core/java/com/android/server/AlarmManagerService.javapublicclassAlarmManagerServiceextendsSystemService{// ...privatelongmNativeData;// Native 层 AlarmImpl 的指针privateclassAlarmThreadextendsThread{publicAlarmThread(){super(AlarmManager);}publicvoidrun(){ArrayListAlarmtriggerListnewArrayListAlarm();while(true){// 1. 等待 Native 层的 Alarm 驱动通知阻塞调用intresultwaitForAlarm(mNativeData);// 2. 获取当前时间finallongnowRTCSystem.currentTimeMillis();finallongnowELAPSEDSystemClock.elapsedRealtime();// 3. 处理时间变更通知if((resultTIME_CHANGED_MASK)!0){// 系统时间被修改重新调度所有 AlarmrebatchAllAlarms();}// 4. 取出所有到期的 Alarmsynchronized(mLock){booleanhasWakeuptriggerAlarmsLocked(triggerList,nowELAPSED,nowRTC);// ... 处理非唤醒 Alarm 的延迟逻辑 ...deliverAlarmsLocked(triggerList,nowELAPSED);// 分发 Alarm}// 5. 重新设置下一个最近的 AlarmrescheduleKernelAlarmsLocked();}}}privatenativeintwaitForAlarm(longnativeData);// JNI 调用}关键设计waitForAlarm()是 native 方法底层通过epoll_wait()阻塞在 timerfd 上。当 RTC 硬件定时器到期触发中断后timerfd 变为可读epoll_wait()返回线程继续处理到期的 Alarm。五、Native 层 — alarm 驱动交互5.1 timerfd 机制Android 4.4源码路径frameworks/base/services/core/jni/com_android_server_AlarmManagerService.cppAndroid 4.4 开始框架层的 Alarm 使用 Linux 标准timerfd代替了早期的/dev/alarm// frameworks/base/services/core/jni/com_android_server_AlarmManagerService.cppclassAlarmImplTimerFd:publicAlarmImpl{// ...intepollfd;// epoll 文件描述符intrtc_id;// RTC 设备 IDintset(inttype,structtimespec*ts){if(typeANDROID_ALARM_TYPE_COUNT){errnoEINVAL;return-1;}if(!ts-tv_nsec!ts-tv_sec){ts-tv_nsec1;// timerfd 解释 0 为解除替换为 1ns}structitimerspecspec;memset(spec,0,sizeof(spec));memcpy(spec.it_value,ts,sizeof(spec.it_value));returntimerfd_settime(fds[type],TFD_TIMER_ABSTIME,spec,NULL);// 设置定时器}intwaitForAlarm(){epoll_event events[N_ANDROID_TIMERFDS];intneventsepoll_wait(epollfd,events,N_ANDROID_TIMERFDS,-1);// 阻塞等待// ... 处理事件 ...returnresult;}};关键设计timerfd_settime()设置定时器到期时间epoll_wait()阻塞等待 timerfd 变为可读。CLOCK_BOOTTIME_ALARM类型的 timerfd 能在设备休眠时唤醒 CPU。六、内核层 — alarmtimer 子系统6.1 alarmtimer 架构源码路径kernel/msm-3.18/kernel/time/alarmtimer.c// kernel/time/alarmtimer.cstaticstructalarm_base{spinlock_tlock;// 自旋锁structtimerqueue_headtimerqueue;// 定时器队列红黑树ktime_t(*gettime)(void);// 获取当前时间的函数clockid_tbase_clockid;// 时钟类型}alarm_bases[ALARM_NUMTYPE];// RTC 定时器相关staticstructrtc_timerrtctimer;// RTC 定时器staticstructrtc_device*rtcdev;// RTC 设备alarmtimer 维护多个定时器队列alarm_bases数组每个队列对应一种时钟类型ALARM_REALTIME基于墙上时间的定时器ALARM_BOOTTIME基于启动时间的定时器timerfd 使用的就是此队列6.2 设置硬件 RTC 定时器源码路径kernel/msm-3.18/kernel/time/alarmtimer.c当添加 alarm 时需要将其插入定时器队列并在必要时编程 RTC 硬件// kernel/time/alarmtimer.cstaticvoidalarmtimer_enqueue(structalarm_base*base,structalarm*alarm){// 如果已入队先移除if(alarm-stateALARMTIMER_STATE_ENQUEUED)timerqueue_del(base-timerqueue,alarm-node);// 插入到定时器队列红黑树timerqueue_add(base-timerqueue,alarm-node);alarm-state|ALARMTIMER_STATE_ENQUEUED;}关键设计alarmtimer_enqueue()将 alarm 插入alarm_base的红黑树队列。插入后如果该 alarm 是队列中最早到期的内核会在系统休眠时通过alarmtimer_suspend()将其编程到 RTC 硬件。6.3 系统休眠时的 RTC 编程源码路径kernel/msm-3.18/kernel/time/alarmtimer.c当系统进入休眠时alarmtimer_suspend()会查找最近的 alarm 并编程 RTC 硬件// kernel/time/alarmtimer.cstaticintalarmtimer_suspend(structdevice*dev){structrtc_timetm;ktime_tmin,now;structrtc_device*rtc;inti;rtcalarmtimer_get_rtcdev();if(!rtc)return0;// 查找所有队列中最近的 alarmfor(i0;iALARM_NUMTYPE;i){structalarm_base*basealarm_bases[i];structtimerqueue_node*next;spin_lock_irqsave(base-lock,flags);nexttimerqueue_getnext(base-timerqueue);if(next(minnext-expires||!min)){minnext-expires;// 记录最近的到期时间}spin_unlock_irqrestore(base-lock,flags);}// 如果找到 alarm编程 RTC 硬件if(min){rtc_timer_cancel(rtc,rtctimer);// 设置 RTC 定时器在 min 时刻触发rtc_timer_start(rtc,rtctimer,min,ktime_set(0,0));}return0;}关键设计alarmtimer_suspend()在系统休眠前被调用它会遍历所有 alarm 队列找到最近的到期时间然后编程 RTC 硬件定时器。这样即使 CPU 进入 deep sleepRTC 芯片仍会在指定时刻触发中断唤醒系统。6.4 RTC 中断的唤醒路径当 RTC 硬件到达设定时间RTC 硬件定时器到期 → 产生 IRQ已在 suspend 前标记为 wakeup capable → 中断控制器唤醒 CPU → CPU 退出 deep sleep → RTC 驱动 IRQ handler 执行 → rtc_timer_handler() → alarmtimer 子系统收到通知 → 触发到期的 alarm 回调 → timerfd 变为可读 → epoll_wait 返回 → JNI 层 waitForAlarm() 返回 → Java 层 AlarmThread 继续处理七、硬件唤醒源全枚举除了 RTC AlarmAndroid 设备还存在多种硬件唤醒源。以下按类型枚举。7.1 GPIO 唤醒源最常见的按键类唤醒GPIO 源对应事件GPIO 标签示例电源键KEY_POWERgpio-keys音量 / 音量-KEY_VOLUMEUP / KEY_VOLUMEDOWNgpio-keysHome 键KEY_HOMEgpio-keys耳机插拔SW_HEADPHONE_INSERTheadset-detect内核中通过irq_set_irq_wake()注册为唤醒源详见第六篇。7.2 RTC实时时钟源rtc0通常挂载在 I2C/SPI 总线上内核驱动drivers/rtc/rtc-*.c如rtc-pm8xxx.c用于高通 PMIC中断名rtc0或pm8xxx_rtc7.3 Modem基带处理器源Modem 到 AP 的 IPC 中断来电、短信、网络事件高通设备的实现drivers/soc/qcom/smd.c或drivers/soc/qcom/glink.c中断名smd/glink/ipc_router7.4 USB 插拔源USB PHY 或充电 IC 的 VBUS 检测中断中断名usb-vbus/charger/usb_id7.5 WiFi源WiFi 芯片的 GPIO 唤醒线WOW — Wake on Wireless中断名wlan/wlan_hostwake用途收到推送通知时唤醒设备7.6 传感器源传感器 Hub 或独立传感器的中断线中断名sns/sensor_irq用途计步器、接近传感器、加速度计触发7.7 SD 卡源SD 卡检测引脚中断中断名sd_detect八、内核层的唤醒源查看接口8.1 /sys/power/wakeup_sources显示每个唤醒源的统计信息cat/sys/kernel/debug/wakeup_sources输出示例name active_count event_count wakeup_count expire_count ... event0 145 89 12 0 ... alarmtimer 2345 2345 456 0 ... wlan_wake 345 123 34 0 ... smd 89 45 15 0 ...8.2 /sys/power/wakeup_count以/sys/power/wakeup_sources统计为基础用于竞态检测见第五篇。8.3 /proc/interrupts直接查看每个中断的触发次数可以间接判断是哪个硬件唤醒源唤醒了设备cat/proc/interrupts|grep-Ertc|wake|key|wlan|smd九、Alarm 与 Doze 模式的交互Android 6 引入的 Doze 模式低电耗模式对 Alarm 的管理更严格9.1 Doze 维护窗口源码路径frameworks/base/services/core/java/com/android/server/DeviceIdleController.javaDoze 模式下设备进入深度休眠后Alarm 被限制只能在固定的维护窗口Maintenance Window触发设备进入 Doze 后非白名单应用的 Alarm 被延迟定期退出 Doze 的维护窗口期间批量处理积压的 Alarm随着进入 Doze 的时间增长维护窗口的间隔越来越长9.2 优先级分类类型Doze 下的行为API 方法普通 Alarm被延迟到下一个维护窗口set() / setRepeating()高优先级 Alarm允许立即触发setExact() / setExactAndAllowWhileIdle()闹钟 Alarm始终允许且系统会在触发前提前唤醒setAlarmClock()十、小结本篇完成了 Android Alarm 系统的完整分析框架层AlarmManagerService 维护触发时间优先队列AlarmThread 等待和分发 AlarmNative 层通过 timerfd (CLOCK_BOOTTIME_ALARM) 与内核 alarmtimer 交互内核层alarmtimer 子系统管理定时器红黑树编程 RTC 硬件定时器硬件层RTC 芯片在 CPU 休眠期间持续计时到期触发中断唤醒 CPU此外枚举了 GPIO 按键、RTC、Modem、USB、WiFi、传感器等主要硬件唤醒源以及/sys/power/wakeup_sources和/proc/interrupts等调试接口。下一篇将回到 Native 层深入 libsuspend 的实现细节和 Power HAL 的设计。

相关新闻

如何在Windows平台上实现智能化的演示时间管理?

如何在Windows平台上实现智能化的演示时间管理?

如何在Windows平台上实现智能化的演示时间管理? 【免费下载链接】ppttimer 一个简易的 PPT 计时器 项目地址: https://gitcode.com/gh_mirrors/pp/ppttimer 演示时间控制是专业演讲者面临的核心挑战之一。无论是学术会议、商务汇报还是教学场景,精…

2026/8/23 14:37:18 阅读更多 →
单片机C语言预处理指令实战:从宏定义到条件编译的嵌入式开发内功

单片机C语言预处理指令实战:从宏定义到条件编译的嵌入式开发内功

1. 项目概述:为什么预处理指令是单片机开发的“内功心法”?如果你刚开始玩单片机,可能觉得写代码就是对着芯片手册,把寄存器配置好,让LED灯闪起来就完事了。但当你真正开始做一个稍微复杂点的项目,比如要管…

2026/8/22 7:53:25 阅读更多 →
AI Agent开发入门:从零搭建智能体的完整链路与实践指南

AI Agent开发入门:从零搭建智能体的完整链路与实践指南

最近在技术社区里,经常看到有人问:AI Agent 开发到底从哪开始?是直接上手写代码,还是先学透 Transformer?是跟着热门项目跑一遍,还是先搞清楚 SFT 和 RLHF 的区别?更实际的问题是:学…

2026/8/21 16:42:40 阅读更多 →

最新新闻

Rydr计价引擎深度剖析:如何读懂网约车高峰加价、夜间时段与距离计费规则

Rydr计价引擎深度剖析:如何读懂网约车高峰加价、夜间时段与距离计费规则

Rydr计价引擎深度剖析:如何读懂网约车高峰加价、夜间时段与距离计费规则 【免费下载链接】rydr Rydr - A complete ride-hailing platform built with Spring Cloud microservices 项目地址: https://gitcode.com/gh_mirrors/on/rydr 想搞懂网约车平台如何算…

2026/8/26 14:46:59 阅读更多 →
如何让PC微信防撤回继续有效:防撤回补丁3步上手指南

如何让PC微信防撤回继续有效:防撤回补丁3步上手指南

如何让PC微信防撤回继续有效:防撤回补丁3步上手指南 【免费下载链接】RevokeMsgPatcher :trollface: A hex editor for WeChat/QQ/TIM - PC版微信/QQ/TIM防撤回补丁(我已经看到了,撤回也没用了) 项目地址: https://gitcode.com/…

2026/8/26 14:46:59 阅读更多 →
如何用SpringBoot快速实现接口幂等性设计

如何用SpringBoot快速实现接口幂等性设计

“下单按钮连点两次,结果生成了两个订单”——这不是段子,而是很多系统上线后最先暴露的脏数据来源。接口幂等性设计的本质,不是让接口“不能重复调用”,而是让重复调用产生与一次调用完全相同的效果。理解这一点至关重要&#xf…

2026/8/26 14:46:59 阅读更多 →
从一沓账单到可搜索的数字档案:Paperless-ngx 一键部署实战指南

从一沓账单到可搜索的数字档案:Paperless-ngx 一键部署实战指南

从一沓账单到可搜索的数字档案:Paperless-ngx 一键部署实战指南 【免费下载链接】paperless-ngx A community-supported supercharged document management system: scan, index and archive all your documents 项目地址: https://gitcode.com/GitHub_Trending/p…

2026/8/26 14:46:59 阅读更多 →
数字化转型核心引擎:智能排产系统(APS)

数字化转型核心引擎:智能排产系统(APS)

1. 引言:为什么智能排产会成为数字化转型的必答题过去十年,制造企业的数字化建设大多沿着“管理信息化 现场自动化”两条主线推进。企业上了 ERP、装了 MES、接入了 SCADA、构建了数据中台,生产现场的设备和传感器也越来越多。然而&#xff…

2026/8/26 14:46:58 阅读更多 →
数字化转型:工业人工智能时代的制造业数智化转型

数字化转型:工业人工智能时代的制造业数智化转型

一、引言:制造业正站在数智化转型的历史拐点 制造业始终是国民经济的压舱石,也是技术创新的主战场。从第一次工业革命的蒸汽机,到第二次工业革命的电力与流水线,再到第三次工业革命的自动化与信息化,每一次技术跃迁都…

2026/8/26 14:45:55 阅读更多 →

日新闻

Python random 模块常用函数详解:从入门到实战

Python random 模块常用函数详解:从入门到实战

目录 1. 引言2. 准备工作3. 基础随机函数4. 序列相关函数5. 随机种子与复现6. 实战案例7. 注意事项8. 常见问题与排查9. 总结 1. 引言 摘要: 本文系统介绍 Python 标准库 random 模块中最常用的随机数生成函数。内容涵盖基础随机函数(random()、unifor…

2026/8/26 0:00:40 阅读更多 →
《Microsoft Sql server 2008 Internals》读书笔记--第三章Databases and Database Files(2)

《Microsoft Sql server 2008 Internals》读书笔记--第三章Databases and Database Files(2)

《Microsoft Sql server 2008 Internals》索引目录: 《Microsoft Sql server 2008 Internals》读书笔记--目录索引 在上篇文章中,主要介绍了创建数据库的基本语法和FileGroup的初步知识。需要注意的是: 关于FileGroup 如果你的系统是用Raid设备直接存…

2026/8/26 1:18:18 阅读更多 →
政务AI智能体怎么建?三种模式、三步路径与四个误区

政务AI智能体怎么建?三种模式、三步路径与四个误区

政务AI智能体已经从概念试点阶段,转入了政务服务的常态化落地应用;在实际使用过程中,它能自主理解办事需求、辅助完成填报申报、开展材料预审,并联动多个系统协同作业,真正嵌入到政务办理的全流程当中。但在落地推进过…

2026/8/26 1:18:18 阅读更多 →

周新闻

[光学原理与应用-521]:对光的错误理解与纠偏

[光学原理与应用-521]:对光的错误理解与纠偏

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

2026/8/26 14:45:33 阅读更多 →
SIP通话转接原理与REFER方法实战解析

SIP通话转接原理与REFER方法实战解析

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

2026/8/25 3:38:18 阅读更多 →
Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

2026/8/26 14:46:37 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/26 3:50:20 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/25 10:31:12 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/26 1:24:05 阅读更多 →