01 · 总览与使用方

源码:base/settingsVehicleLib/src/main/java/com/android/car/settings/miauto/vehicle/SettingsCarPropertyManager.kt

1. 职责定位

SettingsCarPropertyManager(下称 SCPM)是「业务 Controller」与「AOSP 车服务」之间的中间层,提供:

  • 类型安全的读写getInt/Float/Boolean/IntArray/String/ByteArray 等包装
  • 本地缓存:减少跨进程调用
  • 生命周期托管:绑定 Lifecycle,页面销毁自动 release
  • 超时监控:下发信号后等待车端回弹,超时/校验失败回调业务层
  • 统一事件分发:AOSP 回调 → 缓存 → 超时处理 → 业务层通知
  • 调试辅助setHolderName 日志定位、mockError/mockTimeout 本地模拟

架构分层

graph TD
    A["业务 Controller<br/>CarPropertyMgrPreferenceController"]
    B["SettingsCarPropertyManager<br/>(per-Controller 实例)"]
    C["VehicleControlManager<br/>屏蔽 dcd/xcd 平台差异"]
    D["CarPropertyCacheManager<br/>单例:回调分发+缓存"]
    E["AOSP CarPropertyManager"]
    F["车端 VHAL / MCU"]

    A -->|"setCarManagerCallback<br/>registerPropertyCallback"| B
    B -->|"getProperty / setXxxProperty"| C
    C --> D
    D --> E
    E <-->|"binder / VHAL"| F

    F -.->|"onChangeEvent 回弹"| D
    D -.-> B
    B -.->|"onPropertyChanged"| A

2. 核心能力与 API 清单

职责关键方法行号
生命周期constructor(ctx, lifecycle) / release() / setAutoReleaseUnderLifecycle()69 / 216 / 138
读(带缓存)getIntProperty / getFloatProperty / getBooleanProperty / getIntArrayProperty / getStringProperty / getByteArrayProperty / getProperty<T>331-378
读(不缓存)getPropertyWithoutCache<T> / getIntPropertyWithoutCache340 / 381
setCarProperty / setCarPropertyBySync / setCarPropertyWithoutDelayCheck / setCarProperty(VehicleData)423 / 408 / 482 / 416
可用性isPropertyAvailable / isConnected / filterSupportedProperties326 / 234 / 321
监听注册registerPropertyCallback(ArraySet<Int>) / unregisterPropertyCallback / retryRegisterPropertyCallback237 / 265 / 284
超时isInHMITriggerWaitingDuration / configPropertyRate564 / 257
调试setHolderName / mockErrorEvent / mockTimeoutEvent79 / 616 / 635

3. 使用方分析(82 个引用文件)

3.1 按模块分布

模块文件数
settingsPage/*(各设置页)62
base/*(基础库)19
app/*1

3.2 settingsPage 子模块 TOP 8

子模块数量典型业务
micarDrivingSettings30驾驶模式、能量回收、悬挂等
micarSafetyServiceSettings6安全服务
micarChargeSettings5充电设置
micarLockSettings4门锁、锁车
VehicleBodyControl3车身控制(门/窗/后备箱)
settingsSystem3系统设置
settingsAutoPilot3自动驾驶
micarDisplaySettings3显示

3.3 最常调用的方法(按调用点频次)

方法调用次数用途
getIntProperty(propId, areaId, default)504+整型信号读取(绝对主力)
getProperty<T>(propId, areaId)253+通用读取
isPropertyAvailable(propId, areaId)205+判断可用性
isConnected()130+Car 服务连接检查
setCarProperty(propId, value, areaId, isSync)96+写信号
release()54+释放
registerPropertyCallback(ids)22+注册监听
getFloatProperty(propId, areaId)18+浮点读取

读远多于写(504 vs 96),符合「设置页主要是查询并展示车端状态」的特征。

4. 实例化方式

不是单例,每个 Controller 各 new 一个实例:

// 方式 1:直接创建(最常见,推荐带 lifecycle)
mCarPropertyManager = SettingsCarPropertyManager(context, lifecycle)
 
// 方式 2:不带 lifecycle(已标记 @Deprecated,不推荐)
SettingsCarPropertyManager(context)
 
// 方式 3:全局共享实例(不属于具体页面时用)
GlobalCarPropertyManager.getCarManager()

包装它的基类 / 工厂

作用
CarPropertyMgrPreferenceController<V>所有「需要读写车信号」的 Controller 抽象基类,实现 CarPropertyManagerCallback,内部 new 出 SCPM 并绑 Fragment 生命周期
BaseCarPropertyControllerlazy 初始化 SCPM
BaseVehicleTabPreferenceControllerTab 选择控制器基类
GlobalCarPropertyManager(object)全局单例包装(SoftReference),供非页面的逻辑(如 CarConfigManager)读信号

5. 典型使用模板

class XxxDoorController(...) : CarPropertyMgrPreferenceController<XxxPreference>(...) {
 
    override fun onCreateInternal() {
        // 1. 基类已 new 出 mCarPropertyManager 并绑生命周期
        mCarPropertyManager.setHolderName("XxxDoorController")   // 日志定位
 
        // 2. 注册业务回调
        mCarPropertyManager.setCarManagerCallback(object : CarPropertyManagerCallback {
            override fun onPropertyManagerPrepared() {
                // Car 服务连上了 → 注册关心的信号
                mCarPropertyManager.registerPropertyCallback(arraySetOf(PROP_DOOR_STATE))
                refreshUi()
            }
            override fun onPropertyChanged(v: CarPropertyValue<*>) {
                if (v.propertyId == PROP_DOOR_STATE) refreshUi()  // 车端回弹刷新
            }
            override fun onSetPropertyTimeout(propId: Int, areaId: Int) {
                showToast("设置失败,请重试")
            }
            // ... 其他回调
        })
    }
 
    override fun handlePreferenceChanged(preference, value: Any) {
        // 3. 用户操作 → 下发信号(同步,带超时监控)
        mCarPropertyManager.setCarPropertyBySync(PROP_DOOR_LOCK, if (value) 1 else 0)
    }
 
    private fun refreshUi() {
        val doorOpen = mCarPropertyManager.getIntProperty(PROP_DOOR_STATE) == 1
        // ... 更新 UI
    }
}

三个易踩的坑(来自 docs/05-车辆接口层与IPC.md 总结)

  1. 不要在构造函数拿 Car 实例——Controller 构造时 CarService 多半没 ready。Car 实例要在 onPropertyManagerPrepared 回调里用。
  2. 不要绕过 SCPM 直接调 AOSP——会丢失缓存/超时/异常兜底。
  3. registerPropertyCallback 要在 onPropertyManagerPrepared 之后调——否则服务没连上注册会失败。

6. 与 AOSP Car 的关系

SCPM 完全依赖 AOSP Car API,无 protobuf / 自定义 IPC 中间层(信号层)。证据:

import android.car.Car
import android.car.hardware.CarPropertyValue
import android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback

底层调用最终落到 AOSP:mCarPropMgr.getProperty(propId, areaId)CarPropertyManager.getProperty(...)getCarInstance()LocalCarManager.getInstance().getCar()


下一篇:02-依赖关系图.md