2. Android 功耗架构基础:电源管理框架、Power HAL、Suspend/Resume 机制

Android 功耗架构是系统级功耗优化的核心骨架。本章从电源管理框架、Power HAL 接口定义、Suspend/Resume 机制三个层次展开,帮助调试人员建立从上层策略到底层硬件的完整视图。

2.1 Android 电源管理框架

Android 电源管理框架采用分层设计,从上至下依次为:应用框架层、系统服务层、HAL 层和内核层。每一层通过明确的接口与下层交互,形成闭环控制。

关键设计原则:上层策略驱动下层状态,下层状态反馈给上层决策。任何一层的参数配置错误都会导致功耗异常。

2.1.1 框架分层与职责

层级 核心组件 主要职责
应用框架层 PowerManager / WakeLock 管理应用唤醒锁、屏幕亮度、Doze 模式策略
系统服务层 PowerManagerService 协调 WakeLock、屏幕状态、待机决策、电量统计
HAL 层 power.default / power.stats 抽象硬件电源控制接口,提供功耗统计原始数据
内核层 Linux PM core / Device PM 执行 Suspend/Resume、CPU 频率调节、设备运行时电源管理
调试提示:在 CTS 功耗测试中,大部分失败案例源于 HAL 层与内核层之间的参数不匹配,例如 WakeLock 超时时间与内核 Suspend 延迟不兼容。

2.1.2 框架交互流程

下图展示了从应用请求到硬件响应的完整电源管理交互路径:

Android 电源管理框架交互流程 应用 (App) PowerManagerService Power HAL 内核 PM Core 硬件设备 acquireWakeLock() setInteractive() ioctl / sysfs suspend/resume 状态回调 (PowerState) 说明: 虚线表示异步回调路径。HAL 层是用户态与内核态的唯一桥梁,所有电源状态变更必须经过 Power HAL 的接口转换。

2.2 Power HAL 接口详解

Power HAL 是 Android 电源管理框架中连接系统服务与内核驱动的关键抽象层。它定义了一组标准接口,用于控制设备的电源状态、性能模式和功耗统计。

2.2.1 核心接口定义

Power HAL 接口定义在 hardware/libhardware/include/hardware/power.h 中,主要包含以下函数指针:

// power.h 核心接口 (Android 12+)
struct power_module {
    struct hw_module_t common;

    // 设置电源提示(如 APP 启动、游戏、视频播放)
    void (*power_hint)(struct power_module *module, 
                       power_hint_t hint, 
                       void *data);

    // 设置交互模式(屏幕亮/灭)
    void (*set_interactive)(struct power_module *module, 
                            int on);

    // 获取功耗统计信息(可选)
    int (*get_feature)(struct power_module *module, 
                       feature_t feature);

    // 设置特定功耗模式(如低功耗音频、显示优化)
    void (*set_mode)(struct power_module *module, 
                     mode_t mode, 
                     int enabled);
};

2.2.2 关键枚举与参数

枚举类型 取值 说明 调试关注点
power_hint_t POWER_HINT_INTERACTION 用户交互提示,提升 CPU 频率 频率提升时长是否过长
POWER_HINT_SUSTAINED_PERF 持续性能模式(如游戏) 温控降频阈值是否合理
POWER_HINT_LAUNCH 应用启动加速 启动完成后是否及时降频
mode_t MODE_DOUBLE_TAP_TO_WAKE 双击唤醒 是否导致误唤醒
MODE_LOW_POWER_AUDIO 低功耗音频播放 音频路径是否绕过 AP
常见陷阱:部分 OEM 在实现 set_interactive() 时,屏幕灭后未及时释放 CPU 频率锁,导致待机电流异常偏高。CTS 测试中 testScreenOffSuspend 用例专门验证此行为。

2.2.3 Power HAL 实现示例

以下是一个简化的 Power HAL 实现片段,展示如何将上层 hint 转换为内核 sysfs 操作:

// power_default.c 简化实现
static void power_hint(struct power_module *module, 
                       power_hint_t hint, void *data) {
    switch (hint) {
        case POWER_HINT_INTERACTION: {
            // 获取交互时长(默认 500ms)
            int duration = data ? *(int *)data : 500;
            // 写入 CPU 频率提升 sysfs
            write_to_sysfs("/sys/devices/system/cpu/cpufreq/interactive/boost",
                           "1");
            // 设置定时器自动降频
            set_boost_timer(duration);
            break;
        }
        case POWER_HINT_SUSTAINED_PERF: {
            int enabled = data ? *(int *)data : 0;
            // 设置持续性能模式
            write_to_sysfs("/sys/class/kgsl/kgsl-3d0/max_pwrlevel",
                           enabled ? "0" : "6");
            break;
        }
        default:
            break;
    }
}

2.3 Suspend/Resume 机制

Suspend/Resume 是 Android 系统进入和退出低功耗状态的核心机制。理解这一过程对于定位待机功耗异常至关重要。

2.3.1 Suspend 流程

系统进入 Suspend 状态需要经过以下关键阶段:

  1. 冻结用户空间进程:内核向所有用户进程发送冻结信号,进程进入不可中断睡眠状态。
  2. 同步文件系统:将脏页写回存储设备,确保数据一致性。
  3. 暂停设备驱动:按设备依赖树顺序调用驱动的 .suspend() 回调。
  4. 关闭非唤醒中断:只保留唤醒源中断(如电源键、RTC 闹钟)。
  5. 进入低功耗模式:CPU 执行 WFI(Wait For Interrupt)指令,系统进入挂起状态。
关键指标:从步骤 1 到步骤 5 的耗时称为 Suspend Latency,通常要求 < 200ms。如果某个设备驱动的 .suspend() 回调耗时过长,会导致系统无法及时进入待机,增加功耗。

2.3.2 Resume 流程

当唤醒事件发生时,系统执行反向操作:

  1. 唤醒中断触发:唤醒源(如 GPIO 中断)将 CPU 从 WFI 状态唤醒。
  2. 恢复设备驱动:按依赖树逆序调用驱动的 .resume() 回调。
  3. 解冻用户空间进程:内核恢复进程执行状态。
  4. 通知上层:PowerManagerService 收到唤醒事件,更新系统电源状态。

2.3.3 Suspend/Resume 状态机

下图展示了 Suspend/Resume 的完整状态转换过程:

Suspend/Resume 状态机 运行态 (Active) CPU 全速运行 冻结态 (Freeze) 进程冻结完成 挂起态 (Suspend) WFI 低功耗 恢复态 (Resume) 驱动恢复中 suspend 设备暂停 唤醒中断 解冻进程 调试要点: 使用 cat /sys/kernel/debug/suspend_stats 查看 Suspend 失败次数和原因。如果失败率 > 5%,说明存在唤醒锁泄漏或驱动异常。

2.3.4 唤醒源与调试方法

常见的唤醒源及其调试接口如下:

唤醒源类型 典型来源 调试接口 异常表现
GPIO 唤醒 电源键、指纹传感器 /proc/interrupts 误触发导致频繁唤醒
RTC 闹钟 AlarmManager 定时任务 dumpsys alarm 第三方应用设置过多闹钟
USB 唤醒 USB 插入/拔出 /sys/bus/usb/devices/*/power/wakeup USB 设备未正确配置唤醒
WiFi 唤醒 WOWLAN (Wake on Wireless LAN) iw dev wlan0 wowlan show 广播包过多导致频繁唤醒
实用命令:adb shell dumpsys power | grep "Wake Locks" 可以查看当前持有唤醒锁的进程。如果待机时仍有唤醒锁未被释放,说明应用或系统服务存在功耗异常。

2.4 本章小结

Android 功耗架构的核心要点总结如下:

  • 分层协作:应用层通过 WakeLock 表达需求,系统服务层进行策略决策,HAL 层完成硬件抽象,内核层执行实际状态切换。
  • Power HAL 是调试入口:所有电源状态变更最终都会经过 Power HAL 的 power_hint() 和 set_interactive() 接口。CTS 功耗测试用例直接调用这些接口验证行为。
  • Suspend/Resume 是待机功耗的关键:系统能否及时进入 Suspend 状态、唤醒源是否合理,直接决定待机电流大小。调试时应重点关注 suspend_stats 和唤醒锁持有情况。