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> / getIntPropertyWithoutCache | 340 / 381 |
| 写 | setCarProperty / setCarPropertyBySync / setCarPropertyWithoutDelayCheck / setCarProperty(VehicleData) | 423 / 408 / 482 / 416 |
| 可用性 | isPropertyAvailable / isConnected / filterSupportedProperties | 326 / 234 / 321 |
| 监听注册 | registerPropertyCallback(ArraySet<Int>) / unregisterPropertyCallback / retryRegisterPropertyCallback | 237 / 265 / 284 |
| 超时 | isInHMITriggerWaitingDuration / configPropertyRate | 564 / 257 |
| 调试 | setHolderName / mockErrorEvent / mockTimeoutEvent | 79 / 616 / 635 |
3. 使用方分析(82 个引用文件)
3.1 按模块分布
| 模块 | 文件数 |
|---|---|
settingsPage/*(各设置页) | 62 |
base/*(基础库) | 19 |
app/* | 1 |
3.2 settingsPage 子模块 TOP 8
| 子模块 | 数量 | 典型业务 |
|---|---|---|
micarDrivingSettings | 30 | 驾驶模式、能量回收、悬挂等 |
micarSafetyServiceSettings | 6 | 安全服务 |
micarChargeSettings | 5 | 充电设置 |
micarLockSettings | 4 | 门锁、锁车 |
VehicleBodyControl | 3 | 车身控制(门/窗/后备箱) |
settingsSystem | 3 | 系统设置 |
settingsAutoPilot | 3 | 自动驾驶 |
micarDisplaySettings | 3 | 显示 |
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 生命周期 |
BaseCarPropertyController | lazy 初始化 SCPM |
BaseVehicleTabPreferenceController | Tab 选择控制器基类 |
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 总结)
- 不要在构造函数拿 Car 实例——Controller 构造时 CarService 多半没 ready。Car 实例要在
onPropertyManagerPrepared回调里用。 - 不要绕过 SCPM 直接调 AOSP——会丢失缓存/超时/异常兜底。
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