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/7/29 4:04:52 阅读更多 →
单片机C语言预处理指令实战:从宏定义到条件编译的嵌入式开发内功

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

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

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

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

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

2026/7/29 4:04:52 阅读更多 →

最新新闻

萌新联赛萌新

萌新联赛萌新

I-Domino_河南萌新联赛2026第&#xff08;二&#xff09;场&#xff1a;河南农业大学 题目大意&#xff1a;遍历倒下的卡牌&#xff0c;记录这些卡牌倒下的范围&#xff0c;在<n中取最大值 思路&#xff1a;受第一块影响倒的这些卡牌&#xff0c;每个都要进行像第一块卡牌…

2026/7/29 4:13:55 阅读更多 →
基于Arduino与ESP8266的实时温度监控系统:从硬件连接到云端可视化

基于Arduino与ESP8266的实时温度监控系统:从硬件连接到云端可视化

1. 项目缘起&#xff1a;为什么需要“实时”监控温度&#xff1f;几年前&#xff0c;我负责一个存放精密电子元件的仓库环境管理。当时用的是市面上常见的带屏幕的温湿度计&#xff0c;每天需要人工巡检记录。问题就出在这个“每天”上。有一次&#xff0c;空调半夜故障停机&am…

2026/7/29 4:13:55 阅读更多 →
有录网在2026留学服务榜单中的表现评估

有录网在2026留学服务榜单中的表现评估

在竞争激烈的留学服务市场中&#xff0c;学生和家长在选择留学中介时往往会关注服务模式、申请结果、机构资质和投诉治理等多个方面。有录网在2026年的表现究竟如何&#xff0c;本文将展开多维度测评。多岗协作&#xff0c;保障服务流程稳定有录网开创了顾问、文书、申请、签证…

2026/7/29 4:13:55 阅读更多 →
CTK插件框架实战:C++/Qt模块化开发与动态加载指南

CTK插件框架实战:C++/Qt模块化开发与动态加载指南

1. 项目概述&#xff1a;为什么我们需要CTK这样的插件框架&#xff1f;在桌面应用开发&#xff0c;尤其是像医疗影像、工业控制这类大型、复杂的专业软件领域&#xff0c;一个核心的痛点就是&#xff1a;软件功能会随着时间不断膨胀&#xff0c;但开发和维护的团队可能分散&…

2026/7/29 4:13:55 阅读更多 →
llama.cpp:轻量级LLM推理引擎的CPU优化与量化技术

llama.cpp:轻量级LLM推理引擎的CPU优化与量化技术

1. llama.cpp项目概述llama.cpp是一个用C编写的轻量级LLM&#xff08;大语言模型&#xff09;推理引擎&#xff0c;最初由Georgi Gerganov开发&#xff0c;目的是在消费级硬件上高效运行Meta的LLaMA系列模型。这个项目最大的特点是完全摆脱了对NVIDIA CUDA的依赖&#xff0c;仅…

2026/7/29 4:13:55 阅读更多 →
从LED驱动到MCU控制:一个硬件工程师的汽车尾灯模组实战设计全解析

从LED驱动到MCU控制:一个硬件工程师的汽车尾灯模组实战设计全解析

1. 项目概述&#xff1a;从“尾灯模组”说起&#xff0c;一个硬件工程师的实战拆解“尾灯模组”这四个字&#xff0c;在汽车电子、消费电子乃至创客圈里&#xff0c;都是一个既经典又充满挑战的课题。乍一看&#xff0c;它不就是让几个LED亮起来、灭下去&#xff0c;再搞点流水…

2026/7/29 4:12:55 阅读更多 →

日新闻

【RT-DETR多模态创新改进】CVPR 2025 | 独家特征融合创新改进篇 | 引入RLAB残差线性注意力模块,有效融合并强调多尺度特征,多种改进点,适合红外与可见光融合目标检测任务,有效涨点

【RT-DETR多模态创新改进】CVPR 2025 | 独家特征融合创新改进篇 | 引入RLAB残差线性注意力模块,有效融合并强调多尺度特征,多种改进点,适合红外与可见光融合目标检测任务,有效涨点

一、本文介绍 🔥本文在RT-DETR多模态融合目标检测中引入RLAB残差线性注意力模块,可在不同模态特征交互阶段进行多次残差细化,使可见光、红外等特征在尺度、语义和空间位置上更好对齐;随后将细化特征与解码器输出拼接并生成Q、K、V,通过线性注意力自适应强化关键通道、目…

2026/7/29 0:00:23 阅读更多 →
AI编程系列02:合并知识功能,给 AI 问数和 RAG 场景打基础

AI编程系列02:合并知识功能,给 AI 问数和 RAG 场景打基础

AI编程系列02&#xff1a;合并知识功能&#xff0c;给 AI 问数和 RAG 场景打基础 在上一期「AI编程系列」中&#xff0c;我们学习了如何构建一个基础的 AI 问答系统&#xff0c;通过简单的输入输出让模型回应问题。但现实世界中的 AI 应用往往需要处理更复杂的场景&#xff1a;…

2026/7/29 0:00:23 阅读更多 →
AI智能体开发实战:从工具调用到企业级部署

AI智能体开发实战:从工具调用到企业级部署

1. 从被动问答到主动执行&#xff1a;AI Agent的范式转变过去两年&#xff0c;大语言模型最显著的应用形态是聊天机器人——用户提问&#xff0c;AI回答。但真正的生产力革命发生在2023年下半年&#xff1a;当AI学会主动调用工具完成任务时&#xff0c;生产力工具的历史被彻底改…

2026/7/29 0:00:23 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档&#xff0c;可以直接使用&#xff01;系统支持图片、视频、摄像头等多种方式检测裂缝&#xff0c;功能强大实用。 1数据集6000张 8各类别

2026/7/28 12:04:22 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像&#xff01; pubg绝地求生目标检测数据集 1分类&#xff1a;e_body&#xff0c;14905个标签&#xff0c;txt格式 共计14244张图&#xff0c;99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/28 8:29:16 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别&#xff1a; allies enemy tag图片总量&#xff1a;7247张训练集&#xff1a;5139张验证集&#xff1a;1425张测试集&#xff1a;683张标注状态&#xff1a;全部已标注&#xff0c;即拿即用数据格式&#xff1a;支持YOLO格式及其他格式&#…

2026/7/28 5:03:42 阅读更多 →

月新闻