Skip to main content

Chapter 32: Timer, Wakeup, Scheduling Latency, Power Sensitivity

手机系统里的“时间”同时服务两个目标:让前台交互及时响应,让后台任务在电量和温度预算内完成。一个 App 设置 10 分钟后的同步任务、一个聊天消息点亮通知、一次触摸从黑屏唤醒设备、一个动画帧赶上下一次 VSync,这些现象都经过同一组底层问题:谁负责计时,谁有资格唤醒设备,CPU 从低功耗状态返回要付出多少延迟,系统如何把后台工作合并到更少的唤醒窗口。

本章建立的判断动作是:看到一个“定时任务延迟、通知晚到、触摸响应慢、后台同步被推迟、耗电异常”的现象时,先定位它属于 timer、wakeup source、scheduler latency 还是 power policy,再追踪 App 请求、framework API、系统服务、内核计时器、设备中断和硬件低功耗状态之间的责任边界。

贯穿材料是一条后台同步路径:App 希望每 15 分钟刷新一次轻量数据,同时支持服务端推送即时消息。前台时,用户希望页面立即更新;锁屏静置时,系统希望设备进入 idle 或 suspend;有推送时,modem 或网络栈可能唤醒系统;同步任务本身通常应合并到系统维护窗口。这个例子覆盖 timer、wakeup、scheduling latency 和 power sensitivity 的核心冲突。

公开资料可以支撑本章的边界判断。Linux 文档把高精度计时器、clock event、dynamic tick 放在计时基础设施中说明,见 High resolution timers and dynamic ticks design notesNO_HZ: Reducing Scheduling-Clock Ticks。Linux suspend 文档说明设备中断在 suspend/resume 期间的处理和 wake IRQ 条件,见 System Suspend and Device Interrupts。Android 公开文档说明 WakeLock、Doze、JobScheduler 和 Alarm 的用户态 API 边界,见 PowerManager.WakeLockOptimize for Doze and App StandbyJobScheduler。Apple 公开文档说明 timer 使用、Low Power Mode、QoS 与后台网络延后,见 Minimize Timer UseReact to Low Power Mode on iPhonesPrioritize Work with Quality of Service ClassesDefer Networking。Apple iOS 的内部 sleep/wake daemon、驱动策略和调度细节很多属于私有实现,本章只使用公开 API、公开文档、Darwin/XNU 公开概念和平台行为推断。

下面这条链路贯穿全章。它把“15 分钟后台同步”拆成可以检查的系统对象:

图中最关键的判断点是 Service->>KernelDevice-->>Kernel。前者决定“是否需要定时唤醒”,后者决定“是否真的有硬件级唤醒来源”。App 看到的是 callback、通知或延迟结果;系统承担的是计时、唤醒、调度和电源状态之间的取舍。

32.1 Timer 与系统时间管理

Timer 是系统对未来某个时间点或时间间隔的承诺。它接收一个时间条件,登记到系统计时结构里,在条件满足后触发回调、唤醒任务或交给更高层服务处理。手机系统里的 timer 既服务用户可见体验,也影响设备能否进入低功耗状态。

系统时间管理至少包含两类时间。Wall clock 表示用户理解的日历时间,例如今天 8:30 的闹钟;monotonic time 表示单调递增的运行时间,适合超时、动画、网络重试和相对延迟。Wall clock 会受时区、用户改时间、网络校时影响;monotonic time 适合判断“经过了多久”。后台同步、网络超时和动画 frame deadline 通常依赖 monotonic time,闹钟、日历提醒和用户指定时间通常依赖 wall clock。

内核负责把抽象时间转成硬件计时事件。Linux 的高精度计时器把 timer 按过期时间排序,并通过 clock event device 安排下一次中断;传统 timer wheel 更适合大量低精度超时。clock source 提供“现在是什么时间”的读数,clock event device 提供“下一次何时打断 CPU”的能力。对移动系统来说,后一项直接影响功耗:越多精确短周期 timer,CPU 越难长时间停留在深 idle。

对象工作定义移动 OS 中的判断用途
Wall clock用户日历时间判断闹钟、日历、用户指定提醒是否应按本地时间触发
Monotonic time单调递增运行时间判断超时、动画节奏、重试间隔和统计耗时
Timer wheel面向大量低精度超时的内核结构承载普通 timeout、延后清理和非精确后台工作
hrtimer面向高精度过期时间的内核计时器承载精确 sleep、frame deadline、短超时和高精度回调
Alarm具有跨 idle 或跨 suspend 语义的系统定时请求连接用户提醒、后台唤醒、维护窗口和权限策略
Timeout callback过期后执行的代码路径判断任务是否只是醒来检查状态,还是确实推进用户可见工作

贯穿材料里的“每 15 分钟刷新一次轻量数据”看似只是一个定时器,系统视角会先追问三个问题。第一,这个刷新是否用户可见;第二,它是否允许延后;第三,它是否需要把设备从低功耗状态唤醒。答案如果是“刷新首页缓存、允许延后、锁屏时无用户可见结果”,系统会倾向把它交给 JobScheduler、WorkManager、BackgroundTasks 或后台 URL session 一类可批处理机制,而非登记一个高精度周期 timer。

Android 的 API 边界体现了这种分层。AlarmManager 更接近“时间到了要通知系统”的 alarm 入口,JobScheduler 更接近“条件满足时执行工作”的调度入口,WorkManager 在应用开发层包装了可延后工作。Android 6.0 API level 23 引入 Doze 后,锁屏静置、未充电、设备不活动时,普通 alarm、job、sync 和网络访问会被推迟到维护窗口;只有用户可见或具备特殊语义的 alarm 才应使用允许 idle 期间触发的接口。

Apple 平台公开文档也把 timer 当作能耗敏感对象。iOS Energy Guide 建议用系统事件、dispatch source、后台 URL session 或通知替代轮询 timer;必须使用 timer 时,应设置合适 timeout、取消已无用的重复 timer,并设置 tolerance,让系统把多个 timer 合并执行。tolerance 的意义是把“精确在某一毫秒执行”改成“在可接受窗口内执行”,系统因此可以减少 CPU 从 idle 被唤醒的次数。

Timer 判断顺序可以稳定复用:先看时间语义是 wall clock 还是 monotonic;再看精度是否影响用户可见结果;接着看它是否需要跨 idle 或 suspend;最后看系统是否提供批处理、事件通知或后台传输入口。对后台同步这条贯穿路径,合理结论通常是:前台刷新使用普通异步请求和 UI deadline,后台刷新使用可延后任务,用户可见提醒使用 alarm 或通知语义,服务端即时消息使用平台推送通道。

32.2 Wakeup Source 与设备唤醒路径

Wakeup source 是有资格把系统从低功耗状态带回可执行状态的来源。它可以来自硬件中断,也可以来自系统服务登记的 alarm。timer 决定“某个时间点需要处理”,wakeup source 决定“设备睡着时这个事件是否有资格唤醒”。这两个对象必须分开判断。

手机进入低功耗状态后,CPU、总线、外设和电源域可能处在不同层级的 idle、runtime suspend 或 system suspend。设备唤醒路径通常从硬件事件开始:触摸控制器产生中断,充电器状态改变,modem 收到寻呼或数据事件,传感器 hub 达到阈值,RTC alarm 到期。内核需要知道哪个 IRQ 能在 suspend 期间保持唤醒语义,驱动需要在 suspend 前配置硬件,PM core 需要在 resume 阶段恢复设备状态。

Linux suspend 文档区分了“suspend 期间保持 IRQ 可用”和“IRQ 能唤醒系统”。某些特殊中断可以在 suspend/resume 周期保持启用;要让某条中断线具备唤醒能力,还需要驱动或平台代码设置 wake IRQ。这个边界可以帮助读者理解手机现象:一个设备能在运行时产生中断,并不自动表示它能在深度睡眠中唤醒整机。

常见唤醒来源可以按责任主体观察。RTC 或 alarm 来源由系统时间和电源管理共同控制;touch 来源由触摸控制器、显示唤醒策略和输入子系统控制;charger 来源由 PMIC、充电驱动和电源服务控制;sensor 来源常由低功耗传感器 hub 或 motion coprocessor 先处理;modem 来源由基带、RIL 或蜂窝服务链路处理;network 来源在 Wi-Fi 或蜂窝电源状态、系统推送通道和网络栈之间协调。

贯穿材料里的即时消息属于典型唤醒路径。App 维持自己的常驻 TCP 连接,会让 radio、网络栈和应用进程频繁参与唤醒;平台推送把多 App 的实时消息聚合到系统级连接和统一策略中。Android 文档建议在 Doze 和 App Standby 场景下使用 FCM 处理下行消息;普通优先级消息可进入维护窗口,高优先级消息用于时间敏感且用户可见的通知。Apple 平台也通过 APNs 和后台模式限制常驻后台网络,把唤醒资格集中到系统通道和声明过的能力上。

Wakeup source 与 WakeLock 也需要分层。Wakeup source 解决“睡着后谁能叫醒系统”;WakeLock 或 power assertion 解决“系统醒着时某段工作是否需要持续执行”。一个 alarm 可以唤醒设备,但 callback 运行后若工作继续访问网络,系统仍要决定是否给 CPU、radio 和 App 后台执行窗口。一个 WakeLock 可以延缓 suspend,但它通常无法把一个已进入深度睡眠的设备直接叫醒。

排查“通知晚到”时,先看服务端是否走平台推送;再看消息优先级是否对应用户可见通知;接着看设备是否处于 Doze、Low Power Mode、弱网或省电策略;最后看 App 是否依赖后台轮询。这个顺序把责任边界拆开:服务端负责消息提交,平台推送负责统一连接,系统电源策略负责唤醒预算,App 负责在短窗口内完成用户可见处理。

32.3 Scheduling Latency 与交互响应

Scheduling latency 是事件已经具备执行条件后,目标线程真正获得 CPU 之前的等待时间。timer 到期、IRQ 到达、Binder 或 XPC 回调可用,都只表示“事件进入系统”;线程还要经过中断处理、软中断或 workqueue、run queue 排队、优先级选择、CPU idle 退出和可能的频率提升,才会执行 App 或系统服务代码。

交互响应对 latency 的预算很窄。60Hz 屏幕一帧约 16.67ms,120Hz 屏幕一帧约 8.33ms。触摸事件从控制器中断进入输入子系统后,还要经过系统服务分发、App 主线程处理、渲染线程提交、GPU 执行和合成显示。任何一个阶段把 CPU 留在深 idle 过久、把 UI 线程排在后台任务之后、让中断风暴占用处理时间,都可能表现为触摸卡顿或掉帧。

timer latency 与 scheduling latency 的差别在排查中很有用。timer latency 指 timer 设定的过期点和实际触发点之间的偏差;scheduling latency 指 callback 已可运行后等待 CPU 的时间。前者常与 timer 精度、tickless idle、系统批处理、Doze 维护窗口有关;后者常与 run queue 长度、优先级、CPU idle exit、thermal throttling、中断负载和锁竞争有关。

贯穿材料中,前台下拉刷新要求立即响应。此时系统通常会提升交互线程优先级,让 CPU 从 idle 退出,并把网络请求、主线程状态更新、渲染提交纳入用户可见路径。后台每 15 分钟同步则属于低优先级工作,系统可以延迟、合并、降频执行。两个任务都可能使用 timer 或 callback,但调度策略完全不同,因为前者绑定输入和 frame deadline,后者绑定电源预算。

Android 上,前台 Activity、前台服务、Binder 回调、RenderThread、SurfaceFlinger、system_server 和 kernel scheduler 共同影响交互路径。App 主线程被后台计算占满时,即使输入事件及时到达,UI 仍会延迟;system_server 繁忙时,事件分发、窗口焦点、权限检查和服务回调也可能变慢;CPU 处于深 idle 时,退出延迟会叠加在第一帧响应上。

Apple 平台公开给开发者的主要调度语义是 QoS。QoS 把任务按用户交互、用户发起、utility、background 等重要性分类,系统据此调整调度、CPU 与 I/O 吞吐、timer latency 等行为。这个公开模型足以建立应用层判断:与当前 UI 直接相关的工作应声明更高 QoS;可延后同步、清理、预取应使用 background 或 discretionary 语义,让系统在能耗合适时处理。

调度延迟的判断顺序是:先确认事件是否真的到达系统,再确认目标线程是否可运行,然后看 run queue 和优先级,再看 CPU 是否从 idle 或低频状态返回,最后看是否存在温控、锁竞争或中断负载。这个顺序把“系统没触发 timer”“系统触发了但任务排队”“任务执行了但结果晚显示”三个问题分开。

32.4 Tick、Idle State 与 CPU 省电状态

Scheduler tick 是周期性打断 CPU 的时钟中断,用于进程时间统计、调度检查、profiling 和其他内核维护工作。周期 tick 简化了内核按时间推进状态的方式,但它会阻止 CPU 长时间保持 idle。手机系统为了续航,倾向在 CPU 空闲时减少 tick,并把下一次必要事件交给可编程 clock event device。

Tickless idle 的基本思路是:当某个 CPU 进入 idle,内核检查下一次 timer 或调度事件;如果下一次事件足够远,就关闭周期 tick 或把 tick 推迟到最近的必要事件。Linux NO_HZ_IDLE 就服务这个目标。公开文档说明,省略 idle CPU 上的调度 tick 对电池设备有明显价值,同时也会增加进出 idle 路径上的指令和时钟重编程开销。

Idle state 有层级差异。浅 idle 退出快、省电少;深 idle 退出慢、省电多。移动 SoC 还涉及 CPU cluster、L2/L3 cache、interconnect、display、modem、sensor hub 和 power domain。系统进入更深状态前,需要确认最近没有必须处理的 timer、没有未完成的 wake lock 或 assertion、没有驱动阻止 suspend、没有前台交互 deadline。

Power domain 是电源管理中的硬件边界。一个 CPU 核心可以 idle,但共享 cluster 仍保持供电;一个外设可以 runtime suspend,但所在电源域还受其他设备约束;display 可以关闭,但触摸、modem、RTC 和传感器 hub 保留唤醒能力。驱动和 PM core 需要维护这些依赖,使系统在关闭电源域前保存状态,在唤醒后按顺序恢复。

贯穿材料里的后台同步会影响 idle state。每 15 分钟精确唤醒一次,系统需要保留或重新编程 timer,并让 CPU、radio、网络栈和 App 进程参与执行。把同步任务交给系统批处理后,多个 App 的后台刷新可以合并到同一个维护窗口,CPU 一次退出 idle,radio 一次上电,随后系统回到低功耗状态。

Tick、idle 和 scheduling latency 的取舍集中在“第一响应”和“长期续航”之间。前台触摸和音视频播放要求低延迟,系统会减少深 idle 停留或提前做性能 hint;锁屏静置要求长 idle,系统会放宽 timer 精度、推迟后台任务、合并网络活动。用户看到的是“点亮快、滑动顺、后台更新稍晚、电池更耐用”;系统执行的是 tick、idle state 和唤醒预算的动态选择。

判断 tick/idle 问题时,先看设备是否处于前台交互、屏幕关闭、充电、低电量或温控状态;再看是否存在短周期 timer、持续 wake lock、常驻网络或传感器采样;接着看任务是否能批处理;最后看用户可见 deadline 是否允许系统进入更深 idle。这个顺序能解释“同样的 timer 前台准时、锁屏延迟、充电时又恢复”的现象。

32.5 Android WakeLock 与 Suspend Control

Android WakeLock 是应用或系统组件向 PowerManager 表达“这段工作需要设备保持某种唤醒状态”的机制。公开 API 中,App 需要 android.permission.WAKE_LOCK,通过 PowerManager.newWakeLock() 创建 WakeLock,调用 acquire() 持有,调用 release() 释放。持有 WakeLock 的代码应有明确工作边界和超时,因为它直接影响 CPU、屏幕或其他电源状态能否下降。

WakeLock 的系统路径可以按责任链理解。App 通过 framework API 提交请求;PowerManagerService 记录调用者身份、tag、WorkSource 和持有状态;电源管理策略综合屏幕、用户活动、充电、Doze、设备 idle、系统服务工作和内核 wakeup source;底层再通过 kernel wakeup source、suspend blocker、driver runtime PM 和设备电源状态控制系统能否 suspend。AOSP 具体实现会随 Android 版本和厂商修改变化,本章只使用公开 API 与 Android 电源管理的通用架构角色。

WakeLock 与 JobScheduler、AlarmManager 的关系是 Android 后台策略的核心。WakeLock 表示工作执行期间需要保持设备醒着;JobScheduler 表示工作可以在条件满足时由系统安排;AlarmManager 表示某个时间点需要系统处理。后台同步任务如果可延后,优先使用 JobScheduler 或 WorkManager 语义,让系统按网络、充电、idle、quota 和维护窗口调度。只有用户明确期望的准时提醒,才应进入 alarm 语义。

Doze 改变了普通后台 timer 的可执行性。Android 6.0 API level 23 及以上,设备锁屏、静置且未充电时进入 Doze 后,系统会限制网络和 CPU 密集服务,推迟 job、sync 和标准 alarm 到维护窗口。普通 WakeLock 在 Doze 限制下会被系统策略收束;允许 idle 期间触发的 alarm 也受到频率限制。这个边界解释了很多工程现象:App 已经调用 schedule,日志里也能看到任务登记,但锁屏后 callback 仍延后。

Suspend control 的判断重点是“谁阻止系统睡眠”。前台音乐播放、导航、正在上传的用户可见任务、系统下载、电话通话、闹钟响铃等路径通常具有明确用户结果;后台轮询、定期预取、埋点上传和缓存刷新通常应延后或批处理。系统会根据应用状态、权限、前台服务类型、通知可见性和电源策略决定执行窗口。

贯穿材料中,App 希望每 15 分钟同步。Android 下更稳的设计是:把普通刷新建模为可延后 job,把即时用户消息交给 FCM,把用户设定提醒交给 alarm,把执行中的短工作用有超时的 WakeLock 或系统提供的任务框架保护。这样责任边界清晰:App 描述工作意图,framework 管理 API 合约,system service 统一调度,kernel 和 driver 执行低功耗状态切换。

排查 Android 后台任务时,可以按六步看:任务入口是 alarm、job、push 还是前台服务;设备状态是否处于 Doze 或 App Standby;任务是否声明网络、充电、idle 等约束;是否存在用户可见通知;WakeLock 是否按路径释放;失败表现是 callback 未到、网络不可用、任务启动后被停止,还是通知展示晚到。每一步都对应不同责任主体。

32.6 Apple 平台的 Sleep / Wake 与电源状态管理

Apple 平台的 sleep/wake 和电源状态管理需要明确资料边界。公开文档能确认的内容包括:App 可通过 QoS 表达工作重要性,通过 timer tolerance 给系统合并执行空间,通过 Low Power Mode 状态调整活动,通过后台 URL session、BackgroundTasks、push notification 和特定 background mode 请求后台执行。iOS 内部 daemon、XNU driver、SEP、baseband 和私有电源策略的具体组合通常无法从公开文档完整验证。

Sleep / wake 在 App 视角表现为执行窗口的变化。前台 App 绑定用户交互和显示刷新,系统给予更高响应优先级;进入后台后,普通代码执行时间被收束,长期网络、定位、音频、蓝牙、VoIP、外设通信等需要对应的系统能力声明;设备锁定和低电量时,系统会进一步推迟 discretionary activity。这个模型让 App 把“想执行”转成“系统允许的后台能力”。

Apple Energy Guide 对 timer 的建议与移动 OS 电源策略一致。轮询式 timer 会阻止 CPU 进入或维持 idle;系统事件通知、dispatch source、后台 URL session 和推送通知更适合等待外部变化;必须使用 timer 时,应取消已无用的重复 timer,并设置 tolerance。tolerance 把多个 App 或系统任务聚合到相近时间点,减少唤醒次数。

QoS 是 Apple 公开调度模型中最适合解释 scheduling latency 的入口。系统根据工作对用户体验的影响调整调度、CPU 与 I/O 吞吐、timer latency。用户正在等待的 UI 更新应使用更高 QoS;预取、同步、清理、日志上传应使用低优先级或 discretionary 语义。QoS 选择错误会把后台工作放进交互路径,或把用户正在等待的工作放进可延后队列。

Low Power Mode 是公开可见的系统电源策略信号。iOS 9 及以上的 iPhone 可启用 Low Power Mode;公开文档说明系统可能降低 CPU/GPU 性能,暂停 discretionary 和后台活动,降低屏幕亮度,缩短自动锁定时间等。App 应监听电源状态变化,在该模式下降低动画、帧率、定位、同步和备份活动。这里的关键边界是:App 不能要求系统永久保持高性能状态;App 可以把工作强度和频率调低,使系统策略更容易完成续航目标。

Power assertion 在 Apple 语境里常见于 macOS 公开电源管理;iOS App 更多通过后台模式、任务框架、音频/定位/蓝牙等能力声明和系统服务获得有限执行窗口。跨 Apple 平台写作时应把这两类语义区分开:power assertion 表达“某段系统或进程工作期间暂缓睡眠”的请求,iOS background mode 表达“此类后台活动符合平台允许的用途”。二者都属于电源策略输入,但 API 表面和适用平台不同。

贯穿材料在 Apple 平台上的设计是:前台刷新使用合适 QoS 和异步网络;后台普通同步使用 BackgroundTasks 或后台 URL session 的 discretionary 语义;即时消息走 APNs;用户可见提醒走通知;低电量或锁屏时降低刷新频率。这个设计不依赖 Apple 私有实现细节,也能解释用户看到的结果:前台响应优先,后台同步可能延后,用户可见通知保留更高投递价值。

32.7 Timer、Wakeup、Power Policy 对后台任务的影响

后台任务是 timer、wakeup 和 power policy 的交汇点。App 关心“什么时候执行”,系统关心“这次执行是否值得唤醒设备、打开网络、提升频率、保留后台进程”。同一个 15 分钟同步请求,在前台、锁屏、充电、低电量、弱网、漫游、温控、用户很久未打开 App 等状态下,会得到不同执行窗口。

后台任务应先按用户结果分类。用户正在等待的结果,例如上传完成提示、导航位置、音频播放、通话、闹钟、即时通知,具有更强执行理由;缓存预热、推荐刷新、日志上传、统计同步、批量清理,适合延后、合并或只在充电/Wi-Fi 条件下运行。这个分类决定 API 入口,而 API 入口决定系统服务如何对它施加 quota、维护窗口和唤醒预算。

Android 与 Apple 的共同模型可以用同一组维度比较:

维度Android 典型路径Apple 典型路径共同判断
普通后台同步JobScheduler / WorkManagerBackgroundTasks / background URL session交给系统批处理和条件调度
用户指定提醒AlarmManager / NotificationUserNotifications按用户可见时间语义处理
即时消息FCMAPNs使用平台推送聚合网络唤醒
长时间用户可见工作Foreground service 与通知合法 background mode 或系统框架让用户可见,并接受系统策略约束
低电量状态Battery Saver、Doze、App StandbyLow Power Mode降低后台频率、网络与计算强度
执行期间保活WakeLock、系统任务窗口后台执行窗口、平台能力声明、部分平台 power assertion只保护有边界的工作区间

贯穿材料里的 15 分钟同步可以拆成三条路径。第一,前台用户打开页面时立即刷新,此路径受输入响应、QoS、线程调度和网络质量影响。第二,后台缓存刷新使用系统任务框架,允许延迟到维护窗口,此路径受 Doze、App Standby、Low Power Mode、充电和网络条件影响。第三,即时消息使用平台推送,只有用户可见通知或高优先级消息才获得更强唤醒价值。

Power policy 会把多个局部正确的请求重新排序。一个 App 认为“15 分钟一次很少”,一台手机上 200 个 App 都这样做,就会变成频繁唤醒、radio 反复上电、CPU 无法长 idle。系统服务因此把后台任务集中到队列、quota 和维护窗口中执行。这个设计牺牲了单个 App 的精确时间,换来整机续航、温控和后台公平性。

失败表现也要按路径分类。任务没有准时回调,可能是 timer 被批处理或 Doze 推迟;通知晚到,可能是消息优先级、推送通道、弱网或省电策略;任务启动后网络失败,可能是 idle 限制或 radio 未开放;任务运行一半停止,可能是后台执行窗口耗尽;前台卡顿,可能是后台任务抢占 CPU、I/O 或锁。把这些表现混成“系统限制后台”会丢失排查方向。

可复用判断顺序如下。先问用户可见结果是什么;再选 API 语义:alarm、job、push、foreground work、background transfer 或普通 async callback;接着看设备状态:屏幕、充电、电量、idle、网络、温控;然后定位执行边界:system service 是否准许,kernel 是否需要唤醒,driver 是否保持设备电源;最后看用户可见结果:准时展示、延后展示、维护窗口执行、取消、重试或静默失败。

本章的结论是:手机系统里的 timer 只回答“何时考虑执行”,wakeup source 回答“谁能叫醒设备”,scheduling latency 回答“醒来后多久拿到 CPU”,power policy 回答“这次执行是否符合整机预算”。后台任务、推送、触摸响应和掉帧都能放进这四个问题中定位责任边界。

最小自检任务

你负责排查一个移动 App 的后台刷新问题:产品希望每 15 分钟刷新一次首页数据;用户反馈锁屏一小时后再次打开 App,数据经常没有更新;同时即时消息通知大多数时间能收到,但有时延迟。请写出这条路径中 timer、wakeup source、scheduling latency 和 power policy 分别要检查什么,并分别说明 Android 与 Apple 平台上应优先使用的系统入口。

答案要点

timer 侧先判断“每 15 分钟”是否需要精确执行。首页缓存刷新通常没有用户指定时间语义,应进入可延后后台任务,而非高精度重复 timer。Android 可使用 JobScheduler 或 WorkManager;Apple 可使用 BackgroundTasks 或后台 URL session 的 discretionary 语义。若任务只是为了用户下次打开时更快,应允许系统合并到维护窗口。

wakeup source 侧先判断是否存在有资格唤醒设备的事件。首页刷新通常无需单独唤醒整机;即时消息应走平台推送。Android 使用 FCM,Apple 使用 APNs。用户可见且时间敏感的消息才应请求更高优先级;普通内容同步可等设备唤醒或维护窗口。

scheduling latency 侧要区分“系统没有准许任务运行”和“准许后线程排队”。锁屏一小时后的数据旧,优先看 Doze、App Standby、Low Power Mode、任务约束、网络状态和维护窗口;前台打开后刷新仍慢,再看主线程、QoS、run queue、网络回调、I/O 和渲染路径。

power policy 侧要把设备状态放入判断:锁屏、未充电、低电量、弱网、温控和用户久未打开 App 都会降低后台执行机会。Android 上检查 Doze、App Standby、Battery Saver、alarm/job 约束、WakeLock 生命周期和通知可见性;Apple 上检查 Low Power Mode、background mode 合法性、BackgroundTasks 调度、后台 URL session、APNs 优先级和 App 被用户强制结束后的行为边界。

最终设计应拆成三条路径:前台打开页面时即时刷新;后台缓存刷新交给系统批处理;即时消息走平台推送并只在用户可见场景使用高优先级。这样能解释数据延后、通知延迟和前台响应三个现象,也能把责任边界分配给 App、framework、system service、kernel/driver 和硬件唤醒源。

本章知识点总结

  • Timer 语义:Timer 表示未来时间条件,系统还会根据精度、用户可见性和电源状态决定实际执行窗口。
  • 时间分类:Wall clock 适合日历和用户提醒,monotonic time 适合超时、重试、动画和耗时统计。
  • 内核计时:Clock source 提供当前时间读数,clock event device 负责安排下一次计时中断。
  • 高精度成本:高精度短周期 timer 会增加 CPU 唤醒次数,并压缩设备停留在深 idle 的时间。
  • Alarm 边界:Alarm 适合具有明确时间语义的提醒或系统事件,普通后台同步更适合任务调度入口。
  • 唤醒来源:Wakeup source 决定睡眠中的设备能被谁叫醒,timer 到期本身仍需具备可唤醒路径。
  • 中断边界:运行时可产生中断的设备,还需要额外唤醒配置才能在 suspend 中唤醒整机。
  • 延迟拆分:Timer latency 描述过期点到触发点的偏差,scheduling latency 描述可运行线程等待 CPU 的时间。
  • 交互预算:触摸和帧输出受毫秒级 deadline 约束,后台同步可使用更宽松的调度窗口。
  • Tickless idle:减少 idle CPU 上的 scheduler tick 能提升续航,但会带来进出 idle 和重编程时钟的开销。
  • WakeLock 责任:Android WakeLock 表达工作执行期间保持唤醒状态的请求,持有和释放必须对应明确工作边界。
  • Doze 策略:Android Doze 会推迟普通 alarm、job、sync 和网络访问,把后台工作集中到维护窗口。
  • Apple 边界:Apple 平台公开可用的判断入口是 timer tolerance、QoS、Low Power Mode、后台任务框架和推送通道。
  • 后台分类:用户可见工作、普通缓存刷新、即时消息和用户指定提醒应使用不同 API 入口。
  • 排查顺序:先看用户结果,再看 API 语义,然后看设备状态、系统准许、内核唤醒和最终可见表现。