AAOS 电源管理深度解析:休眠/唤醒/功耗优化

AAOS 电源管理深度解析:休眠/唤醒/功耗优化

一、引言

车载操作系统(AAOS)的电源管理与手机有着本质区别。手机只需要考虑单用户手持场景,而 AAOS 要同时面对:熄火断电、驻车娱乐、倒车影像、远程控车、OTA 升级等多复杂场景。一旦休眠时序出错,可能导致黑屏死机、蓝牙断连甚至无法点火。

本文基于 Android 14android-14-dev 分支),从 AOSP 源码出发,深入分析 AAOS 电源管理的三大核心模块:

  1. CarPowerManagementService ------ 电源状态机(packages/services/Car/service/src/com/android/car/power/
  2. CarPowerPolicyDaemon ------ 电源策略引擎(frameworks/hardware/interfaces/automotive/powerpolicy/
  3. CarPowerManager ------ 应用层 API(car-lib/src/android/car/hardware/power/

我们会追踪关键代码路径,并结合 diagram 帮助你建立起完整的电源管理知识体系。


二、整体架构

下图展示了 AAOS 电源管理系统的分层架构:
#mermaid-svg-GsQMNEDCWWkoM0Ox{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-GsQMNEDCWWkoM0Ox .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-GsQMNEDCWWkoM0Ox .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-GsQMNEDCWWkoM0Ox .error-icon{fill:#552222;}#mermaid-svg-GsQMNEDCWWkoM0Ox .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-GsQMNEDCWWkoM0Ox .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-GsQMNEDCWWkoM0Ox .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-GsQMNEDCWWkoM0Ox .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-GsQMNEDCWWkoM0Ox .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-GsQMNEDCWWkoM0Ox .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-GsQMNEDCWWkoM0Ox .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-GsQMNEDCWWkoM0Ox .marker{fill:#333333;stroke:#333333;}#mermaid-svg-GsQMNEDCWWkoM0Ox .marker.cross{stroke:#333333;}#mermaid-svg-GsQMNEDCWWkoM0Ox svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-GsQMNEDCWWkoM0Ox p{margin:0;}#mermaid-svg-GsQMNEDCWWkoM0Ox .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-GsQMNEDCWWkoM0Ox .cluster-label text{fill:#333;}#mermaid-svg-GsQMNEDCWWkoM0Ox .cluster-label span{color:#333;}#mermaid-svg-GsQMNEDCWWkoM0Ox .cluster-label span p{background-color:transparent;}#mermaid-svg-GsQMNEDCWWkoM0Ox .label text,#mermaid-svg-GsQMNEDCWWkoM0Ox span{fill:#333;color:#333;}#mermaid-svg-GsQMNEDCWWkoM0Ox .node rect,#mermaid-svg-GsQMNEDCWWkoM0Ox .node circle,#mermaid-svg-GsQMNEDCWWkoM0Ox .node ellipse,#mermaid-svg-GsQMNEDCWWkoM0Ox .node polygon,#mermaid-svg-GsQMNEDCWWkoM0Ox .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-GsQMNEDCWWkoM0Ox .rough-node .label text,#mermaid-svg-GsQMNEDCWWkoM0Ox .node .label text,#mermaid-svg-GsQMNEDCWWkoM0Ox .image-shape .label,#mermaid-svg-GsQMNEDCWWkoM0Ox .icon-shape .label{text-anchor:middle;}#mermaid-svg-GsQMNEDCWWkoM0Ox .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-GsQMNEDCWWkoM0Ox .rough-node .label,#mermaid-svg-GsQMNEDCWWkoM0Ox .node .label,#mermaid-svg-GsQMNEDCWWkoM0Ox .image-shape .label,#mermaid-svg-GsQMNEDCWWkoM0Ox .icon-shape .label{text-align:center;}#mermaid-svg-GsQMNEDCWWkoM0Ox .node.clickable{cursor:pointer;}#mermaid-svg-GsQMNEDCWWkoM0Ox .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-GsQMNEDCWWkoM0Ox .arrowheadPath{fill:#333333;}#mermaid-svg-GsQMNEDCWWkoM0Ox .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-GsQMNEDCWWkoM0Ox .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-GsQMNEDCWWkoM0Ox .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-GsQMNEDCWWkoM0Ox .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-GsQMNEDCWWkoM0Ox .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-GsQMNEDCWWkoM0Ox .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-GsQMNEDCWWkoM0Ox .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-GsQMNEDCWWkoM0Ox .cluster text{fill:#333;}#mermaid-svg-GsQMNEDCWWkoM0Ox .cluster span{color:#333;}#mermaid-svg-GsQMNEDCWWkoM0Ox div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-GsQMNEDCWWkoM0Ox .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-GsQMNEDCWWkoM0Ox rect.text{fill:none;stroke-width:0;}#mermaid-svg-GsQMNEDCWWkoM0Ox .icon-shape,#mermaid-svg-GsQMNEDCWWkoM0Ox .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-GsQMNEDCWWkoM0Ox .icon-shape p,#mermaid-svg-GsQMNEDCWWkoM0Ox .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-GsQMNEDCWWkoM0Ox .icon-shape .label rect,#mermaid-svg-GsQMNEDCWWkoM0Ox .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-GsQMNEDCWWkoM0Ox .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-GsQMNEDCWWkoM0Ox .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-GsQMNEDCWWkoM0Ox :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Kernel / MCU
HAL Layer
AIDL Interfaces
Native Daemon
Framework (Java)
App Layer
ICarPower.Stub
power policy delegation
CarApp / Launcher
CarPowerManager

public API
CarPowerManagementService

State Machine
PowerComponentHandler
ScreenOffHandler
PolicyReader
carPowerPolicyDaemon

Policy Engine
PowerComponentHandler

C++
ICarPowerPolicyServer.aidl
ICarPowerPolicyChangeCallback.aidl
PowerComponent.aidl
Vehicle HAL

IVehicle
PowerHalService
Linux PM / VMCU

核心组件职责

组件 语言 位置 职责
CarPowerManager Java car-lib/.../power/ 应用层 API,提供状态变更回调
CarPowerManagementService Java service/.../car/power/ 电源状态机引擎,驱动状态流转
PowerComponentHandler Java service/.../car/power/ 电源组件(Audio/Display/WiFi/Bluetooth 等)状态跟踪
ScreenOffHandler Java service/.../car/power/ 息屏判定与 Display 电源下电时序
PolicyReader Java service/.../car/power/ 解析 power_policy.xml 策略配置
carPowerPolicyDaemon C++ cpp/powerpolicy/ Native 策略守护进程,单一事实来源
ICarPowerPolicyServer.aidl AIDL frameworks/hardware/interfaces/.../powerpolicy/ 策略 daemon 的 AIDL 接口

三、电源状态机(CarPowerManagementService)

3.1 核心状态定义

CarPowerManagementService 的包路径为 com.android.car.power,通过内部类 CpmsState 定义电源状态:

java 复制代码
// packages/services/Car/service/src/com/android/car/power/CarPowerManagementService.java
package com.android.car.power;

public class CarPowerManagementService extends ICarPower.Stub implements
        CarServiceBase, PowerHalService.PowerEventListener {
    
    // CpmsState 内部类,同时持有 AP 状态和 listener 状态
    private static class CpmsState {
        // AP 电源状态
        static final int WAIT_FOR_VHAL = 0;
        static final int ON = 1;
        static final int SHUTDOWN_PREPARE = 2;
        static final int WAIT_FOR_FINISH = 3;
        static final int SUSPEND = 4;
        static final int GARAGE_MODE_SHUTDOWN_PREPARE = 5;
        static final int SHUTDOWN_POSTPONE = 6;
        static final int SIMULATE_ERROR_STATE = 7;
        static final int SHUTDOWN_IMMEDIATELY = 8;
        
        public final int mState;
        public final int mCarPowerStateListenerState;
        
        CpmsState(int state, int listenerState) {
            mState = state;
            mCarPowerStateListenerState = listenerState;
        }
    }
}

3.2 状态流转图

#mermaid-svg-Hr14EE6OqT6Eg1ou{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Hr14EE6OqT6Eg1ou .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Hr14EE6OqT6Eg1ou .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Hr14EE6OqT6Eg1ou .error-icon{fill:#552222;}#mermaid-svg-Hr14EE6OqT6Eg1ou .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Hr14EE6OqT6Eg1ou .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Hr14EE6OqT6Eg1ou .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Hr14EE6OqT6Eg1ou .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Hr14EE6OqT6Eg1ou .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Hr14EE6OqT6Eg1ou .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Hr14EE6OqT6Eg1ou .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Hr14EE6OqT6Eg1ou .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Hr14EE6OqT6Eg1ou .marker.cross{stroke:#333333;}#mermaid-svg-Hr14EE6OqT6Eg1ou svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Hr14EE6OqT6Eg1ou p{margin:0;}#mermaid-svg-Hr14EE6OqT6Eg1ou defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-Hr14EE6OqT6Eg1ou g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-Hr14EE6OqT6Eg1ou g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-Hr14EE6OqT6Eg1ou g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-Hr14EE6OqT6Eg1ou g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-Hr14EE6OqT6Eg1ou g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-Hr14EE6OqT6Eg1ou .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-Hr14EE6OqT6Eg1ou .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-Hr14EE6OqT6Eg1ou .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-Hr14EE6OqT6Eg1ou .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-Hr14EE6OqT6Eg1ou .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-Hr14EE6OqT6Eg1ou .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-Hr14EE6OqT6Eg1ou .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-Hr14EE6OqT6Eg1ou .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Hr14EE6OqT6Eg1ou .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Hr14EE6OqT6Eg1ou .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Hr14EE6OqT6Eg1ou .edgeLabel .label text{fill:#333;}#mermaid-svg-Hr14EE6OqT6Eg1ou .label div .edgeLabel{color:#333;}#mermaid-svg-Hr14EE6OqT6Eg1ou .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-Hr14EE6OqT6Eg1ou .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-Hr14EE6OqT6Eg1ou .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-Hr14EE6OqT6Eg1ou .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-Hr14EE6OqT6Eg1ou .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-Hr14EE6OqT6Eg1ou .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Hr14EE6OqT6Eg1ou .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Hr14EE6OqT6Eg1ou #statediagram-barbEnd{fill:#333333;}#mermaid-svg-Hr14EE6OqT6Eg1ou .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Hr14EE6OqT6Eg1ou .cluster-label,#mermaid-svg-Hr14EE6OqT6Eg1ou .nodeLabel{color:#131300;}#mermaid-svg-Hr14EE6OqT6Eg1ou .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-Hr14EE6OqT6Eg1ou .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-Hr14EE6OqT6Eg1ou .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-Hr14EE6OqT6Eg1ou .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-Hr14EE6OqT6Eg1ou .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-Hr14EE6OqT6Eg1ou .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-Hr14EE6OqT6Eg1ou .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-Hr14EE6OqT6Eg1ou .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-Hr14EE6OqT6Eg1ou .note-edge{stroke-dasharray:5;}#mermaid-svg-Hr14EE6OqT6Eg1ou .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-Hr14EE6OqT6Eg1ou .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-Hr14EE6OqT6Eg1ou .statediagram-note text{fill:black;}#mermaid-svg-Hr14EE6OqT6Eg1ou .statediagram-note .nodeLabel{color:black;}#mermaid-svg-Hr14EE6OqT6Eg1ou .statediagram .edgeLabel{color:red;}#mermaid-svg-Hr14EE6OqT6Eg1ou #dependencyStart,#mermaid-svg-Hr14EE6OqT6Eg1ou #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-Hr14EE6OqT6Eg1ou .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Hr14EE6OqT6Eg1ou :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 系统启动 / VMCU 上电
VHAL 就绪(VHAL 通知)
熄火 / sleep 信号
OTA / 后台任务
App 准备完成
App 请求推迟
所有组件就绪
组件繁忙
Garage 准备完成
推迟
超时 / 恢复
超时恢复
唤醒事件(开门 / CAN)
深度休眠(Shutdown / Hibernate)
WAIT_FOR_VHAL
ON
SHUTDOWN_PREPARE
GARAGE_MODE_SHUTDOWN_PREPARE
WAIT_FOR_FINISH
SHUTDOWN_POSTPONE
SUSPEND

3.3 PowerHandler 驱动的状态变换

与传统的 switch-case 状态机不同,AAOS 采用 Handler + 消息队列 的异步驱动模式。PowerHandlerCarPowerManagementService 的内部 Handler,负责串行处理所有电源状态变更:

java 复制代码
// 初始化
public void init() {
    synchronized (mLock) {
        mHandlerThread = new HandlerThread(CarLog.TAG_POWER);
        mHandlerThread.start();
        mHandler = new PowerHandler(mHandlerThread.getLooper());
    }

    mHal.setListener(this);
    if (mHal.isPowerStateSupported()) {
        // 初始状态:等待 VHAL 注册
        // CpmsState(内部状态, listener状态)
        onApPowerStateChange(new CpmsState(CpmsState.WAIT_FOR_VHAL,
                             CarPowerManager.STATE_WAIT_FOR_VHAL));
    } else {
        onApPowerStateChange(new CpmsState(CpmsState.ON,
                             CarPowerManager.STATE_ON));
    }
    mSystemInterface.startDisplayStateMonitoring(this);
}

当 VHAL 通知电源事件时,onApPowerStateChange 被调用:

java 复制代码
@Override
public void onApPowerStateChange(PowerState state) {
    PowerHandler handler;
    synchronized (CarPowerManagementService.this) {
        mPendingPowerStates.addFirst(new CpmsState(state));
        handler = mHandler;
    }
    handler.handlePowerStateChange();
}

核心处理逻辑在 doHandlePowerStateChange() 中:

java 复制代码
private void doHandlePowerStateChange() {
    CpmsState state;
    synchronized (CarPowerManagementService.this) {
        state = mPendingPowerStates.peekFirst();
        mPendingPowerStates.clear();
        if (state == null) return;
        if (!needPowerStateChangeLocked(state)) return;
        releaseTimerLocked();
    }
    
    Log.i(TAG, "setCurrentState " + state.toString());
    mCurrentState = state;
    
    switch (state.mState) {
        case CpmsState.WAIT_FOR_VHAL:
            handleWaitForVhal(state);
            break;
        case CpmsState.ON:
            handleOn(state);
            break;
        case CpmsState.SHUTDOWN_PREPARE:
            handleShutdownPrepare(state);
            break;
        // ... 其他状态
    }
}

3.4 Suspend 主流程源码追踪

当 VMCU 检测到驾驶员熄火,通过 VHAL 触发 sleep 流程:
VMCU PowerHalService CarPowerManagementService CarPowerManager 应用 VMCU PowerHalService CarPowerManagementService CarPowerManager 应用 #mermaid-svg-XQ6cymqvvgaiQdDd{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-XQ6cymqvvgaiQdDd .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-XQ6cymqvvgaiQdDd .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-XQ6cymqvvgaiQdDd .error-icon{fill:#552222;}#mermaid-svg-XQ6cymqvvgaiQdDd .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-XQ6cymqvvgaiQdDd .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-XQ6cymqvvgaiQdDd .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-XQ6cymqvvgaiQdDd .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-XQ6cymqvvgaiQdDd .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-XQ6cymqvvgaiQdDd .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-XQ6cymqvvgaiQdDd .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-XQ6cymqvvgaiQdDd .marker{fill:#333333;stroke:#333333;}#mermaid-svg-XQ6cymqvvgaiQdDd .marker.cross{stroke:#333333;}#mermaid-svg-XQ6cymqvvgaiQdDd svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-XQ6cymqvvgaiQdDd p{margin:0;}#mermaid-svg-XQ6cymqvvgaiQdDd .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-XQ6cymqvvgaiQdDd text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-XQ6cymqvvgaiQdDd .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-XQ6cymqvvgaiQdDd .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-XQ6cymqvvgaiQdDd .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-XQ6cymqvvgaiQdDd .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-XQ6cymqvvgaiQdDd #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-XQ6cymqvvgaiQdDd .sequenceNumber{fill:white;}#mermaid-svg-XQ6cymqvvgaiQdDd #sequencenumber{fill:#333;}#mermaid-svg-XQ6cymqvvgaiQdDd #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-XQ6cymqvvgaiQdDd .messageText{fill:#333;stroke:none;}#mermaid-svg-XQ6cymqvvgaiQdDd .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-XQ6cymqvvgaiQdDd .labelText,#mermaid-svg-XQ6cymqvvgaiQdDd .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-XQ6cymqvvgaiQdDd .loopText,#mermaid-svg-XQ6cymqvvgaiQdDd .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-XQ6cymqvvgaiQdDd .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-XQ6cymqvvgaiQdDd .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-XQ6cymqvvgaiQdDd .noteText,#mermaid-svg-XQ6cymqvvgaiQdDd .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-XQ6cymqvvgaiQdDd .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-XQ6cymqvvgaiQdDd .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-XQ6cymqvvgaiQdDd .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-XQ6cymqvvgaiQdDd .actorPopupMenu{position:absolute;}#mermaid-svg-XQ6cymqvvgaiQdDd .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-XQ6cymqvvgaiQdDd .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-XQ6cymqvvgaiQdDd .actor-man circle,#mermaid-svg-XQ6cymqvvgaiQdDd line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-XQ6cymqvvgaiQdDd :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 启动 SHUTDOWN_PREPARE 超时定时器 通知所有组件准备 suspend 写入 /sys/power/statemem → Suspend-to-RAMdisk → Hibernate alt组件未就绪全部就绪 VEHICLE_POWER_STATE_SLEEPonApPowerStateChange(SHUTDOWN_PREPARE)onStateChanged(SHUTDOWN_PREPARE)finished(state) 确认完成PowerComponentHandler 遍历组件状态等待组件回调或超时进入 WAIT_FOR_FINISHSystemInterface 执行 suspendVHAL 通知 VMCU AP 已休眠切断 SoC 主电源

应用层通过 CarPowerManager 注册监听器。Android 14 在 car-lib/src/android/car/hardware/power/CarPowerManager.java 中定义了带 STATE_ 前缀的电源状态常量,应用收到的是 public API 层的状态值,而非 CPMS 内部的 CpmsState

java 复制代码
// car-lib/src/android/car/hardware/power/CarPowerManager.java
package android.car.hardware.power;

public class CarPowerManager extends CarManagerBase {
    // 电源状态常量(与 native 层 CarPowerManager.h 保持一致)
    @SystemApi
    public static final int STATE_INVALID = 0;
    public static final int STATE_WAIT_FOR_VHAL = 1;
    public static final int STATE_SUSPEND_ENTER = 2;
    public static final int STATE_SUSPEND_EXIT = 3;
    public static final int STATE_SHUTDOWN_ENTER = 5;
    public static final int STATE_ON = 6;
    public static final int STATE_SHUTDOWN_PREPARE = 7;
    public static final int STATE_SHUTDOWN_CANCELLED = 8;
    public static final int STATE_HIBERNATION_ENTER = 9;
    public static final int STATE_HIBERNATION_EXIT = 10;
    public static final int STATE_PRE_SHUTDOWN_PREPARE = 11;
    public static final int STATE_POST_SUSPEND_ENTER = 12;
    public static final int STATE_POST_SHUTDOWN_ENTER = 13;
    public static final int STATE_POST_HIBERNATION_ENTER = 14;

    @Retention(RetentionPolicy.SOURCE)
    @IntDef(prefix = "STATE_", value = {
        STATE_INVALID, STATE_WAIT_FOR_VHAL,
        STATE_SUSPEND_ENTER, STATE_SUSPEND_EXIT,
        STATE_SHUTDOWN_ENTER, STATE_ON,
        STATE_SHUTDOWN_PREPARE, STATE_SHUTDOWN_CANCELLED,
        STATE_HIBERNATION_ENTER, STATE_HIBERNATION_EXIT,
        STATE_PRE_SHUTDOWN_PREPARE,
        STATE_POST_SUSPEND_ENTER,
        STATE_POST_SHUTDOWN_ENTER,
        STATE_POST_HIBERNATION_ENTER,
    })
    public @interface CarPowerState {}

    // 基础监听器(同步返回)
    @SystemApi
    public interface CarPowerStateListener {
        void onStateChanged(@CarPowerState int state);
    }

    // 带异步完成回调的监听器(需调用 future.complete())
    @SystemApi
    public interface CarPowerStateListenerWithCompletion {
        void onStateChanged(@CarPowerState int state,
                @NonNull CompletablePowerStateChangeFuture future);
    }

    @RequiresPermission(Car.PERMISSION_CAR_POWER)
    public void requestShutdownOnNextSuspend() {
        try {
            mService.requestShutdownOnNextSuspend();
        } catch (RemoteException e) {
            handleRemoteExceptionFromCarService(e);
        }
    }
}

注意:STATE_SHUTDOWN_PREPARE(值 7)对应 CPMS 内部的 SHUTDOWN_PREPARESTATE_SUSPEND_ENTER(值 2)是通知应用准备 suspend 的 public API 状态。两者数值不同,CPMS 在 CpmsState 构造时同时记录 mState(CPMS 内部状态)和 mListenerState(通知给 listener 的状态),通过 PowerHandler 在通知时完成翻译。


四、电源策略引擎(Power Policy)

4.1 PowerComponent 体系

PowerComponent.aidl 定义了所有可独立控制的电源组件,位于 frameworks/hardware/interfaces/automotive/powerpolicy/aidl/

java 复制代码
// frameworks/hardware/interfaces/automotive/powerpolicy/aidl/
// android/frameworks/automotive/powerpolicy/PowerComponent.aidl
package android.frameworks.automotive.powerpolicy;

@Backing(type="byte")
enum PowerComponent {
    INVALID,
    AUDIO,
    MEDIA,
    DISPLAY,
    BLUETOOTH,
    WIFI,
    CELLULAR,
    ETHERNET,
    PROJECTION,
    NFC,
    INPUT,
    VISUAL_INTERACTION,
    VOICE_INTERACTION,
    TRUSTED_DEVICE_DETECTION,
    LOCATION,
    MICROPHONE,
    CPU,
}

4.2 PowerPolicy 定义与 XML 配置

OEM 在 /vendor/etc/automotive/power_policy.xml 中定义电源策略:

xml 复制代码
<!-- /vendor/etc/automotive/power_policy.xml -->
<power_policy_group>
    <!-- 预占策略:高优先级,覆盖当前策略 -->
    <power_policy id="emergency_call" pre_emptive="true">
        <component type="AUDIO" state="ON"/>
        <component type="DISPLAY" state="ON"/>
        <component type="VOICE_INTERACTION" state="ON"/>
    </power_policy>

    <!-- 普通休眠策略 -->
    <power_policy id="sleep">
        <component type="AUDIO" state="OFF"/>
        <component type="DISPLAY" state="OFF"/>
        <component type="MEDIA" state="OFF"/>
    </power_policy>

    <!-- Garage Mode 策略 -->
    <power_policy id="garage_mode">
        <component type="AUDIO" state="OFF"/>
        <component type="DISPLAY" state="OFF"/>
        <component type="MEDIA" state="OFF"/>
    </power_policy>
</power_policy_group>

PolicyReader.java 的具体解析逻辑:

java 复制代码
// packages/services/Car/service/src/com/android/car/power/PolicyReader.java
package com.android.car.power;

class PolicyReader {
    private final Map<String, PowerPolicy> mPolicies = new ArrayMap<>();
    
    public void parsePowerPolicies(@NonNull XmlResourceParser parser) {
        // 解析 <power_policy id="..." pre_emptive="true|false">
        // 内部的 <component type="..." state="..."/>
        // 构建策略映射表,供 PowerComponentHandler 使用
    }
}

4.3 ICarPowerPolicyServer 接口

Native 策略 daemon 通过 ICarPowerPolicyServer.aidl 暴露服务,路径在 frameworks/hardware/interfaces/

java 复制代码
// frameworks/hardware/interfaces/automotive/powerpolicy/aidl/
// android/frameworks/automotive/powerpolicy/ICarPowerPolicyServer.aidl
package android.frameworks.automotive.powerpolicy;

@VintfStability
interface ICarPowerPolicyServer {
    CarPowerPolicy getCurrentPowerPolicy();
    boolean getPowerComponentState(in PowerComponent componentId);
    
    void registerPowerPolicyChangeCallback(
        in ICarPowerPolicyChangeCallback callback,
        in CarPowerPolicyFilter filter);
    void unregisterPowerPolicyChangeCallback(
        in ICarPowerPolicyChangeCallback callback);
    
    void applyPowerPolicy(in @utf8InCpp String policyId);
    void setPowerPolicyGroup(in @utf8InCpp String policyGroupId);
}

CarPowerPolicy 的 Java 层封装:

java 复制代码
// car-lib/src/android/car/hardware/power/CarPowerPolicy.java
public final class CarPowerPolicy implements Parcelable {
    public String getPolicyId() { /* 返回策略 ID */ }
    public int[] getEnabledComponents() { /* 返回开启的组件列表 */ }
    public int[] getDisabledComponents() { /* 返回关闭的组件列表 */ }
    public boolean isComponentEnabled(int component) { /* 检查组件状态 */ }
}

五、PowerComponentHandler + ScreenOffHandler

5.1 PowerComponentHandler:组件状态跟踪与 Mediator 模式

PowerComponentHandler 在 Android 14 中采用 Mediator 模式 管理各电源组件的开关状态。它持有 SparseBooleanArray mComponentStates 记录每个组件的使能状态,并为特定组件注册 PowerComponentMediator 来处理用户可控制组件的策略冲突:

java 复制代码
// packages/services/Car/service/src/com/android/car/power/PowerComponentHandler.java
package com.android.car.power;

import android.car.hardware.power.CarPowerPolicy;
import android.car.hardware.power.CarPowerPolicyFilter;
import android.car.hardware.power.PowerComponent;
import static android.car.hardware.power.PowerComponentUtil.*;

class PowerComponentHandler {
    // 组件当前状态(true=使能,false=关闭)
    private final SparseBooleanArray mComponentStates = new SparseBooleanArray();
    // 被电源策略关闭的组件(key=component, value=true)
    private final SparseBooleanArray mComponentsOffByPolicy = new SparseBooleanArray();
    // Mediator 映射表 --- 处理用户可控制组件的策略仲裁
    private final SparseArray<PowerComponentMediator> mPowerComponentMediators =
            new SparseArray<>();
    // 上一次策略变更中被修改的组件列表
    private final ArrayList<Integer> mLastModifiedComponents = new ArrayList<>();
    
    PowerComponentHandler(Context context, SystemInterface systemInterface) { /* ... */ }

    /** 根据 CarPowerPolicy 一次性更新多个组件状态 */
    void applyPowerPolicy(CarPowerPolicy policy) {
        synchronized (mLock) {
            mLastModifiedComponents.clear();
            int[] enabled = policy.getEnabledComponents();
            int[] disabled = policy.getDisabledComponents();
            
            for (int component : enabled) {
                if (!mComponentStates.get(component, false)) {
                    setComponentEnabledLocked(component, true);
                    mLastModifiedComponents.add(component);
                }
            }
            for (int component : disabled) {
                if (mComponentStates.get(component, false)) {
                    setComponentEnabledLocked(component, false);
                    mLastModifiedComponents.add(component);
                }
            }
        }
    }
    
    /** 修改单个组件状态(Mediator 会介入用户可控组件) */
    @GuardedBy("mLock")
    private boolean setComponentEnabledLocked(int component, boolean enabled) {
        int componentIndex = mComponentStates.indexOfKey(component);
        boolean oldState = mComponentStates.get(component, false);
        if (oldState == enabled && componentIndex >= 0) return false;
        
        mComponentStates.put(component, enabled);
        
        PowerComponentMediator mediator = mPowerComponentMediators.get(component);
        if (mediator == null) return true;
        
        if (mediator.isUserControllable()) {
            if (!enabled && mediator.isUserEnabled()) {
                mediator.disableByPolicy();  // 策略覆盖用户设置
            } else if (enabled && mediator.isDisabledByPolicy()) {
                mediator.restoreUserSetting();  // 恢复用户偏好
            }
        }
        return true;
    }
    
    boolean isComponentEnabled(int component) {
        return mComponentStates.get(component, false);
    }
}

PowerComponentMediator 负责仲裁"策略要求关 vs 用户想开"的冲突,保障紧急电话等高优先级场景不被用户设置阻断。

5.2 ScreenOffHandler:多 Display 息屏管理

Android 14 的车机支持多屏(仪表盘、中控、后排娱乐),ScreenOffHandlerDisplayPowerMode 管理每个 Display 的电源模式。四种模式定义在内部注解 @DisplayPowerMode

模式 常量 行为
NONE DISPLAY_POWER_MODE_NONE 未初始化
OFF DISPLAY_POWER_MODE_OFF 息屏,超时后关闭
ON DISPLAY_POWER_MODE_ON 亮屏,用户注销后超时息屏
ALWAYS_ON DISPLAY_POWER_MODE_ALWAYS_ON 常亮,用户可手动关闭

使用 DisplayPowerInfo 内部类为每块屏幕维护独立状态:

java 复制代码
// packages/services/Car/service/src/com/android/car/power/ScreenOffHandler.java
package com.android.car.power;

class ScreenOffHandler {
    @VisibleForTesting
    static final int DISPLAY_POWER_MODE_NONE = -1;
    @VisibleForTesting
    static final int DISPLAY_POWER_MODE_OFF = 0;
    @VisibleForTesting
    static final int DISPLAY_POWER_MODE_ON = 1;
    @VisibleForTesting
    static final int DISPLAY_POWER_MODE_ALWAYS_ON = 2;
    
    @IntDef(prefix = "DISPLAY_POWER_MODE_", value = {
        DISPLAY_POWER_MODE_NONE,
        DISPLAY_POWER_MODE_OFF,
        DISPLAY_POWER_MODE_ON,
        DISPLAY_POWER_MODE_ALWAYS_ON,
    })
    private @interface DisplayPowerMode {}
    
    // 每块 Display 的状态跟踪
    private static final class DisplayPowerInfo {
        private final int mDisplayId;
        private int mUserId;
        private @DisplayPowerMode int mMode;
        private boolean mIsDriverDisplay;
        private long mLastUserActivityTime;
        // ...
    }
    
    private final Context mContext;
    private final SystemInterface mSystemInterface;
    private final Handler mHandler;
    private final SparseArray<DisplayPowerInfo> mDisplayPowerInfos = new SparseArray<>();
    private final DisplayManager mDisplayManager;
    
    ScreenOffHandler(Context context, SystemInterface systemInterface, Looper looper) {
        mContext = context;
        mSystemInterface = systemInterface;
        mHandler = new Handler(looper);
        mDisplayManager = context.getSystemService(DisplayManager.class);
        // 为每个 Display 创建 DisplayPowerInfo
        DisplayHelper.forEachDisplay(mDisplayManager, (displayId) -> {
            mDisplayPowerInfos.put(displayId,
                new DisplayPowerInfo(displayId));
        });
    }
    
    /** 设置指定 Display 的电源模式 */
    void setDisplayMode(int displayId, @DisplayPowerMode int mode) {
        DisplayPowerInfo info = mDisplayPowerInfos.get(displayId);
        if (info == null) return;
        info.setMode(mode);
        scheduleDisplayStateUpdate(displayId);
    }
    
    /** 用户交互时刷新息屏定时器 */
    void onUserActivity(int displayId) {
        DisplayPowerInfo info = mDisplayPowerInfos.get(displayId);
        if (info == null) return;
        info.setLastUserActivityTime(SystemClock.elapsedRealtime());
        scheduleDisplayStateUpdate(displayId);
    }
    
    private void scheduleDisplayStateUpdate(int displayId) {
        mHandler.removeMessages(MSG_UPDATE_DISPLAY_STATE, displayId);
        mHandler.sendMessageDelayed(
            mHandler.obtainMessage(MSG_UPDATE_DISPLAY_STATE, displayId, 0),
            getScreenOffDelayMs(displayId));
    }
}

六、休眠模式详解

6.1 Suspend-to-RAM(S3 / STR)

CPMS 通过 SystemInterface 执行最终的 suspend 调用。SystemInterface 定义了三个 suspend 结果常量,用于处理 suspend 成功、需要重试、或者中止的情况:

java 复制代码
// com.android.car.systeminterface.SystemInterface
import static com.android.car.systeminterface.SystemInterface.SUSPEND_RESULT_ABORT;
import static com.android.car.systeminterface.SystemInterface.SUSPEND_RESULT_RETRY;
import static com.android.car.systeminterface.SystemInterface.SUSPEND_RESULT_SUCCESS;

// 在 CPMS 中处理 suspend 结果:
// mSystemInterface 负责与 BSP/kernel 交互
// 如果 suspend 失败(SUSPEND_RESULT_RETRY),CPMS 会以指数退避重试
// 初始间隔 INITIAL_SUSPEND_RETRY_INTERVAL_MS = 10ms
// 最大间隔 MAX_RETRY_INTERVAL_MS = 100ms

底层通过写入 /sys/power/state 实现。从 source.android.com 官方文档确认:

bash 复制代码
# 挂起到 RAM
echo mem > /sys/power/state

# 挂起到磁盘(hibernate)
echo disk > /sys/power/state

CPMS 在 Suspend-to-RAM 前会先等待组件就绪,并启动 MIN_SUSPEND_WAIT_DURATION_MS ~ MAX_SUSPEND_WAIT_DURATION_MS(最大 3 分钟)的超时定时器。如果所有组件确认就绪,CPMS 通知 VMCU AP 已休眠,VMCU 切断 SoC 主电源。

6.2 唤醒源管理

唤醒源 优先级 典型场景
CAN Bus 消息 开门、点火、远程控车
GPIO 中断 物理按键
USB 插入 CarPlay / Android Auto
RTC 定时 OTA 定时唤醒
网络 WoWLAN 远程查询车辆状态

七、常见问题与调优 Checklist

7.1 应用层注意事项

  • 正确注册监听器 :使用 CarPowerStateListener,不要依赖 ACTION_SCREEN_OFF
  • 异步完成回调onStateChanged 带有 CompletablePowerStateChangeFuture,应用完成准备后必须调用 future.complete()
  • 及时释放资源 :避免在 SHUTDOWN_PREPARE 后长时间持有 wake lock

7.2 OEM 配置建议

  • power_policy.xml:预占策略仅用于紧急电话等高优先级场景
  • Garage Mode 电耗:OTA 下载限制带宽,监控 12V 蓄电池电压
  • ScreenOff 延迟:建议 5000ms+,避免频繁上下电

7.3 调试命令

bash 复制代码
# 查看当前电源状态
adb shell dumpsys car_service --service CarPowerManagementService

# 查看电源策略
adb shell dumpsys car_service --service CarPowerPolicyDaemon

# 查看 PowerComponent 状态
adb shell dumpsys car_service --service PowerComponentHandler

八、总结

AAOS 的电源管理是多层次协同的系统工程:

层次 组件 职责
Java Framework CarPowerManagementService 状态机引擎,通过 PowerHandler + 消息队列驱动
Java Framework PowerComponentHandler / ScreenOffHandler 细粒度组件电源管理
AIDL 接口 ICarPowerPolicyServer.aidl / PowerComponent.aidl 电源策略契约定义
Native Daemon carPowerPolicyDaemon 解析 XML 策略,单一事实来源
HAL PowerHalService / Vehicle HAL 与 VMCU 通信,收发电源事件
Kernel Linux PM suspend/resume 硬件操作

设计亮点在于 Handler 驱动的异步状态机 ------通过 PendingPowerStates + PowerHandler 串行处理,保证状态变更原子性且避免阻塞。Power Policy 机制让 OEM 可以灵活配置各组件的电源行为,无需修改框架代码。

本文基于 Android 14(android-14-dev)AOSP 源码撰写,建议读者结合源码阅读以获得更完整的理解。


版权声明 :本文参考代码来自 AOSP android-14-dev 分支。文中观点仅代表个人理解,如有错误欢迎指正。

相关推荐
Xzaveir2 小时前
企业号码展示不可观测怎么办:状态机、拨测事件与异常回放
android·人工智能
2501_916007472 小时前
iOS和macOS应用程序性能分析和优化工具使用综合指南
android·macos·ios·小程序·uni-app·iphone·webview
黄林晴2 小时前
Nearby Connections 重大变更:不再自动开启 Wi-Fi / 蓝牙,适配指南
android
恋猫de小郭3 小时前
Flutter 全新真 3D 实现,用 flutter_scene 能开发一个「我的世界」
android·前端·flutter
HLC++16 小时前
Linux的进程间通信
android·linux·服务器
爱笑鱼19 小时前
Binder(二):AIDL 生成的 Proxy、Stub 和 Parcel 到底在做什么?
android
爱笑鱼20 小时前
Binder(一):一次方法调用,究竟怎样跨进程执行?
android
壮哥_icon20 小时前
【Android 系统开发】使用 BAT 脚本高效自动化管理 /system/priv-app/ 系统应用(安装与卸载)
android·运维·自动化
用户69371750013841 天前
Claude Code终端日志Token占用实测:一个过滤器砍掉60%-90%
android·前端·后端