Android Automotive Power Policy 全流程技术解析

Android Automotive Power Policy 全流程技术解析

基于 AOSP(Android15 Automotive LTS3) CarService 源码分析,涵盖从硬件信号到应用层回调的完整链路。


目录

  1. 架构总览
  2. 核心参与者
  3. 系统启动与初始化流程
  4. [Power Policy 定义体系](#Power Policy 定义体系 "#4-power-policy-%E5%AE%9A%E4%B9%89%E4%BD%93%E7%B3%BB")
  5. [电源状态机(CPMS State Machine)](#电源状态机(CPMS State Machine) "#5-%E7%94%B5%E6%BA%90%E7%8A%B6%E6%80%81%E6%9C%BAcpms-state-machine")
  6. [Policy 应用全流程](#Policy 应用全流程 "#6-policy-%E5%BA%94%E7%94%A8%E5%85%A8%E6%B5%81%E7%A8%8B")
  7. [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")
  8. [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")
  9. [Silent Mode 机制](#Silent Mode 机制 "#9-silent-mode-%E6%9C%BA%E5%88%B6")
  10. 典型场景全链路分析
  11. 调试与验证方法
  12. 关键源码文件索引

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 通知是异步的(oneway AIDL),不保证严格时序

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_REQPOWER_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 策略来源

电源策略有三个来源,优先级依次降低:

  1. 系统内置策略 :硬编码在 PolicyReader.javaPolicyManager.cpp
  2. Vendor XML 配置/vendor/etc/automotive/power_policy.xml
  3. 运行时动态注册 :通过 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>ArrayMapput() 方法通过二分查找将元素按 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(恢复)时------涉及两个不同的策略:

  1. system_power_policy_initial_on :只启用 AUDIO, DISPLAY, CPU(不包含 MEDIA)
    • isComponentChanged 检查:只有 AUDIO Listener 匹配 → 只通知 CarAudioPowerListener
  2. 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),不是执行队列。有三个层面保证了它的顺序无意义:

  1. PolicyReader :数组只构建 CarPowerPolicy 对象的 enabled/disabled int 数组
  2. CPPD PowerComponentHandler :使用 std::unordered_map 汇总后写回 vector,顺序被打乱
  3. 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_onall_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 算法
相关推荐
aykon2 小时前
android 扫码优化方案
android
墨狂之逸才2 小时前
Android TV 智能看板开发踩坑指南:WebView 常见问题与解决方
android
林栩link2 小时前
Now in Android 现代应用开发实践(三):架构设计(UI)
android·android jetpack
Coolmuster_cn2 小时前
永久擦除您的 Android
android
我命由我123452 小时前
Android 开发 - UriMatcher(一个 URI 分类器)
android·java·java-ee·kotlin·android studio·android-studio·android runtime
阿拉斯攀登2 小时前
第 13 篇 输入设备驱动(触摸屏 / 按键)开发详解,Linux input 子系统全解析
android·linux·运维·驱动开发·rk3568·瑞芯微·rk安卓驱动
学习3人组3 小时前
Workerman实现 WSS 基于客户端 ID 的精准推送
android·java·开发语言
阿拉斯攀登3 小时前
第 11 篇 RK 平台安卓驱动实战 4:I2C 设备驱动开发,以 OLED 屏为例
android·驱动开发·i2c·瑞芯微·嵌入式驱动·rk3576·嵌入式安卓
段娇娇3 小时前
Android jetpack LiveData (二) 原理篇
android·android jetpack