03 · 读写信号全链路时序图
源码:
SettingsCarPropertyManager.kt+VehicleControlManager.java+CarPropertyCacheManager.java
1. 读信号全链路(以 getIntProperty 为例)
sequenceDiagram autonumber participant Ctrl as 业务Controller participant SCPM as SettingsCarPropertyManager participant Cache as mPropertiesCache participant VCM as VehicleControlManager participant CPCM as CarPropertyCacheManager participant AOSP as AOSP CarPropertyManager participant Car as 车端 Ctrl->>SCPM: getIntProperty(propId, areaId, default)<br/>[:331] SCPM->>SCPM: getProperty Int(propId, areaId)<br/>[:371] SCPM->>Cache: getCachedProp(propId, areaId)<br/>key = propId#areaId [:580] alt 缓存命中 Cache-->>SCPM: CarPropertyValue SCPM-->>Ctrl: .value ?: default else 缓存未命中 SCPM->>SCPM: remoteGetProperty(propId, areaId) [:391] SCPM->>SCPM: 检查 isConnected() [:392] alt 未连接 SCPM-->>Ctrl: null (返回 default) else 已连接 SCPM->>VCM: getProperty(propId, areaId) [:395] VCM->>CPCM: 取值(命中缓存直接返回) CPCM->>AOSP: getProperty(propId, areaId) AOSP->>Car: 读取信号 Car-->>AOSP: CarPropertyValue AOSP-->>VCM: CarPropertyValue VCM-->>SCPM: CarPropertyValue SCPM->>Cache: cachePropVal(value) [:397] Note over Cache: 首次缓存可注入<br/>getPropValueForFirstCache 终态值 SCPM->>SCPM: propId 是否在 observedSet? [:398] opt 不在观察集合(隐式注册) SCPM->>VCM: registerPropertyCallback(dispatcher, propId) [:400] VCM->>CPCM: registerPropertyCallback(cb, propId) CPCM->>AOSP: registerCallback(internalCb, propId) SCPM->>SCPM: mNoNeedObservedPropertyIdSet.add(propId) [:402] end SCPM-->>Ctrl: .value ?: default end end
要点
- 缓存优先:
getProperty先查mPropertiesCache(key=propId#areaId),命中直接返回,不走 binder。 - 不缓存读:
getPropertyWithoutCache强制走remoteGetProperty,绕过缓存(适合需要实时值的场景,如CarConfigManager)。 - 隐式注册:
remoteGetProperty拿到值后,若 propId 不在mObservedPropertyIdSet,会自动注册底层回调并记到mNoNeedObservedPropertyIdSet——意思是”你 get 过一次,后续变化就会被通知”。这会随release()/unregisterPropertyCallback一起清理。
2. 写信号全链路(以 setCarPropertyBySync 为例)
sequenceDiagram autonumber participant Ctrl as 业务Controller participant SCPM as SettingsCarPropertyManager participant VCM as VehicleControlManager participant AOSP as AOSP CarPropertyManager participant Car as 车端 participant Handler as mTimeoutHandler participant Cb as SettingsCarPropertyEventCallback participant Cache as mPropertiesCache Ctrl->>SCPM: setCarPropertyBySync(propId, value, areaId) [:408] SCPM->>SCPM: setCarProperty(propId, val, areaId, isSync=true) [:413/423] SCPM->>SCPM: reportOneTrackWhenSetProperty(...) 埋点 [:429] SCPM->>SCPM: 检查 isConnected() [:430] alt 未连接 SCPM->>SCPM: 打 w 日志后 return [:431] else 已连接 SCPM->>SCPM: mNoNeedObservedPropertyIdSet.add(propId) [:435] SCPM->>SCPM: 按 propVal 类型分发 [:438-474] alt Int SCPM->>VCM: setIntPropertyBySync(propId, val, areaId) [:440] else Float SCPM->>VCM: setFloatPropertyBySync(propId, val, areaId) [:445] else Int 数组 SCPM->>VCM: setIntArrayPropertyBySync(...) [:452] else List (BATCH_PROP 批量) SCPM->>VCM: setBatchPropertyBySync(list) [:466] else 其他类型 SCPM->>SCPM: typeSupport=false, 打 e 日志 [:478] end VCM->>AOSP: setProperty(...) (异步线程 ThreadPoolUtils.ASYNC) AOSP->>Car: 下发控制指令 SCPM->>SCPM: startTimeOutMonitor(propId, val, areaId) [:476] opt BATCH_PROP SCPM->>SCPM: 遍历集合逐个 startTimeOutMonitorReal [:531-535] end SCPM->>SCPM: startTimeOutMonitorReal [:541] Note over SCPM: 取 timeoutPropId / timeoutValue<br/>仅对 observedSet 内的 propId 计时<br/>TIMEOUT_IGNORE 跳过 [:546-553] SCPM->>Handler: sendMessageDelayed(msgId, timeout) [:557] Note over Handler: msgId = (propId#areaId).hashCode() Car-->>AOSP: 车端回弹 AOSP-->>Cb: onChangeEvent(value) Cb->>Cb: mockError? / mockTimeout? 拦截 [:664-672] Cb->>Cache: cachePropVal(value) [:673] Cb->>Cb: processTimeout(value, getTimeoutFlag) [:674] alt CONTINUE Note over Cb: 继续等待,不动计时 else RESTART Cb->>Handler: 重启计时 [:167-177] else REMOVE(默认) Cb->>Handler: removeMessages(msgId) [:181-186] end Cb->>Cb: propId 是否在 observedSet? [:675] alt 在观察集合 Cb-->>Ctrl: onPropertyChanged(value) [:680] else 不在 Note over Cb: 打 w 日志,不上抛 [:682] end end
超时触发分支(回弹没在窗口内到达)
sequenceDiagram Handler->>Handler: 延时到期 handleMessage [:150] Handler->>Handler: handlePropertyTimeout(propId, areaId, propVal) [:191] Handler-->>Ctrl: mCallback.onSetPropertyTimeout(propId, areaId) [:194] Handler->>Cache: 取下发时缓存值 vs 当前缓存值 [:196] alt 下发值 != 缓存值 Handler-->>Ctrl: mCallback.onDataVerifyFailed(propId, areaId, propVal) [:199] Note over Handler: 数据校验失败:车端最终态与下发不一致 end
3. setCarProperty vs setCarPropertyWithoutDelayCheck
两者代码高度相似,关键差异:
| 特性 | setCarProperty (423) | setCarPropertyWithoutDelayCheck (482) |
|---|---|---|
| 超时监控 | ✅ 调 startTimeOutMonitor (476) | ❌ 不调,无超时检测 |
| 类型校验 | ✅ typeSupport 校验,不支持打 e 日志 (475) | ❌ 无校验,静默跳过不支持的类型 |
| 埋点 | ✅ | ✅ |
| 连接检查 | ✅ | ✅ |
| 自动注册 observedSet | ✅ | ✅ |
| 类型分发 | Int/Float/Array/List | Int/Float/Array/List |
选用建议:
- 大多数控制信号用
setCarProperty/setCarPropertyBySync——需要回弹确认,超时能提示用户”操作未生效”。 - 只读状态查询、或不需要确认的指令用
setCarPropertyWithoutDelayCheck。
4. 关键文件位置
| 文件 | 路径 |
|---|---|
| SettingsCarPropertyManager | base/settingsVehicleLib/.../vehicle/SettingsCarPropertyManager.kt |
| VehicleControlManager | base/settingsVehicleLib/.../vehicle/VehicleControlManager.java |
| CarPropertyCacheManager | base/settingsVehicleLib/.../vehicle/CarPropertyCacheManager.java |
| NewBaseCarServiceManager | base/settingsVehicleLib/.../vehicle/NewBaseCarServiceManager.java |
| LocalCarManager | base/settingsVehicleLib/.../vehicle/LocalCarManager.java |
| CarPropertyManagerCallback | base/settingsVehicleLib/.../vehicle/CarPropertyManagerCallback.java |
下一篇:04-超时监控与回调机制.md