Android 7系统休眠唤醒(一)电源管理架构全景图

系列目录第一篇:电源管理架构全景图 | 第二篇:开机全链路---BootROM到Launcher | 第三篇:关机/重启全链路---ShutdownThread到kernel_power_off | 第四篇:休眠唤醒与开关机---核心差异深度对比 | 第五篇:休眠全链路---PMS到Kernel Suspend | 第六篇:唤醒全链路---Kernel Resume到屏幕点亮 | 第七篇:内核层---wakelock与autosleep机制 | 第八篇:内核层---Alarm定时唤醒与硬件唤醒源 | 第九篇:Native层---libsuspend与Power HAL | 第十篇:实战调试与问题排查


一、为什么要理解休眠唤醒

移动设备与 PC 在电源管理上有本质区别。PC 可以随时插电使用,而手机依赖电池供电,必须在"性能"和"续航"之间做精细平衡。Android 为此设计了一套从应用到内核、跨越四层软件栈的电源管理体系。

当你遇到以下问题时,答案都在这套体系之中:

  • "为什么 App 申请了 WakeLock,设备还是会休眠?"------WakeLock 的 level 可能不够高,或者 PMS 的 mWakeLockSummary 汇总时被覆盖了
  • "为什么设备休眠后无法通过 Alarm 唤醒?"------Alarm 的 type 可能不是 RTC_WAKEUPELAPSED_REALTIME_WAKEUP
  • "为什么功耗测试显示设备从未进入 deep sleep?"------内核 wakelock 可能被某个驱动持锁,/sys/power/wake_lock 可以排查

这套体系的核心思想:当用户不使用设备时,让它尽可能深地睡眠;当用户需要使用设备时,让它在一秒之内恢复


二、三种状态转移模型

Android 系统的电源状态可以抽象为三种粒度的转移:

2.1 宏观级别:关机 ↔ 开机

最彻底的状态切换。关机将操作系统完整卸载、硬件完全掉电;开机则从 BootROM 开始,经历 BootLoader → Kernel → init → Zygote → SystemServer → Launcher 的完整启动链。

维度 说明
耗时 开机 30-60 秒,关机 5-15 秒
状态保留 无。所有内存数据、进程状态、寄存器上下文全部丢失
功耗 关机后几乎为零(仅 RTC 时钟供电)

2.2 中观级别:休眠 ↔ 唤醒

这是本系列的核心。休眠时 CPU 进入深度睡眠状态(deep idle / suspend),仅保留 RAM 自刷新供电和外设唤醒源。唤醒时,从中断触发到屏幕点亮通常在 1 秒以内完成。

维度 说明
耗时 休眠 < 1 秒,唤醒 < 1 秒
状态保留 完整。进程页表、ART 虚拟机堆、Activity 栈全部保留在 RAM 中
功耗 仅 RAM 自刷新 + RTC + 唤醒源监听,功耗极低

2.3 微观级别:亮屏 ↔ 暗屏

最轻量级的切换,仅涉及 DisplayPowerController 控制屏幕背光和显示层,不涉及 CPU 挂起。通常由用户操作(触摸屏幕、按下按键)或接近传感器触发。


三、Android 电源管理四层架构

Android 电源管理跨越四层软件栈,每层有明确的职责边界:

复制代码
┌──────────────────────────────────────────────────────┐
│              应用层 (Application Layer)               │
│  PowerManager API / WakeLock 申请与释放               │
│  frameworks/base/core/java/android/os/PowerManager   │
├──────────────────────────────────────────────────────┤
│             框架层 (Framework Layer)                  │
│  PowerManagerService / DisplayPowerController        │
│  Notifier / ShutdownThread                          │
│  frameworks/base/services/core/java/com/android/     │
│    server/power/                                     │
├──────────────────────────────────────────────────────┤
│             Native 层 (Native Layer)                  │
│  libsuspend / suspend_blocker / Power HAL            │
│  system/core/libsuspend/                             │
│  hardware/libhardware/include/hardware/power.h       │
├──────────────────────────────────────────────────────┤
│             内核层 (Kernel Layer)                     │
│  wakelock / autosleep / alarmtimer                   │
│  kernel/power/                                       │
│  drivers/rtc/alarm-dev.c                             │
└──────────────────────────────────────────────────────┘

3.1 应用层:PowerManager API

应用程序通过 PowerManager.WakeLock 通知系统"我正在做重要的事,不要休眠"。

源码路径frameworks/base/core/java/android/os/PowerManager.java

java 复制代码
public final class PowerManager {
    // WakeLock 级别(从低到高)
    public static final int PARTIAL_WAKE_LOCK = 0x00000001;      // 仅保持 CPU 运行
    public static final int SCREEN_DIM_WAKE_LOCK = 0x00000006;   // 保持 CPU + 暗屏
    public static final int SCREEN_BRIGHT_WAKE_LOCK = 0x0000000a; // 保持 CPU + 亮屏
    public static final int FULL_WAKE_LOCK = 0x0000001a;          // 保持 CPU + 亮屏 + 键盘

    public WakeLock newWakeLock(int levelAndFlags, String tag) {
        return new WakeLock(levelAndFlags, tag, mContext.getOpPackageName());
    }

    public final class WakeLock {
        public void acquire() { ... }           // 获取锁,阻止休眠
        public void acquire(long timeout) { ... } // 带超时的获取
        public void release() { ... }            // 释放锁
    }
}

关键设计WakeLock 默认非引用计数(setReferenceCounted(false)),多次 acquire() 只需一次 release() 即可释放。如果设为引用计数模式,则必须 acquire()release() 次数匹配。

3.2 框架层:PowerManagerService

PowerManagerService(PMS)是休眠唤醒的"中枢大脑",运行在 SystemServer 进程中。

源码路径frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

java 复制代码
public final class PowerManagerService extends SystemService {
    // 唤醒状态机:四种状态
    private int mWakefulness;          // AWAKE → DREAMING → DOZING → ASLEEP
    private boolean mWakefulnessChanging;  // 状态迁移中标志

    // WakeLock 聚合状态:所有活跃 WakeLock 的位掩码汇总
    private int mWakeLockSummary;      // 每个 bit 代表一种 WakeLock 类型

    // 脏标记:指示哪部分电源状态需要更新
    protected int mDirty;              // 位掩码,驱动 updatePowerStateLocked() 的增量更新
}

关键设计 :PMS 用 mDirty 位掩码驱动增量更新------当某个条件变化时(如 WakeLock 变化、亮度变化),只设置对应的 dirty bit,updatePowerStateLocked() 根据 dirty bits 分阶段处理,避免全量重算。

Wakefulness 状态机沿固定方向迁移:

复制代码
AWAKE ──→ DREAMING ──→ DOZING ──→ ASLEEP
  ↑         ↑           ↑           │
  │         │           │           │
  └─────────┴───────────┴───────────┘
           (用户交互 / 唤醒事件)
  • AWAKE:屏幕亮,设备完全可用
  • DREAMING:屏幕变暗,可能进入屏保(Daydream)
  • DOZING:Doze 模式,限制网络和后台任务
  • ASLEEP:CPU 挂起,仅 RAM 自刷新

关键设计 :状态迁移是单向的(AWAKE → ASLEEP),唤醒时直接跳回 AWAKE。mWakefulnessChanging 标志在状态迁移过程中置位,防止并发状态变更。

3.3 Native 层:libsuspend 与 Power HAL

libsuspend 是用户空间与内核休眠机制的桥梁。两种实现方式:

源码路径system/core/libsuspend/autosuspend_wakeup_count.c

  1. wakeup_count 方式 :读取 /sys/power/wakeup_count 获取当前值,写入 /sys/power/state 为 "mem" 触发休眠。如果在读取和写入之间产生了新的唤醒事件,wakeup_count 不匹配,内核拒绝休眠并返回错误。

源码路径system/core/libsuspend/autosuspend_autosleep.c

  1. autosleep 方式 :写入 /sys/power/autosleep 为 "mem",内核在 autosleep 工作线程中自动尝试休眠,无需用户空间持续轮询。

Power HAL 定义硬件抽象层接口:

源码路径hardware/libhardware/include/hardware/power.h

关键接口:powerHint() --- 向底层(cpufreq governor)传递电源提示;setInteractive() --- 通知 HAL 交互模式变化。

3.4 内核层:wakelock 与 autosleep

Android 内核在 Linux 标准 suspend/resume 基础上,增加了 wakelock 和 autosleep 机制,确保在有活跃 wakelock 时不会错误休眠。

关键内核源码路径:

  • kernel/power/wakelock.c --- wakelock 核心实现
  • kernel/power/autosleep.c --- autosleep 工作线程
  • kernel/power/main.c --- sysfs 节点注册(/sys/power/wake_lock/sys/power/wake_unlock
  • kernel/power/suspend.c --- suspend 主路径(pm_suspend
  • kernel/power/process.c --- 进程 freeze/thaw

四、休眠唤醒与开关机:核心区分

理解这四种流程的关键在于状态保持 vs 状态重建

复制代码
关机→开机:状态完全重建
    BootROM → BootLoader → Kernel → init → Zygote → SystemServer → Launcher
    内核重载、进程全部冷启动、ART 堆清零重分配

休眠→唤醒:状态完全保持
    内核仍在运行(仅 CPU 暂停)
    进程被 freeze(冻结)而非 kill
    ART 虚拟机堆内存完整保留
    Activity 栈原样保存
    恢复时只需 thaw(解冻)→ 恢复外设 → 点亮屏幕

关键:休眠唤醒的核心优势是"状态保持"------不需要重新加载内核、不需要重启进程、不需要重新初始化服务。这解释了为什么唤醒只需不到 1 秒,而开机需要 30-60 秒。


五、关键源码文件索引

层级 文件 本文涉及内容
Framework frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java PMS 核心,Wakefulness 状态机、mDirty 增量更新
Framework frameworks/base/services/core/java/com/android/server/power/Notifier.java 电源状态广播(SCREEN_ON/OFF)
Framework frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java 关机/重启调度
Framework frameworks/base/core/java/android/os/PowerManager.java 应用层 WakeLock API
Native system/core/libsuspend/autosuspend.c 自动休眠核心实现
Native system/core/libsuspend/autosuspend_wakeup_count.c wakeup_count 方式休眠
Native system/core/libsuspend/autosuspend_autosleep.c autosleep 方式休眠
HAL hardware/libhardware/include/hardware/power.h Power HAL 接口定义
Kernel kernel/power/wakelock.c 内核 wakelock 实现
Kernel kernel/power/autosleep.c 内核 autosleep 线程
Kernel kernel/power/suspend.c Suspend 主路径
Kernel kernel/power/process.c 进程 freeze/thaw

六、系列阅读路线

复制代码
第 1 篇(本篇)全景图
    │
    ├─→ 第 2 篇:开机全链路(建立"全量启动"的基准认知)
    │       │
    │       └─→ 第 3 篇:关机/重启全链路(理解"全量销毁"的代价)
    │               │
    │               └─→ 第 4 篇:休眠唤醒 vs 开关机 对比(核心交汇点)
    │                       │
    │           ┌───────────┼───────────┐
    │           │                       │
    │    第 5 篇:休眠全链路      第 6 篇:唤醒全链路
    │     (Framework → Kernel)    (Kernel → Framework)
    │           │                       │
    │           └───────────┬───────────┘
    │                       │
    │    第 7 篇:内核wakelock  第 8 篇:Alarm唤醒源
    │                       │
    │            第 9 篇:Native 层 & Power HAL
    │                       │
    └─────────── 第 10 篇:实战调试与问题排查
  • App 开发者:重点读第 1、4、5、6、10 篇,理解 WakeLock 的申请释放与功耗影响
  • Framework 开发者:通读全系列,核心是第 2-6 篇
  • 驱动/Kernel 开发者:重点关注第 4-8 篇,特别是第 5、6、7、8 篇

七、小结

本篇建立了 Android 电源管理的顶层认知:

概念 说明
三种状态转移 关机↔开机(全量重建)、休眠↔唤醒(状态保持)、亮屏↔暗屏(仅背光)
四层架构 应用层(WakeLock API)→ 框架层(PMS 状态机)→ Native 层(libsuspend)→ 内核层(wakelock/autosleep)
核心区分 状态保持(休眠唤醒)vs 状态重建(开关机)

后续篇章将逐层深入------下一篇从"开机"开始,走完从 BootROM 到 Launcher 的完整启动链路,为理解"休眠唤醒跳过了什么"打下基础。

相关推荐
Xzaveir7 小时前
别把所有“认证”都塞进 AuthService:实名、一键登录与号码身份的领域拆分
android·人工智能
BerrySen1787 小时前
KMP全栈开发:从Android到AI Agent的技术演进与实践
android·人工智能
YM52e9 小时前
鸿蒙Flutter Center居中组件:Align对齐详解
android·学习·flutter·华为·harmonyos·鸿蒙
时间的拾荒人10 小时前
MySQL 视图详解
android·数据库·mysql
祉猷并茂,雯华若锦11 小时前
Appium 3.x安卓按键与通知栏操作全指南
android·appium
码农coding11 小时前
android 12 SurfaceFlinger开机启动分析
android
hunterandroid11 小时前
Paging 3 RemoteMediator 实战:构建离线优先的分页列表
android·前端
码农coding11 小时前
android12 开机启动PMS
android
Days205012 小时前
GPT-Image-2 国风美学人设生成提示词分享
android·gpt