Android Automotive Power Policy 全流程技术解析
基于 AOSP(Android15 Automotive LTS3) CarService 源码分析,涵盖从硬件信号到应用层回调的完整链路。
目录
- 架构总览
- 核心参与者
- 系统启动与初始化流程
- [Power Policy 定义体系](#Power Policy 定义体系 "#4-power-policy-%E5%AE%9A%E4%B9%89%E4%BD%93%E7%B3%BB")
- [电源状态机(CPMS State Machine)](#电源状态机(CPMS State Machine) "#5-%E7%94%B5%E6%BA%90%E7%8A%B6%E6%80%81%E6%9C%BAcpms-state-machine")
- [Policy 应用全流程](#Policy 应用全流程 "#6-policy-%E5%BA%94%E7%94%A8%E5%85%A8%E6%B5%81%E7%A8%8B")
- [Listener 注册与通知机制](#Listener 注册与通知机制 "#7-listener-%E6%B3%A8%E5%86%8C%E4%B8%8E%E9%80%9A%E7%9F%A5%E6%9C%BA%E5%88%B6")
- [Listener 通知顺序的决定因素](#Listener 通知顺序的决定因素 "#8-listener-%E9%80%9A%E7%9F%A5%E9%A1%BA%E5%BA%8F%E7%9A%84%E5%86%B3%E5%AE%9A%E5%9B%A0%E7%B4%A0")
- [Silent Mode 机制](#Silent Mode 机制 "#9-silent-mode-%E6%9C%BA%E5%88%B6")
- 典型场景全链路分析
- 调试与验证方法
- 关键源码文件索引
1. 架构总览
Android Automotive Power Policy 框架采用分层架构,由 Native 守护进程和 Java 系统服务协同管理车辆电源组件的开关状态。
scss
┌─────────────────────────────────────────────────────────────────────┐
│ VHAL (Vehicle HAL) │
│ AP_POWER_STATE_REQ / POWER_POLICY_REQ / POWER_POLICY_GROUP │
└──────────┬──────────────────────┬───────────────────────────────────┘
│ │
▼ ▼
┌─────────────────────┐ ┌───────────────────────────────────────────┐
│ PowerHalService │ │ carpowerpolicyd (CPPD) - Native Daemon │
│ (Java, CarService) │ │ │
│ │ │ ┌─────────────┐ ┌────────────────────┐ │
│ 接收 VHAL 电源状态 │ │ │PolicyManager│ │PowerComponentHandler│ │
│ 驱动 CPMS 状态机 │ │ └─────────────┘ └────────────────────┘ │
└─────────┬───────────┘ │ ┌────────────────┐ │
│ │ │SilentModeHandler│ │
▼ │ └────────────────┘ │
┌────────────────────┐ └─────┬─────────────────────┬───────────────┘
│ CPMS │ │ │
│ CarPowerManagement │◄────────┘ │
│ Service │ AIDL (Delegate/ │
│ │ SystemNotification) │
│ ┌──────────────┐ │ │
│ │PolicyReader │ │ ▼
│ │(Java policy) │ │ ┌──────────────────────┐
│ └──────────────┘ │ │ Native Clients │
│ ┌──────────────┐ │ │ (AudioControl HAL, │
│ │PowerComponent│ │ │ AHAL, etc.) │
│ │Handler (Java)│ │ │ 直接连接 CPPD │
│ └──────────────┘ │ └──────────────────────┘
└───────┬────────────┘
│ oneway AIDL (ICarPowerPolicyListener)
▼
┌───────────────────────────────────────────────┐
│ Java Listeners (CarService 内部) │
│ ┌──────────────────┐ ┌────────────────────┐ │
│ │CarAudioPowerList.│ │ CarMediaService │ │
│ │ (AUDIO filter) │ │ (MEDIA filter) │ │
│ └──────────────────┘ └────────────────────┘ │
└───────────────────────────────────────────────┘
关键设计原则:
- CPPD 负责早期(CarService 启动前)电源策略管理和 Native 客户端通知
- CarService 启动后接管电源策略控制权(
notifyCarServiceReady) - Policy 只定义"哪些组件 ON/OFF",不定义执行顺序
- Listener 通知是异步的(
onewayAIDL),不保证严格时序
2. 核心参与者
2.1 carpowerpolicyd(CPPD)
Native C++ 守护进程,运行在独立进程中。
源码位置 :packages/services/Car/cpp/powerpolicy/server/src/
职责:
- 系统启动最早阶段的电源策略管理
- 读取
/vendor/etc/automotive/power_policy.xml配置 - 管理 Accumulated Policy(累积策略状态)
- 通知 Native 客户端(如 Audio HAL)策略变化
- 监听 VHAL 的
POWER_POLICY_REQ和POWER_POLICY_GROUP_REQ属性 - 向 VHAL 写入
CURRENT_POWER_POLICY属性
核心组件:
| 组件 | 说明 |
|---|---|
CarPowerPolicyServer |
AIDL 服务端,处理策略请求和通知 |
PolicyManager |
解析和管理策略定义(含 vendor XML) |
PowerComponentHandler |
维护组件累积状态(Accumulated Policy) |
SilentModeHandler |
监控 sysfs 中的 Silent Mode 硬件状态 |
2.2 CarPowerManagementService(CPMS)
Java 系统服务,运行在 CarService 进程内。
源码位置 :packages/services/Car/service/src/com/android/car/power/CarPowerManagementService.java
职责:
- 实现完整的电源状态机(WAIT_FOR_VHAL → ON → SHUTDOWN_PREPARE → ...)
- 接收 PowerHalService 传来的 VHAL 电源状态事件
- 与 CPPD 通过 AIDL 交互(发送策略变更请求、接收回调)
- 管理 Java 侧 Power Policy Listener(通过
RemoteCallbackList) - 分发策略变更通知给已注册的 Java Listener
核心字段:
java
// 已注册的策略变更 Listener(基于 RemoteCallbackList<ICarPowerPolicyListener>)
private final PowerManagerCallbackList<ICarPowerPolicyListener> mPowerPolicyListeners;
// 与 CPPD 的 AIDL 连接(Refactored 版)
private ICarPowerPolicyDelegate mRefactoredCarPowerPolicyDaemon;
// Legacy 版
private ICarPowerPolicySystemNotification mCarPowerPolicyDaemon;
// 当前策略 ID
private String mCurrentPowerPolicyId;
// 当前策略组 ID
private String mCurrentPowerPolicyGroupId;
// 当前累积策略
private CarPowerPolicy mCurrentAccumulatedPowerPolicy;
// 策略是否被锁定(系统策略生效时锁定)
private boolean mIsPowerPolicyLocked;
2.3 PowerHalService
Java 服务,VHAL 与 CPMS 之间的桥梁。
源码位置 :packages/services/Car/service/src/com/android/car/hal/PowerHalService.java
职责:
- 监听 VHAL 的
AP_POWER_STATE_REQ属性变化 - 将
VehicleApPowerStateReq(ON / SHUTDOWN_PREPARE / CANCEL_SHUTDOWN / FINISHED)转换为PowerState对象 - 通过
PowerEventListener.onApPowerStateChange()回调 CPMS - 提供
sendXxx()方法向 VHAL 报告当前电源状态(AP_POWER_STATE_REPORT)
2.4 PolicyReader
Java 工具类,负责解析和管理电源策略定义。
源码位置 :packages/services/Car/service/src/com/android/car/power/PolicyReader.java
内置系统策略:
| 策略 ID | 类型 | Enabled 组件 | Disabled 组件 |
|---|---|---|---|
system_power_policy_all_on |
普通 | 全部组件 | 无 |
system_power_policy_initial_on |
普通 | AUDIO, DISPLAY, CPU | 其余全部 |
system_power_policy_no_user_interaction |
抢占式 | WIFI, CELLULAR, ETHERNET, TRUSTED_DEVICE_DETECTION, CPU | MEDIA, AUDIO, DISPLAY, BLUETOOTH, PROJECTION, NFC, INPUT, VOICE_INTERACTION, VISUAL_INTERACTION, LOCATION, MICROPHONE |
system_power_policy_suspend_prep |
抢占式 | 无 | AUDIO, BLUETOOTH, WIFI, LOCATION, MICROPHONE, CPU |
2.5 PowerComponentHandler
Java 和 Native 侧各有一个实现,负责维护组件状态和计算累积策略。
Java 侧(CarService 内)
源码 :packages/services/Car/service/src/com/android/car/power/PowerComponentHandler.java
java
// 组件当前状态:component ID -> boolean (on/off)
private final SparseBooleanArray mComponentStates;
// 上次策略变更中被修改的组件
private final SparseBooleanArray mLastModifiedComponents;
applyPowerPolicy() 方法遍历策略的 enabled/disabled 数组,更新 mComponentStates,并记录哪些组件发生了实际变化到 mLastModifiedComponents。
Native 侧(CPPD 内)
源码 :packages/services/Car/cpp/powerpolicy/server/src/PowerComponentHandler.cpp
cpp
void PowerComponentHandler::applyPowerPolicy(const CarPowerPolicyPtr& powerPolicy) {
// 使用 std::unordered_map 合并当前累积状态和新策略
std::unordered_map<PowerComponent, bool> componentStates;
// 先载入当前累积状态
setComponentStates(componentStates, mAccumulatedPolicy->enabledComponents, true);
setComponentStates(componentStates, mAccumulatedPolicy->disabledComponents, false);
// 再叠加新策略
setComponentStates(componentStates, powerPolicy->enabledComponents, true);
setComponentStates(componentStates, powerPolicy->disabledComponents, false);
// 从 unordered_map 写回 vector(顺序不确定)
...
}
重要 :Native 侧使用
std::unordered_map,遍历顺序不确定。因此累积策略中 enabled/disabled vector 的组件排列顺序是不保序的。
3. 系统启动与初始化流程
3.1 CPPD 启动(最早阶段)
css
系统启动
│
▼
carpowerpolicyd main()
│
├─ CarPowerPolicyServer::startService(looper)
│ │
│ ├─ 检查 CarService 是否已运行
│ │ mIsCarServiceInOperation = (AServiceManager_checkService != nullptr)
│ │
│ ├─ mPolicyManager.init()
│ │ ├─ initRegularPowerPolicy() → 注册 all_on, initial_on
│ │ ├─ initPreemptivePowerPolicy() → 注册 no_user_interaction, suspend_prep
│ │ └─ readPowerPolicyConfiguration() → 解析 /vendor/etc/automotive/power_policy.xml
│ │
│ ├─ mComponentHandler.init()
│ │ └─ 所有标准组件初始化为 disabled
│ │
│ ├─ mSilentModeHandler.init()
│ │ └─ 监控 sysfs: pm_silentmode_hw_state
│ │
│ ├─ 注册 AIDL 服务
│ │ ├─ ICarPowerPolicyServer (供 native client 调用)
│ │ └─ ICarPowerPolicyDelegate / ICarPowerPolicySystemNotification (供 CarService 调用)
│ │
│ └─ connectToVhal()
│ ├─ 连接 VHAL Service
│ ├─ applyInitialPowerPolicy()
│ │ ├─ 查找 policyGroup 中 WaitForVHAL 的默认策略
│ │ └─ 如无自定义 → 应用 system_power_policy_initial_on
│ └─ subscribeToVhal()
│ ├─ 订阅 POWER_POLICY_REQ → 收到后 applyPowerPolicy()
│ └─ 订阅 POWER_POLICY_GROUP_REQ → 收到后 setPowerPolicyGroup()
│
└─ Looper 事件循环
3.2 CarService 启动
scss
CarService 启动
│
▼
ICarImpl 构造函数
│
├─ 按序构造各 CarSystemService 并加入 allServices 列表
│ ├─ ...
│ ├─ CarAudioService (line 335)
│ ├─ ...
│ ├─ CarMediaService (line 376)
│ ├─ ...
│ └─ CarPowerManagementService
│
├─ mAllServicesInInitOrder = allServices.toArray()
│
└─ ICarImpl.init()
│
├─ 对每个 service 调用 service.init()
│ │
│ ├─ CPMS.init()
│ │ ├─ 连接 CPPD (connectToPowerPolicyDaemon)
│ │ ├─ mSilentModeHandler.init()
│ │ ├─ 初始化到 WAIT_FOR_VHAL 状态
│ │ └─ 应用默认策略 (initial_on)
│ │
│ ├─ CarAudioService.init()
│ │ └─ 注册 PowerPolicyListener (filter: AUDIO)
│ │
│ ├─ CarMediaService.init()
│ │ └─ 注册 PowerPolicyListener (filter: MEDIA)
│ │
│ └─ ... 其他 Service
│
└─ 通知 CPPD: notifyCarServiceReady()
└─ CPPD 停止独立策略管理: mIsCarServiceInOperation = true
3.3 CPMS 与 CPPD 的控制权交接
存在两种交互模式,取决于 car_power_policy_refactoring feature flag:
Legacy 模式(flag = false):
scss
CPMS ──notifyCarServiceReady()──> CPPD (ICarPowerPolicySystemNotification)
CPMS ──notifyPowerPolicyChange(policyId, force)──> CPPD
(CPMS 主导策略决策,通知 CPPD 执行并通知 native 客户端)
Refactored 模式(flag = true):
scss
CPMS ──notifyCarServiceReady(callback)──> CPPD (ICarPowerPolicyDelegate)
<──返回 PowerPolicyInitData (当前策略、策略组、已注册策略列表)──
CPMS ──applyPowerPolicyAsync(requestId, policyId, force)──> CPPD
(CPPD 执行策略变更,通过 callback 通知 CPMS 更新组件和策略状态)
CPPD ──callback.updatePowerComponents(policy)──> CPMS
CPPD ──callback.onPowerPolicyChanged(accumulatedPolicy)──> CPMS
4. Power Policy 定义体系
4.1 策略来源
电源策略有三个来源,优先级依次降低:
- 系统内置策略 :硬编码在
PolicyReader.java和PolicyManager.cpp中 - Vendor XML 配置 :
/vendor/etc/automotive/power_policy.xml - 运行时动态注册 :通过
notifyPowerPolicyDefinition()AIDL 接口
4.2 Vendor XML 配置格式
xml
<powerPolicy version="1.0" defaultPolicyGroup="basic_policy_group">
<!-- 自定义组件定义 -->
<customComponents>
<customComponent value="1001">CUSTOM_SENSOR</customComponent>
</customComponents>
<!-- 策略定义 -->
<policies>
<policy id="my_custom_policy">
<component id="POWER_COMPONENT_AUDIO">on</component>
<component id="POWER_COMPONENT_MEDIA">off</component>
<otherComponents behavior="untouched"/>
</policy>
</policies>
<!-- 策略组定义 -->
<policyGroups>
<policyGroup id="basic_policy_group">
<defaultPolicy state="WaitForVHAL" id="my_custom_policy"/>
<defaultPolicy state="On" id="my_custom_policy"/>
</policyGroup>
</policyGroups>
<!-- 系统策略覆写(仅允许 BLUETOOTH, NFC, TRUSTED_DEVICE_DETECTION) -->
<systemPolicyOverrides>
<policy id="system_power_policy_no_user_interaction">
<component id="POWER_COMPONENT_BLUETOOTH">on</component>
</policy>
</systemPolicyOverrides>
</powerPolicy>
4.3 策略组与状态映射
策略组(Policy Group)定义了电源状态到默认策略的映射关系:
vbnet
policyGroup "basic_policy_group":
WaitForVHAL → "my_custom_policy"
On → "my_custom_policy"
当电源状态转换时,CPMS 调用 applyDefaultPowerPolicyForState(state, fallbackPolicyId) 查找当前策略组中对应状态的默认策略。如果策略组无配置,则回退到 fallback 策略。
4.4 抢占式策略(Preemptive Power Policy)
抢占式策略具有更高优先级,应用后会锁定策略变更:
java
// applyPreemptivePowerPolicy()
mIsPowerPolicyLocked = true;
mPendingPowerPolicyId = mCurrentPowerPolicyId; // 保存当前策略
mCurrentPowerPolicyId = policyId; // 切换到抢占式策略
当抢占式策略被取消(cancelPreemptivePowerPolicy),之前保存的 pending 策略会被恢复。
系统内置的抢占式策略:
system_power_policy_no_user_interaction:关闭用户交互相关组件system_power_policy_suspend_prep:挂起前准备
4.5 Accumulated Policy(累积策略)
累积策略代表系统中所有组件的当前实际状态,每次应用新策略时叠加更新:
ini
初始状态:所有组件 OFF
│
▼ 应用 initial_on → AUDIO=ON, DISPLAY=ON, CPU=ON,其余不变
│
▼ 应用 all_on → 所有组件 ON
│
▼ 应用 no_user_interaction → MEDIA=OFF, AUDIO=OFF, DISPLAY=OFF, ..., CPU=ON, WIFI=ON, ...
Listener 收到的 accumulatedPolicy 参数即此累积状态。
5. 电源状态机(CPMS State Machine)
5.1 状态定义
java
// CpmsState 内部类
public static final int WAIT_FOR_VHAL = 0; // 等待 VHAL 就绪
public static final int ON = 1; // 正常运行
public static final int SHUTDOWN_PREPARE = 2; // 关机/休眠准备
public static final int WAIT_FOR_FINISH = 3; // 等待 VHAL 确认可以进入休眠
public static final int SUSPEND = 4; // 收到 FINISHED,执行实际挂起
public static final int SIMULATE_SLEEP = 5; // 模拟深度睡眠(调试用)
public static final int SIMULATE_HIBERNATION = 6; // 模拟休眠(调试用)
5.2 状态转换图
scss
系统启动
│
▼
┌─────────────────┐
│ WAIT_FOR_VHAL │◄──────────────── CANCEL_SHUTDOWN
│ (初始状态) │ ▲
└────────┬────────┘ │
│ VHAL 报告 ON │
▼ │
┌─────────────────┐ │
│ ON │ │
│ (正常运行) │ │
└────────┬────────┘ │
│ VHAL 请求 SHUTDOWN_PREPARE │
▼ │
┌─────────────────┐ │
│SHUTDOWN_PREPARE │────────────────────────┘
│ │ (取消关机)
│ PRE_SHUTDOWN_P. │
│ ↓ │
│ SHUTDOWN_PREP. │
└────────┬────────┘
│ Listener 完成 + Garage Mode 结束
▼
┌─────────────────┐
│ WAIT_FOR_FINISH │
│ (SUSPEND_ENTER/ │
│ SHUTDOWN_ENTER/│
│ HIBERN._ENTER) │
└────────┬────────┘
│ VHAL 报告 FINISHED
▼
┌─────────────────┐
│ SUSPEND │
│ (执行挂起) │
└────────┬────────┘
│ 唤醒
▼
┌─────────────────┐
│ WAIT_FOR_VHAL │ (STATE_SUSPEND_EXIT / STATE_HIBERNATION_EXIT)
│ (唤醒后状态) │
└────────┬────────┘
│ VHAL 报告 ON
▼
┌─────────────────┐
│ ON │
└─────────────────┘
5.3 关键状态处理逻辑
WAIT_FOR_VHAL → handleWaitForVhal()
java
private void handleWaitForVhal(CpmsState state) {
mSilentModeHandler.querySilentModeHwState();
if (!mFeatureFlags.carPowerPolicyRefactoring()) {
// 应用 initial_on 策略(仅启用 AUDIO, DISPLAY, CPU)
applyDefaultPowerPolicyForState(STATE_WAIT_FOR_VHAL,
PolicyReader.POWER_POLICY_ID_INITIAL_ON);
if (!mSilentModeHandler.isSilentMode()) {
cancelPreemptivePowerPolicy();
}
}
sendPowerManagerEvent(carPowerStateListenerState, INVALID_TIMEOUT);
// 根据具体子状态向 VHAL 报告
switch (carPowerStateListenerState) {
case STATE_WAIT_FOR_VHAL: mHal.sendWaitForVhal(); break;
case STATE_SHUTDOWN_CANCELLED: mHal.sendShutdownCancel(); break;
case STATE_SUSPEND_EXIT: mHal.sendSleepExit(); break;
case STATE_HIBERNATION_EXIT: mHal.sendHibernationExit(); break;
}
}
ON → handleOn()
java
void handleOn() {
if (!mFeatureFlags.carPowerPolicyRefactoring()) {
if (!mSilentModeHandler.isSilentMode()) {
cancelPreemptivePowerPolicy(); // 取消 no_user_interaction 等抢占策略
}
// 应用 all_on 策略(启用所有组件)
applyDefaultPowerPolicyForState(ON, PolicyReader.POWER_POLICY_ID_ALL_ON);
}
sendPowerManagerEvent(CarPowerManager.STATE_ON, INVALID_TIMEOUT);
mHal.sendOn();
}
SHUTDOWN_PREPARE → handleShutdownPrepare()
分两阶段执行:
阶段1: PRE_SHUTDOWN_PREPARE
java
private void handlePreShutdownPrepare() {
sendPowerManagerEvent(STATE_PRE_SHUTDOWN_PREPARE, timeoutMs);
// 等待 Listener 完成(有超时机制)
waitForCompletionWithShutdownPostpone(state, timeoutMs, taskAtCompletion, intervalMs);
// 完成后转入阶段2
→ onApPowerStateChange(SHUTDOWN_PREPARE, STATE_SHUTDOWN_PREPARE);
}
阶段2: SHUTDOWN_PREPARE (core)
java
private void doShutdownPrepare() {
makeSureNoUserInteraction(); // 应用 no_user_interaction 策略
sendPowerManagerEvent(STATE_SHUTDOWN_PREPARE, timeoutMs);
mHal.sendShutdownPrepare();
waitForShutdownPrepareListenersToComplete(timeoutMs, intervalMs);
// 完成后 → finishShutdownPrepare() → WAIT_FOR_FINISH
}
6. Policy 应用全流程
6.1 策略应用入口
策略应用有多个入口:
| 入口 | 触发方式 | 说明 |
|---|---|---|
| 电源状态转换 | CPMS 状态机 | applyDefaultPowerPolicyForState() |
| 抢占式策略 | makeSureNoUserInteraction() |
applyPreemptivePowerPolicy() |
| VHAL 属性 | POWER_POLICY_REQ |
CPPD 直接处理 |
| Shell 命令 | adb shell cmd car_service apply-power-policy |
调用 CPMS 公开方法 |
| Silent Mode | SilentModeHandler | CPPD 侧直接应用 no_user_interaction |
6.2 Legacy 模式下的完整流程
以 doShutdownPrepare() 调用 makeSureNoUserInteraction() 为例:
less
CPMS.makeSureNoUserInteraction()
│
├─ mSilentModeHandler.updateKernelSilentMode(true)
│ └─ 写入 sysfs: pm_silentmode_kernel_state = 1
│
└─ applyPreemptivePowerPolicy("system_power_policy_no_user_interaction")
│
├─ 1. PolicyReader 查找策略定义
│ mPolicyReader.getPreemptivePowerPolicy(policyId)
│ → CarPowerPolicy {
│ enabled: [WIFI, CELLULAR, ETHERNET, TRUSTED_DEVICE_DETECTION, CPU]
│ disabled: [MEDIA, AUDIO, DISPLAY, BLUETOOTH, PROJECTION, NFC,
│ INPUT, VOICE_INTERACTION, VISUAL_INTERACTION, LOCATION, MICROPHONE]
│ }
│
├─ 2. 锁定策略变更
│ mIsPowerPolicyLocked = true
│ mPendingPowerPolicyId = 之前的策略ID(用于后续恢复)
│
├─ 3. Java 侧 PowerComponentHandler 应用策略
│ mPowerComponentHandler.applyPowerPolicy(policy)
│ │
│ │ 遍历 enabledComponents:
│ │ WIFI → setComponentEnabledLocked(WIFI, true)
│ │ CELLULAR → setComponentEnabledLocked(CELLULAR, true)
│ │ ... 记录实际变化到 mLastModifiedComponents
│ │
│ │ 遍历 disabledComponents:
│ │ MEDIA → setComponentEnabledLocked(MEDIA, false)
│ │ AUDIO → setComponentEnabledLocked(AUDIO, false)
│ │ ... 记录实际变化到 mLastModifiedComponents
│ │
│ └─ mCurrentPolicyId = policyId
│
├─ 4. 通知 CPPD(Legacy: notifyPowerPolicyChangeToDaemon)
│ daemon.notifyPowerPolicyChange(policyId, force=true)
│ │
│ └─ CPPD 侧执行:
│ ├─ applyPowerPolicy(policyId, carServiceExpected=true, force)
│ │ ├─ PolicyManager 查找策略
│ │ ├─ canApplyPowerPolicyLocked() → 检查并锁定
│ │ └─ applyAndNotifyPowerPolicy()
│ │ ├─ mComponentHandler.applyPowerPolicy(policy)
│ │ │ └─ unordered_map 合并累积状态
│ │ │
│ │ ├─ notifyVhalNewPowerPolicy(policyId)
│ │ │ └─ 写入 VHAL: CURRENT_POWER_POLICY = policyId
│ │ │
│ │ └─ 通知 Native Clients:
│ │ for (auto client : clients) {
│ │ ICarPowerPolicyChangeCallback::fromBinder(client.binder)
│ │ ->onPolicyChanged(*accumulatedPolicy);
│ │ }
│ └─ (native clients 如 Audio HAL 收到通知)
│
└─ 5. 通知 Java Listeners
notifyPowerPolicyChangeToListeners(notification, appliedPolicy)
// 详见第7章
6.3 Refactored 模式下的流程差异
scss
CPMS.applyPowerPolicy(policyId, delayNotification=false, upToDaemon=false, force=true)
│
├─ 向 CPPD 发送异步请求
│ daemon.applyPowerPolicyAsync(requestId, policyId, force)
│
├─ CPPD 处理:
│ ├─ PolicyManager 查找策略
│ ├─ applyAndNotifyPowerPolicy()
│ │ ├─ mComponentHandler.applyPowerPolicy(policy)
│ │ ├─ callback.updatePowerComponents(policy) ← 通知 CPMS 更新 Java 侧组件
│ │ ├─ notifyVhalNewPowerPolicy(policyId)
│ │ ├─ 通知 native clients
│ │ └─ callback.onPowerPolicyChanged(accumulatedPolicy) ← 通知 CPMS 策略已生效
│ └─ 发送成功结果给请求方
│
├─ CPMS 等待请求完成 (request.await())
│
├─ 更新本地状态
│ updateCurrentPowerPolicy(accumulatedPolicy)
│
└─ 通知 Java Listeners
notifyPowerPolicyChange(notification)
7. Listener 注册与通知机制
7.1 Listener 注册
Java 侧 Listener 注册
java
// CPMS.addPowerPolicyListener()
public void addPowerPolicyListener(CarPowerPolicyFilter filter,
ICarPowerPolicyListener listener) {
mPowerPolicyListeners.register(listener, filter); // filter 作为 cookie 存储
}
mPowerPolicyListeners 的类型链:
swift
PowerManagerCallbackList<ICarPowerPolicyListener>
extends RemoteCallbackList<ICarPowerPolicyListener>
内部: ArrayMap<IBinder, Callback> mCallbacks
register() 调用 mCallbacks.put(binder, cb),ArrayMap.put() 根据 binder.hashCode() 进行二分查找排序插入。
Native 侧 Listener 注册
cpp
// CarPowerPolicyServer::registerPowerPolicyChangeCallback()
mPolicyChangeCallbacks.emplace_back(binder, filter, callingPid);
// std::vector<CallbackInfo>,按注册顺序追加
7.2 Listener 通知流程(Java 侧)
java
private void notifyPowerPolicyChangeToListeners(
PowerPolicyChangeNotification policyChangeNotification,
CarPowerPolicy appliedPolicy) {
// 在专用 broadcast handler 线程上投递任务
mBroadcastHandler.post(() -> {
// 1. 创建 broadcast 快照(从 ArrayMap 按 index 复制)
int idx = mPowerPolicyListeners.beginBroadcast();
// 2. 倒序遍历(idx-- > 0)
while (idx-- > 0) {
ICarPowerPolicyListener listener =
mPowerPolicyListeners.getBroadcastItem(idx);
CarPowerPolicyFilter filter =
(CarPowerPolicyFilter) mPowerPolicyListeners.getBroadcastCookie(idx);
// 3. 组件过滤:只通知关心的组件发生变化的 Listener
if (!PowerComponentHandler.isComponentChanged(updatedComponents, filter)) {
continue; // 跳过不相关的 Listener
}
// 4. oneway AIDL 调用(异步,不等待返回)
listener.onPolicyChanged(appliedPolicy,
policyChangeNotification.accumulatedPolicy);
}
mPowerPolicyListeners.finishBroadcast();
});
}
7.3 组件过滤机制(isComponentChanged)
java
public static boolean isComponentChanged(SparseBooleanArray updatedComponents,
CarPowerPolicyFilter carPowerPolicyFilter) {
int[] components = carPowerPolicyFilter.getComponents();
for (int i = 0; i < components.length; i++) {
if (updatedComponents.get(components[i], false)) {
return true; // 此 Listener 关心的组件在本次策略变更中发生了变化
}
}
return false; // 无关组件变化,跳过此 Listener
}
这意味着:如果某次策略变更只改变了 AUDIO 状态、没改变 MEDIA 状态,那么 CarMediaService 的 Listener 不会被调用。
7.4 Listener 通知流程(Native 侧)
cpp
// CarPowerPolicyServer::applyAndNotifyPowerPolicy()
auto accumulatedPolicy = mComponentHandler.getAccumulatedPolicy();
for (auto client : clients) {
ICarPowerPolicyChangeCallback::fromBinder(client.binder)
->onPolicyChanged(*accumulatedPolicy);
}
Native 侧采用简单的顺序遍历 std::vector<CallbackInfo>,按注册顺序调用。
8. Listener 通知顺序的决定因素
8.1 Java 侧顺序由 ArrayMap 的 hashCode 排序决定
RemoteCallbackList 内部使用 ArrayMap<IBinder, Callback>。ArrayMap 的 put() 方法通过二分查找将元素按 hashCode 升序 排列在 mHashes[] 数组中:
java
// ArrayMap.put()
hash = mIdentityHashCode ? System.identityHashCode(key) : key.hashCode();
index = indexOf(key, hash);
// index < 0 时,取反得到插入位置
index = ~index;
// System.arraycopy 腾出位置,保持 mHashes[] 升序
mHashes[index] = hash;
注意 :
ArrayMap默认构造函数设mIdentityHashCode = false,因此走key.hashCode()分支。 但Binder未覆写hashCode(),最终调用Object.hashCode(),等价于System.identityHashCode(key)。两个分支结果一致。
beginBroadcast() 按 valueAt(0), valueAt(1), ..., valueAt(N-1) 顺序复制到快照数组,即 hashCode 从小到大。
notifyPowerPolicyChangeToListeners() 使用 while (idx-- > 0) 倒序 遍历,即先调用 hashCode 最大的 Listener。
8.2 hashCode 的来源
ART 运行时的 identityHashCode 实现(art/runtime/mirror/object.cc):
cpp
static uint32_t GenerateIdentityHashCode() {
// LCG 线性同余生成器
// seed 初始值 = 987654321 + time(nullptr),每次启动不同
uint32_t expected_value, new_value;
do {
expected_value = hash_code_seed.load(std::memory_order_relaxed);
new_value = expected_value * 1103515245 + 12345;
} while (!hash_code_seed.compare_exchange_weak(...));
return new_value & LockWord::kHashMask;
}
结论 :Listener 在 ArrayMap 中的位置由其 IBinder 的
identityHashCode决定,该值使用 LCG 伪随机算法生成,种子包含time(nullptr)。因此每次系统启动后,同样两个 Listener 的遍历顺序可能不同。
8.3 实际表现
Suspend(关闭)时 ------由同一策略 no_user_interaction 同时关闭 AUDIO 和 MEDIA:
- 两个 Listener 在同一
while(idx--)循环中被调用 - 哪个先调用,取决于本次启动时两个 IBinder 的 hashCode 大小关系
- 日志可能表现为 Audio 先、Media 后,或反过来
Resume(恢复)时------涉及两个不同的策略:
system_power_policy_initial_on:只启用 AUDIO, DISPLAY, CPU(不包含 MEDIA)isComponentChanged检查:只有 AUDIO Listener 匹配 → 只通知 CarAudioPowerListener
system_power_policy_all_on:启用所有组件- AUDIO 已从 initial_on 变为 ON,此次 all_on 不再改变 AUDIO → 只有 MEDIA Listener 匹配
结论 :Resume 时 Audio 总是先于 Media 恢复,不是因为遍历顺序,而是因为两个策略分两次 broadcast 循环依次应用,Audio 在第一个策略中恢复,Media 在第二个策略中恢复。
8.4 为什么修改 NO_USER_INTERACTION_DISABLED_COMPONENTS 数组顺序无效
该数组仅用于构造策略定义(哪些组件 ON/OFF),不是执行队列。有三个层面保证了它的顺序无意义:
- PolicyReader :数组只构建
CarPowerPolicy对象的 enabled/disabled int 数组 - CPPD PowerComponentHandler :使用
std::unordered_map汇总后写回 vector,顺序被打乱 - CPMS notifyPowerPolicyChangeToListeners:遍历顺序由 ArrayMap 中 Listener 的 hashCode 决定,与组件数组无关
9. Silent Mode 机制
9.1 概述
Silent Mode 用于在车辆发动机未启动(如远程唤醒)时静默运行系统,禁用所有用户交互组件。
9.2 硬件状态监控(CPPD 侧)
cpp
// SilentModeHandler 监控 sysfs 文件
// /sys/kernel/silent_boot/pm_silentmode_hw_state
// 值: "0" = non-silent, "1" = silent
当硬件状态变化时:
php
SilentModeHandler 检测到 hw_state 变化
│
├─ isSilent = true:
│ └─ CarPowerPolicyServer::notifySilentModeChange(true)
│ └─ applyPowerPolicy("system_power_policy_no_user_interaction", ...)
│
└─ isSilent = false:
└─ CarPowerPolicyServer::notifySilentModeChange(false)
└─ applyPowerPolicy(pendingPowerPolicyId, ...) // 恢复之前的策略
9.3 内核状态通知(CPMS 侧)
java
// CPMS 在 doShutdownPrepare() 和 makeSureNoUserInteraction() 中:
mSilentModeHandler.updateKernelSilentMode(true);
// → 写入 /sys/kernel/silent_boot/pm_silentmode_kernel_state = 1
// 通知内核进入静默模式
9.4 Forced Silent Mode(调试用)
通过 shell 命令手动强制 Silent Mode:
bash
# 进入强制静默模式
adb shell cmd car_service silent-mode forced-silent
# 退出强制静默模式
adb shell cmd car_service silent-mode forced-non-silent
# 恢复自动模式
adb shell cmd car_service silent-mode non-forced-silent-mode
10. 典型场景全链路分析
10.1 场景:正常休眠(Suspend to RAM)
css
MCU 发送休眠请求
│
▼
VHAL: AP_POWER_STATE_REQ = SHUTDOWN_PREPARE (type=DEEP_SLEEP, canPostpone=true)
│
▼
PowerHalService.onApPowerStateChange(PowerState)
│
▼
CPMS.onApPowerStateChange(SHUTDOWN_PREPARE, STATE_PRE_SHUTDOWN_PREPARE)
│
▼
doHandlePowerStateChange() → case SHUTDOWN_PREPARE
│
├─ handlePreShutdownPrepare()
│ ├─ sendPowerManagerEvent(STATE_PRE_SHUTDOWN_PREPARE)
│ │ └─ 通知 CarPowerStateListener(带 completion)
│ └─ 等待 Listener 完成(可postpone)
│
▼ 所有 Listener 完成
├─ handleCoreShutdownPrepare() → doShutdownPrepare()
│ │
│ ├─ makeSureNoUserInteraction()
│ │ ├─ updateKernelSilentMode(true)
│ │ └─ applyPreemptivePowerPolicy("no_user_interaction")
│ │ │
│ │ ├─ Java PowerComponentHandler: 更新组件状态
│ │ ├─ → CPPD: notifyPowerPolicyChange("no_user_interaction", force=true)
│ │ │ ├─ CPPD PowerComponentHandler: 合并累积状态
│ │ │ ├─ → VHAL: CURRENT_POWER_POLICY = "no_user_interaction"
│ │ │ └─ → Native Clients: onPolicyChanged(accumulated)
│ │ │ └─ Audio HAL 收到通知,日志: "AUDIO is being disabled"
│ │ │
│ │ └─ → Java Listeners (via mBroadcastHandler):
│ │ ├─ CarAudioPowerListener: setAudioEnabled(false)
│ │ │ └─ 日志: "setting isAudioEnabled to false"
│ │ └─ CarMediaService: MEDIA is OFF, pause playback
│ │ └─ 日志: "onPolicyChanged(); MEDIA is OFF"
│ │
│ ├─ sendPowerManagerEvent(STATE_SHUTDOWN_PREPARE)
│ ├─ mHal.sendShutdownPrepare()
│ └─ waitForShutdownPrepareListenersToComplete() // Garage Mode 运行
│
▼ Garage Mode 完成或超时
├─ finishShutdownPrepare()
│ ├─ applyPreemptivePowerPolicy("suspend_prep") // 关闭更多组件
│ └─ → WAIT_FOR_FINISH (STATE_SUSPEND_ENTER)
│
▼ 等待 Listener 完成
├─ mHal.sendSleepEntry(wakeupSec)
│
▼ VHAL: AP_POWER_STATE_REQ = FINISHED
└─ handleFinish() → 系统挂起
10.2 场景:唤醒恢复(Resume from Suspend)
scss
系统唤醒
│
▼
CPMS.onApPowerStateChange(WAIT_FOR_VHAL, STATE_SUSPEND_EXIT)
│
▼
handleWaitForVhal()
│
├─ mSilentModeHandler.querySilentModeHwState()
│
├─ applyDefaultPowerPolicyForState(WAIT_FOR_VHAL, INITIAL_ON)
│ │
│ └─ 应用 system_power_policy_initial_on
│ enabled: [AUDIO, DISPLAY, CPU] ← 注意:没有 MEDIA!
│ │
│ ├─ isComponentChanged 检查:
│ │ AUDIO 从 OFF→ON: CarAudioPowerListener 匹配 ✓
│ │ MEDIA 未变化: CarMediaService 不匹配 ✗
│ │
│ └─ 只通知 CarAudioPowerListener: setAudioEnabled(true)
│ └─ 日志: "setting isAudioEnabled to true"
│
├─ cancelPreemptivePowerPolicy()
│ └─ mIsPowerPolicyLocked = false, 恢复 pendingPolicyId
│
├─ mHal.sendSleepExit()
│
▼ VHAL: AP_POWER_STATE_REQ = ON
│
handleOn()
│
├─ cancelPreemptivePowerPolicy() // 如果还有
│
└─ applyDefaultPowerPolicyForState(ON, ALL_ON)
│
└─ 应用 system_power_policy_all_on
enabled: [所有组件]
│
├─ isComponentChanged 检查:
│ AUDIO 已经是 ON(从 initial_on): 未变化 → CarAudioPowerListener 不匹配 ✗
│ MEDIA 从 OFF→ON: CarMediaService 匹配 ✓
│
└─ 只通知 CarMediaService: MEDIA is ON
└─ 日志: "onPolicyChanged(); MEDIA is ON"
关键发现 :Resume 过程中,Audio 总是先于 Media 恢复,不是因为遍历顺序,而是因为
initial_on和all_on是两个独立的策略,分两次 broadcast 应用。initial_on只包含 AUDIO(不含 MEDIA),所以 AUDIO 必然最先恢复。
10.3 场景:通过 Shell 命令触发策略切换
bash
# 手动应用策略
adb shell cmd car_service apply-power-policy <policyId>
# 模拟休眠/唤醒
adb shell cmd car_service silent-mode forced-silent # 触发 no_user_interaction
adb shell cmd car_service silent-mode forced-non-silent # 触发恢复
# 模拟完整的挂起-唤醒周期
adb shell cmd car_service suspend
adb shell cmd car_service resume
11. 调试与验证方法
11.1 关键日志 TAG
| TAG | 来源 | 说明 |
|---|---|---|
CarPowerManagementService |
CPMS | 状态机转换、策略应用 |
carpowerpolicyd |
CPPD | Native 守护进程日志 |
CAR.AUDIO |
CarAudioService | Audio 组件状态变更 |
CAR.MEDIA (TAG_MEDIA) |
CarMediaService | Media 组件状态变更 |
AHAL_PowerPolicyClient |
Audio HAL | Native Audio 客户端 |
SilentModeHandler |
CPMS / CPPD | Silent Mode 状态变更 |
11.2 推荐日志过滤
bash
# 综合观察策略变更流程
adb logcat | grep -E "power policy|PowerPolicy|CAR.AUDIO|CAR.MEDIA|AHAL_Power|silentmode|carpowerpolicyd"
# 精确定位 CPMS 策略分发
adb logcat -s CarPowerManagementService:I
# 观察 CPPD native 侧
adb logcat -s carpowerpolicyd:D
11.3 Dump 当前状态
bash
# CarService 完整 dump
adb shell dumpsys car_service --services CarPowerManagementService
# 输出包含:
# - mCurrentPowerPolicyId
# - mCurrentPowerPolicyGroupId
# - 已注册 Listener 数量
# - PowerComponentHandler 各组件当前状态
# - SilentModeHandler 状态
bash
# CPPD dump
adb shell dumpsys android.frameworks.automotive.powerpolicy.ICarPowerPolicyServer/default
# 输出包含:
# - Current power policy
# - Registered callbacks (pid, filter)
# - Component states (accumulated)
11.4 区分 Listener 调用顺序
如需精确定位 Java Listener 的调用先后,可以在以下位置添加带时间戳的日志:
java
// CarAudioPowerListener.java - onPolicyChanged 回调入口
Slogf.i(TAG, "onPolicyChanged: uptimeMs=%d, tid=%d, AUDIO enabled=%b",
SystemClock.uptimeMillis(), Thread.currentThread().getId(),
accumulatedPolicy.isComponentEnabled(AUDIO));
// CarMediaService.java - onPolicyChanged 回调入口
Slogf.i(TAG, "onPolicyChanged: uptimeMs=%d, tid=%d, MEDIA enabled=%b",
SystemClock.uptimeMillis(), Thread.currentThread().getId(),
accumulatedPolicy.isComponentEnabled(PowerComponent.MEDIA));
注意:由于 notifyPowerPolicyChangeToListeners() 在 mBroadcastHandler 线程中执行,所有 Java Listener 回调在同一线程 (同一 tid)上顺序执行 (非并行),先后完全由 while(idx--) 的遍历顺序决定。
12. 关键源码文件索引
Java 侧(CarService)
| 文件 | 路径 | 说明 |
|---|---|---|
| CarPowerManagementService | packages/services/Car/service/.../power/CarPowerManagementService.java |
核心状态机与策略管理 |
| PolicyReader | packages/services/Car/service/.../power/PolicyReader.java |
策略定义与解析 |
| PowerComponentHandler | packages/services/Car/service/.../power/PowerComponentHandler.java |
Java 侧组件状态管理 |
| SilentModeHandler | packages/services/Car/service/.../power/SilentModeHandler.java |
静默模式处理 |
| PowerHalService | packages/services/Car/service/.../hal/PowerHalService.java |
VHAL 电源事件桥梁 |
| ICarImpl | packages/services/Car/service/.../ICarImpl.java |
Service 创建与初始化顺序 |
| CarAudioPowerListener | packages/services/Car/service/.../audio/CarAudioPowerListener.java |
Audio 策略 Listener |
| CarAudioService | packages/services/Car/service/.../audio/CarAudioService.java |
Audio 服务 |
| CarMediaService | packages/services/Car/service/.../CarMediaService.java |
Media 服务与策略 Listener |
Native 侧(CPPD)
| 文件 | 路径 | 说明 |
|---|---|---|
| CarPowerPolicyServer | packages/services/Car/cpp/powerpolicy/server/src/CarPowerPolicyServer.cpp/.h |
CPPD 主服务 |
| PolicyManager | packages/services/Car/cpp/powerpolicy/server/src/PolicyManager.cpp/.h |
策略解析与管理 |
| PowerComponentHandler | packages/services/Car/cpp/powerpolicy/server/src/PowerComponentHandler.cpp/.h |
Native 侧组件状态 |
| SilentModeHandler | packages/services/Car/cpp/powerpolicy/server/src/SilentModeHandler.cpp/.h |
sysfs 静默模式监控 |
| PowerPolicyClientBase | packages/services/Car/cpp/powerpolicy/client/include/PowerPolicyClientBase.h |
Native 客户端基类 |
Framework 基础设施
| 文件 | 路径 | 说明 |
|---|---|---|
| RemoteCallbackList | frameworks/base/core/java/android/os/RemoteCallbackList.java |
Listener 管理基类 |
| ArrayMap | frameworks/base/core/java/android/util/ArrayMap.java |
hashCode 排序的 Map |
| ICarPowerPolicyListener.aidl | packages/services/Car/car-lib/.../power/ICarPowerPolicyListener.aidl |
oneway 回调接口 |
ART 运行时
| 文件 | 路径 | 说明 |
|---|---|---|
| object.cc | art/runtime/mirror/object.cc |
GenerateIdentityHashCode() - LCG 算法 |