AAOS 电源管理深度解析:休眠/唤醒/功耗优化
一、引言
车载操作系统(AAOS)的电源管理与手机有着本质区别。手机只需要考虑单用户手持场景,而 AAOS 要同时面对:熄火断电、驻车娱乐、倒车影像、远程控车、OTA 升级等多复杂场景。一旦休眠时序出错,可能导致黑屏死机、蓝牙断连甚至无法点火。
本文基于 Android 14 (android-14-dev 分支),从 AOSP 源码出发,深入分析 AAOS 电源管理的三大核心模块:
- CarPowerManagementService ------ 电源状态机(
packages/services/Car/service/src/com/android/car/power/) - CarPowerPolicyDaemon ------ 电源策略引擎(
frameworks/hardware/interfaces/automotive/powerpolicy/) - 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 + 消息队列 的异步驱动模式。PowerHandler 是 CarPowerManagementService 的内部 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_PREPARE;STATE_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 的车机支持多屏(仪表盘、中控、后排娱乐),ScreenOffHandler 按 DisplayPowerMode 管理每个 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分支。文中观点仅代表个人理解,如有错误欢迎指正。