1 概述
本篇重要讲解VehicleHal的重要运行流程,包括设置属性、获取属性、订阅属性、取消订阅、持续上报属性订阅等。
2 获取属性流程
2.1 获取属性流程源码分析
作为服务注册到hwServiceManager中的类是VehicleHalManager,所以,CarService对服务端的调用的hidl接口都是调用到了VehicleHalManager中。
- get(VehiclePropValue requestedPropValue)
- generates (StatusCode status, VehiclePropValue propValue);
复制代码 IVehicle这个hidl接口中的界说如上
- Return<void> VehicleHalManager::get(const VehiclePropValue& requestedPropValue, get_cb _hidl_cb) {
- const auto* config = getPropConfigOrNull(requestedPropValue.prop);
- if (config == nullptr) {
- ALOGE("Failed to get value: config not found, property: 0x%x",
- requestedPropValue.prop);
- _hidl_cb(StatusCode::INVALID_ARG, kEmptyValue);
- return Void();
- }
- if (!checkReadPermission(*config)) {
- _hidl_cb(StatusCode::ACCESS_DENIED, kEmptyValue);
- return Void();
- }
- StatusCode status;
- auto value = mHal->get(requestedPropValue, &status);
- _hidl_cb(status, value.get() ? *value : kEmptyValue);
- return Void();
- }
复制代码 调用之后会调用到VehicleHalManager中的get函数
- const VehiclePropConfig* VehicleHalManager::getPropConfigOrNull(
- int32_t prop) const {
- return mConfigIndex->hasConfig(prop)
- ? &mConfigIndex->getConfig(prop) : nullptr;
- }
复制代码 起首,会从属性设置列表中是否存在这个属性,这个是初始化的时候缓存的,缓存的是所有的属性设置。
如果获取的属性不在属性设置列表中,则不能够获取,如果存在,会判断访问权限,访问权限校验通过之后,会调用mHal的get函数。
- VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get(
- const VehiclePropValue& requestedPropValue, StatusCode* outStatus) {
- auto propId = requestedPropValue.prop;
- ALOGV("get(%d)", propId);
- auto& pool = *getValuePool();
- VehiclePropValuePtr v = nullptr;
- switch (propId) {
- case OBD2_FREEZE_FRAME:
- v = pool.obtainComplex();
- *outStatus = fillObd2FreezeFrame(requestedPropValue, v.get());
- break;
- case OBD2_FREEZE_FRAME_INFO:
- v = pool.obtainComplex();
- *outStatus = fillObd2DtcInfo(v.get());
- break;
- default:
- if (mEmulatedUserHal != nullptr && mEmulatedUserHal->isSupported(propId)) {
- ALOGI("get(): getting value for prop %d from User HAL", propId);
- const auto& ret = mEmulatedUserHal->onGetProperty(requestedPropValue);
- if (!ret.ok()) {
- ALOGE("get(): User HAL returned error: %s", ret.error().message().c_str());
- *outStatus = StatusCode(ret.error().code());
- } else {
- auto value = ret.value().get();
- if (value != nullptr) {
- ALOGI("get(): User HAL returned value: %s", toString(*value).c_str());
- v = getValuePool()->obtain(*value);
- *outStatus = StatusCode::OK;
- } else {
- ALOGE("get(): User HAL returned null value");
- *outStatus = StatusCode::INTERNAL_ERROR;
- }
- }
- break;
- }
- auto internalPropValue = mPropStore->readValueOrNull(requestedPropValue);
- if (internalPropValue != nullptr) {
- v = getValuePool()->obtain(*internalPropValue);
- }
- *outStatus = v != nullptr ? StatusCode::OK : StatusCode::INVALID_ARG;
- break;
- }
- if (v.get()) {
- v->timestamp = elapsedRealtimeNano();
- }
- return v;
- }
复制代码 起首,会对userhal的一些判断操作,这个EmulatedUserHal是跟用户身份相关的hal界说,用于处置惩罚用户切换相关事件。如果是用户hal相关的prop获取,则获取完成之后就直接跳出。如果不是,则走普通的property获取路径,从VehiclePropertyStore中读取。
- using PropertyMap = std::map<RecordId, VehiclePropValue>;
- PropertyMap mPropertyValues;
- std::unique_ptr<VehiclePropValue> VehiclePropertyStore::readValueOrNull(
- int32_t prop, int32_t area, int64_t token) const {
- RecordId recId = {prop, isGlobalProp(prop) ? 0 : area, token };
- MuxGuard g(mLock);
- const VehiclePropValue* internalValue = getValueOrNullLocked(recId);
- return internalValue ? std::make_unique<VehiclePropValue>(*internalValue) : nullptr;
- }
- const VehiclePropValue* VehiclePropertyStore::getValueOrNullLocked(
- const VehiclePropertyStore::RecordId& recId) const {
- auto it = mPropertyValues.find(recId);
- return it == mPropertyValues.end() ? nullptr : &it->second;
- }
复制代码 从mPropertyValues这个map中去获取对应propId的property。mPropertyValues内里的值是在哪添补的呢?
- bool VehiclePropertyStore::writeValue(const VehiclePropValue& propValue,
- bool updateStatus) {
- MuxGuard g(mLock);
- if (!mConfigs.count(propValue.prop)) return false;
- RecordId recId = getRecordIdLocked(propValue);
- VehiclePropValue* valueToUpdate = const_cast<VehiclePropValue*>(getValueOrNullLocked(recId));
- if (valueToUpdate == nullptr) {
- mPropertyValues.insert({ recId, propValue });
- return true;
- }
- // propValue is outdated and drops it.
- if (valueToUpdate->timestamp > propValue.timestamp) {
- return false;
- }
- // update the propertyValue.
- // The timestamp in propertyStore should only be updated by the server side. It indicates
- // the time when the event is generated by the server.
- valueToUpdate->timestamp = propValue.timestamp;
- valueToUpdate->value = propValue.value;
- if (updateStatus) {
- valueToUpdate->status = propValue.status;
- }
- return true;
- }
复制代码 是在这个函数中,这个函数是在VHAL初始化的时候调用的,初始化的时候,会遍历一个界说了所有支持属性的列表,并调用writeValue函数将属性设置和属性值缓存到VehiclePropertyStore中。
以上就是CarService从VHAL获取属性的流程,总结来说就是:从VHAL的缓存map中获取属性。
2.2 获取属性流程图
plantuml
- @startuml
- participant CarService
- box
- participant VehicleHalManager
- participant EmulatedVehicleHal
- participant VehiclePropertyStore
- endbox
- CarService -> VehicleHalManager: get(const VehiclePropValue& \n\trequestedPropValue, get_cb _hidl_cb)
- VehicleHalManager -> EmulatedVehicleHal: get(const VehiclePropValue& \n\trequestedPropValue, get_cb _hidl_cb)
- EmulatedVehicleHal -> VehiclePropertyStore: readValueOrNull(int32_t prop, \n\tint32_t area, int64_t token)
- VehiclePropertyStore -> EmulatedVehicleHal: propValue
- EmulatedVehicleHal -> VehicleHalManager: propValue
- VehicleHalManager -> CarService: _hidl_cb(propValue)
- @enduml
复制代码
3 设置属性流程
3.1 设置属性流程源码分析
hidl调用后照旧从VehicleHalManager开始的
- Return<StatusCode> VehicleHalManager::set(const VehiclePropValue &value) {
- auto prop = value.prop;
- const auto* config = getPropConfigOrNull(prop);
- if (config == nullptr) {
- ALOGE("Failed to set value: config not found, property: 0x%x", prop);
- return StatusCode::INVALID_ARG;
- }
- if (!checkWritePermission(*config)) {
- return StatusCode::ACCESS_DENIED;
- }
- handlePropertySetEvent(value);
- auto status = mHal->set(value);
- return Return<StatusCode>(status);
- }
复制代码 起首判断缓存中是否有该属性的属性设置,有才支持后续的set操作
handlePropertySetEvent是对带有EVENTS_FROM_ANDROID这个订阅标签属性的处置惩罚,这种属性的设置必要直接上报给上层。
然后是调用EmulatedVehicleHal的set函数
- StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) {
- constexpr bool updateStatus = false;
- //这里是模拟车辆属性
- if (propValue.prop == kGenerateFakeDataControllingProperty) {
- // Send the generator controlling request to the server.
- // 'updateStatus' flag is only for the value sent by setProperty (propValue in this case)
- // instead of the generated values triggered by it. 'propValue' works as a control signal
- // here, since we never send the control signal back, the value of 'updateStatus' flag
- // does not matter here.
- auto status = mVehicleClient->setProperty(propValue, updateStatus);
- return status;
- //处理空调相关的属性
- } else if (mHvacPowerProps.count(propValue.prop)) {
- auto hvacPowerOn = mPropStore->readValueOrNull(
- toInt(VehicleProperty::HVAC_POWER_ON),
- (VehicleAreaSeat::ROW_1_LEFT | VehicleAreaSeat::ROW_1_RIGHT |
- VehicleAreaSeat::ROW_2_LEFT | VehicleAreaSeat::ROW_2_CENTER |
- VehicleAreaSeat::ROW_2_RIGHT));
- if (hvacPowerOn && hvacPowerOn->value.int32Values.size() == 1
- && hvacPowerOn->value.int32Values[0] == 0) {
- return StatusCode::NOT_AVAILABLE;
- }
- } else {
- // Handle property specific code
- switch (propValue.prop) {
- case OBD2_FREEZE_FRAME_CLEAR:
- return clearObd2FreezeFrames(propValue);
- case VEHICLE_MAP_SERVICE:
- // Placeholder for future implementation of VMS property in the default hal. For
- // now, just returns OK; otherwise, hal clients crash with property not supported.
- return StatusCode::OK;
- }
- }
- if (propValue.status != VehiclePropertyStatus::AVAILABLE) {
- // Android side cannot set property status - this value is the
- // purview of the HAL implementation to reflect the state of
- // its underlying hardware
- return StatusCode::INVALID_ARG;
- }
- //读取当前值
- auto currentPropValue = mPropStore->readValueOrNull(propValue);
- if (currentPropValue == nullptr) {
- return StatusCode::INVALID_ARG;
- }
- if (currentPropValue->status != VehiclePropertyStatus::AVAILABLE) {
- // do not allow Android side to set() a disabled/error property
- return StatusCode::NOT_AVAILABLE;
- }
- /**
- * After checking all conditions, such as the property is available, a real vhal will
- * sent the events to Car ECU to take actions.
- */
- // Send the value to the vehicle server, the server will talk to the (real or emulated) car
- //设置属性到VehicleClient,通过这个设置到模拟车辆或者实际车辆
- auto setValueStatus = mVehicleClient->setProperty(propValue, updateStatus);
- if (setValueStatus != StatusCode::OK) {
- return setValueStatus;
- }
- return StatusCode::OK;
- }
复制代码 其中mVehicleClient是初始化时传入的EmulatedVehicleConnector对象,所以调用的是EmulatedVehicleConnector的setProperty函数。
- StatusCode setProperty(const VehiclePropValue& value, bool updateStatus) override {
- return this->onSetProperty(value, updateStatus);
- }
复制代码 setProperty函数在EmulatedVehicleConnector的父类IPassThroughConnector中,然后调用onSetProperty函数,这个函数在EmulatedVehicleConnector类中。
- StatusCode EmulatedVehicleConnector::onSetProperty(const VehiclePropValue& value,
- bool updateStatus) {
- if (mEmulatedUserHal.isSupported(value.prop)) {
- LOG(INFO) << "onSetProperty(): property " << value.prop << " will be handled by UserHal";
- const auto& ret = mEmulatedUserHal.onSetProperty(value);
- if (!ret.ok()) {
- LOG(ERROR) << "onSetProperty(): HAL returned error: " << ret.error().message();
- return StatusCode(ret.error().code());
- }
- auto updatedValue = ret.value().get();
- if (updatedValue != nullptr) {
- LOG(INFO) << "onSetProperty(): updating property returned by HAL: "
- << toString(*updatedValue);
- onPropertyValueFromCar(*updatedValue, updateStatus);
- }
- return StatusCode::OK;
- }
- return this->VehicleHalServer::onSetProperty(value, updateStatus);
- }
复制代码 起首处置惩罚UserHal相关的属性操作。然后调用VehicleHalServer中的onSetProperty函数。
- StatusCode VehicleHalServer::onSetProperty(const VehiclePropValue& value, bool updateStatus) {
- LOG(DEBUG) << "onSetProperty(" << value.prop << ")";
- // Some properties need to be treated non-trivially
- switch (value.prop) {
- case kGenerateFakeDataControllingProperty:
- return handleGenerateFakeDataRequest(value);
- // set the value from vehicle side, used in end to end test.
- case kSetIntPropertyFromVehicleForTest: {
- auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::INT32, 1);
- updatedPropValue->prop = value.value.int32Values[0];
- updatedPropValue->value.int32Values[0] = value.value.int32Values[1];
- updatedPropValue->timestamp = value.value.int64Values[0];
- updatedPropValue->areaId = value.areaId;
- onPropertyValueFromCar(*updatedPropValue, updateStatus);
- return StatusCode::OK;
- }
- case kSetFloatPropertyFromVehicleForTest: {
- auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::FLOAT, 1);
- updatedPropValue->prop = value.value.int32Values[0];
- updatedPropValue->value.floatValues[0] = value.value.floatValues[0];
- updatedPropValue->timestamp = value.value.int64Values[0];
- updatedPropValue->areaId = value.areaId;
- onPropertyValueFromCar(*updatedPropValue, updateStatus);
- return StatusCode::OK;
- }
- case kSetBooleanPropertyFromVehicleForTest: {
- auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::BOOLEAN, 1);
- updatedPropValue->prop = value.value.int32Values[1];
- updatedPropValue->value.int32Values[0] = value.value.int32Values[0];
- updatedPropValue->timestamp = value.value.int64Values[0];
- updatedPropValue->areaId = value.areaId;
- onPropertyValueFromCar(*updatedPropValue, updateStatus);
- return StatusCode::OK;
- }
- case AP_POWER_STATE_REPORT:
- switch (value.value.int32Values[0]) {
- case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT):
- case toInt(VehicleApPowerStateReport::SHUTDOWN_CANCELLED):
- case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL):
- // CPMS is in WAIT_FOR_VHAL state, simply move to ON
- // Send back to HAL
- // ALWAYS update status for generated property value
- onPropertyValueFromCar(*createApPowerStateReq(VehicleApPowerStateReq::ON, 0),
- true /* updateStatus */);
- break;
- case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY):
- case toInt(VehicleApPowerStateReport::SHUTDOWN_START):
- // CPMS is in WAIT_FOR_FINISH state, send the FINISHED command
- // Send back to HAL
- // ALWAYS update status for generated property value
- onPropertyValueFromCar(
- *createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0),
- true /* updateStatus */);
- break;
- case toInt(VehicleApPowerStateReport::ON):
- case toInt(VehicleApPowerStateReport::SHUTDOWN_POSTPONE):
- case toInt(VehicleApPowerStateReport::SHUTDOWN_PREPARE):
- // Do nothing
- break;
- default:
- // Unknown state
- break;
- }
- break;
- default:
- break;
- }
- // In the real vhal, the value will be sent to Car ECU.
- // We just pretend it is done here and send back to HAL
- auto updatedPropValue = getValuePool()->obtain(value);
- updatedPropValue->timestamp = elapsedRealtimeNano();
- onPropertyValueFromCar(*updatedPropValue, updateStatus);
- return StatusCode::OK;
- }
复制代码 上面是模拟属性设置流程,这里就相当于模拟属性设置完成了。更新属性的值和时间戳之后,调用onPropertyValueFromCar模拟属性设置成功的上报操作
3.2 设置属性流程图
plantuml
- @startuml
- participant CarService
- box
- participant VehicleHalManager
- participant SubscriptionManager
- participant EmulatedVehicleHal
- participant IPassThroughConnector
- participant EmulatedVehicleConnector
- participant VehicleHalServer
- endbox
- CarService -> VehicleHalManager: set(const VehiclePropValue& value)
- VehicleHalManager -> VehicleHalManager: handlePropertySetEvent(const VehiclePropValue& value)
- VehicleHalManager -> SubscriptionManager: getSubscribedClients(int32_t propId, SubscribeFlags flags)
- SubscriptionManager -> VehicleHalManager: value
- alt flags == SubscribeFlags::EVENTS_FROM_ANDROID
- VehicleHalManager -> CarService: onPropertySet(value)
- end
- VehicleHalManager -> EmulatedVehicleHal: set(const VehiclePropValue& value)
- EmulatedVehicleHal -> IPassThroughConnector: setProperty(const VehiclePropValue& \n\tvalue, bool updateStatus)
- IPassThroughConnector -> EmulatedVehicleConnector: onSetProperty(const VehiclePropValue& \n\tvalue, bool updateStatus)
- EmulatedVehicleConnector -> VehicleHalServer: onSetProperty(const VehiclePropValue& value, bool updateStatus)
- @enduml
复制代码 流程图:
这里由于没有实际车辆,没有往下设置,OEM厂商必要设置到ECU中。至于设置之后,VHAL缓存的改变则是由设置成功的通知上报之后才会写入缓存的。
4 订阅属性流程
4.1 普通订阅属性流程源码分析
订阅入口也是在VehicleHalManager中
- Return<StatusCode> VehicleHalManager::subscribe(const sp<IVehicleCallback> &callback,
- const hidl_vec<SubscribeOptions> &options) {
- hidl_vec<SubscribeOptions> verifiedOptions(options);
- for (size_t i = 0; i < verifiedOptions.size(); i++) {
- SubscribeOptions& ops = verifiedOptions[i];
- auto prop = ops.propId;
- const auto* config = getPropConfigOrNull(prop);
- if (config == nullptr) {
- ALOGE("Failed to subscribe: config not found, property: 0x%x",
- prop);
- return StatusCode::INVALID_ARG;
- }
- if (ops.flags == SubscribeFlags::UNDEFINED) {
- ALOGE("Failed to subscribe: undefined flag in options provided");
- return StatusCode::INVALID_ARG;
- }
- if (!isSubscribable(*config, ops.flags)) {
- ALOGE("Failed to subscribe: property 0x%x is not subscribable",
- prop);
- return StatusCode::INVALID_ARG;
- }
- ops.sampleRate = checkSampleRate(*config, ops.sampleRate);
- }
- std::list<SubscribeOptions> updatedOptions;
- auto res = mSubscriptionManager.addOrUpdateSubscription(getClientId(callback),
- callback, verifiedOptions,
- &updatedOptions);
- if (StatusCode::OK != res) {
- ALOGW("%s failed to subscribe, error code: %d", __func__, res);
- return res;
- }
- for (auto opt : updatedOptions) {
- mHal->subscribe(opt.propId, opt.sampleRate);
- }
- return StatusCode::OK;
- }
复制代码 起首判断属性设置是否存在,存在才支持订阅
然后判断是否可以订阅
- bool VehicleHalManager::isSubscribable(const VehiclePropConfig& config,
- SubscribeFlags flags) {
- bool isReadable = config.access & VehiclePropertyAccess::READ;
- if (!isReadable && (SubscribeFlags::EVENTS_FROM_CAR & flags)) {
- ALOGW("Cannot subscribe, property 0x%x is not readable", config.prop);
- return false;
- }
- if (config.changeMode == VehiclePropertyChangeMode::STATIC) {
- ALOGW("Cannot subscribe, property 0x%x is static", config.prop);
- return false;
- }
- return true;
- }
复制代码 判断访问权限,判断flag,如果flag是从car来的,则返回false。然后是判断属性的changeMode,如果changeMode是STATIC,表现属性不变,则不支持订阅。
然后添加订阅addOrUpdateSubscription,添加之前起首创建clientId
- using ClientId = uint64_t;
- ClientId VehicleHalManager::getClientId(const sp<IVehicleCallback>& callback) {
- //TODO(b/32172906): rework this to get some kind of unique id for callback interface when this
- // feature is ready in HIDL.
- if (callback->isRemote()) {
- BpHwVehicleCallback* hwCallback = static_cast<BpHwVehicleCallback*>(callback.get());
- return static_cast<ClientId>(reinterpret_cast<intptr_t>(hwCallback->onAsBinder()));
- } else {
- return static_cast<ClientId>(reinterpret_cast<intptr_t>(callback.get()));
- }
- }
复制代码 根据传入的回调函数的额指针来强转成ClientId这种int范例,作为客户端的唯一标识。
- StatusCode SubscriptionManager::addOrUpdateSubscription(
- ClientId clientId,
- const sp<IVehicleCallback> &callback,
- const hidl_vec<SubscribeOptions> &optionList,
- std::list<SubscribeOptions>* outUpdatedSubscriptions) {
- outUpdatedSubscriptions->clear();
- MuxGuard g(mLock);
- ALOGI("SubscriptionManager::addOrUpdateSubscription, callback: %p", callback.get());
- const sp<HalClient>& client = getOrCreateHalClientLocked(clientId, callback);
- if (client.get() == nullptr) {
- return StatusCode::INTERNAL_ERROR;
- }
- for (size_t i = 0; i < optionList.size(); i++) {
- const SubscribeOptions& opts = optionList[i];
- ALOGI("SubscriptionManager::addOrUpdateSubscription, prop: 0x%x", opts.propId);
- client->addOrUpdateSubscription(opts);
- addClientToPropMapLocked(opts.propId, client);
- if (SubscribeFlags::EVENTS_FROM_CAR & opts.flags) {
- SubscribeOptions updated;
- if (updateHalEventSubscriptionLocked(opts, &updated)) {
- outUpdatedSubscriptions->push_back(updated);
- }
- }
- }
- return StatusCode::OK;
- }
复制代码 起首,创建客户端对象HalClient
- std::map<ClientId, sp<HalClient>> mClients;
- sp<HalClient> SubscriptionManager::getOrCreateHalClientLocked(
- ClientId clientId, const sp<IVehicleCallback>& callback) {
- auto it = mClients.find(clientId);
- if (it == mClients.end()) {
- uint64_t cookie = reinterpret_cast<uint64_t>(clientId);
- ALOGI("Creating new client and linking to death recipient, cookie: 0x%" PRIx64, cookie);
- auto res = callback->linkToDeath(mCallbackDeathRecipient, cookie);
- if (!res.isOk()) { // Client is already dead?
- ALOGW("%s failed to link to death, client %p, err: %s",
- __func__, callback.get(), res.description().c_str());
- return nullptr;
- }
- sp<HalClient> client = new HalClient(callback);
- mClients.insert({clientId, client});
- return client;
- } else {
- return it->second;
- }
- }
复制代码 mClients是保存订阅客户端的map,key是ClientId,value是HalClient对象。这里会先判断mClients这个map中是否存在对应的客户端,如果没有,则创建HalClient对象,并到场到这个map之中,如果有则直接返回。
然后for循环遍历所有的订阅项,由于订阅的时候,CarService传入的是SubscribeOptions的列表:
- struct SubscribeOptions {
- /** Property to subscribe */
- int32_t propId;
- /**
- * Sample rate in Hz.
- *
- * Must be provided for properties with
- * VehiclePropertyChangeMode::CONTINUOUS. The value must be within
- * VehiclePropConfig#minSamplingRate .. VehiclePropConfig#maxSamplingRate
- * for a given property.
- * This value indicates how many updates per second client wants to receive.
- */
- float sampleRate;
- /** Flags that indicate to which event sources to listen. */
- SubscribeFlags flags;
- };
复制代码 所以可以一次性订阅多个属性。但是这多个属性是一次订阅,也是走一个回调函数上去的。这里会遍历所有的SubscribeOptions,然后调用addOrUpdateSubscription函数。
- std::map<int32_t, SubscribeOptions> mSubscriptions;
- void HalClient::addOrUpdateSubscription(const SubscribeOptions &opts) {
- ALOGI("%s opts.propId: 0x%x", __func__, opts.propId);
- auto it = mSubscriptions.find(opts.propId);
- if (it == mSubscriptions.end()) {
- mSubscriptions.emplace(opts.propId, opts);
- } else {
- const SubscribeOptions& oldOpts = it->second;
- SubscribeOptions updatedOptions;
- if (mergeSubscribeOptions(oldOpts, opts, &updatedOptions)) {
- mSubscriptions.erase(it);
- mSubscriptions.emplace(opts.propId, updatedOptions);
- }
- }
- }
- bool mergeSubscribeOptions(const SubscribeOptions &oldOpts,
- const SubscribeOptions &newOpts,
- SubscribeOptions *outResult) {
- float updatedRate = std::max(oldOpts.sampleRate, newOpts.sampleRate);
- SubscribeFlags updatedFlags = SubscribeFlags(oldOpts.flags | newOpts.flags);
- bool updated = (updatedRate > oldOpts.sampleRate) || (updatedFlags != oldOpts.flags);
- if (updated) {
- *outResult = oldOpts;
- outResult->sampleRate = updatedRate;
- outResult->flags = updatedFlags;
- }
- return updated;
- }
复制代码 起首判断这个SubscribeOptions中包含的propId是否已经存在于mSubscriptions这个map中,如果存在,则更新flag和采样率和相应的SubscribeOptions对象,如果不存在,则添加。
这个map的key是propId,value是SubscribeOptions。
- std::map<int32_t, sp<HalClientVector>> mPropToClients;
- void SubscriptionManager::addClientToPropMapLocked(
- int32_t propId, const sp<HalClient> &client) {
- auto it = mPropToClients.find(propId);
- sp<HalClientVector> propClients;
- if (it == mPropToClients.end()) {
- propClients = new HalClientVector();
- mPropToClients.insert(std::make_pair(propId, propClients));
- } else {
- propClients = it->second;
- }
- propClients->addOrUpdate(client);
- }
复制代码 mPropToClients是SubscriptionManager类中的一个map,key是propId,value是HalClientVector对象。HalClientVectot中存储的是对于同一个propId订阅的不同HalClient对象。
这里,先判断mPropToClients中是否有对应的propId的HalClientVector,如果没有,则表现这个propId没有客户端订阅过。如果有则将当前的client对象添加到HalClientVector中。
总结一下属性订阅做的事就是:
- 根据传入的callback指针,转换成ClientId,作为客户端标识
- 创建HalClient对象,作为客户端实例,并保存客户端的callback回调
- 缓存所有订阅属性到HalClient对象的mSubscriptions中
- 缓存HalClient到mClients这个map中
- 缓存HalClient到mPropToClients这个map中
4.2 连续范例属性订阅流程源码分析
连续范例属性,订阅之后必要VHAL周期性上报给CarService
连续属性订阅,其他和上面的普通订阅雷同,最后会走到EmulatedVehicleHal中进行处置惩罚
- StatusCode EmulatedVehicleHal::subscribe(int32_t property, float sampleRate) {
- ALOGI("%s propId: 0x%x, sampleRate: %f", __func__, property, sampleRate);
- if (isContinuousProperty(property)) {
- mRecurrentTimer.registerRecurrentEvent(hertzToNanoseconds(sampleRate), property);
- }
- return StatusCode::OK;
- }
- bool EmulatedVehicleHal::isContinuousProperty(int32_t propId) const {
- const VehiclePropConfig* config = mPropStore->getConfigOrNull(propId);
- if (config == nullptr) {
- ALOGW("Config not found for property: 0x%x", propId);
- return false;
- }
- return config->changeMode == VehiclePropertyChangeMode::CONTINUOUS;
- }
复制代码 重要就是通过属性设置的changeMode是否是CONTINUOUS来判断,判断如果还连续属性,调用registerRecurrentEvent
- std::unordered_map<int32_t, RecurrentEvent> mCookieToEventsMap;
- void registerRecurrentEvent(std::chrono::nanoseconds interval, int32_t cookie) {
- TimePoint now = Clock::now();
- // Align event time point among all intervals. Thus if we have two intervals 1ms and 2ms,
- // during every second wake-up both intervals will be triggered.
- TimePoint absoluteTime = now - Nanos(now.time_since_epoch().count() % interval.count());
- {
- std::lock_guard<std::mutex> g(mLock);
- mCookieToEventsMap[cookie] = { interval, cookie, absoluteTime };
- }
- mCond.notify_one();
- }
复制代码 用propId作为key,将定时势件的定时周期,propId,当前转换后时间封装成RecurrentEvent对象,存储到mCookieToEventsMap这个map中,然后通过mCond叫醒线程,至此连续订阅完成,等待特定时间上报。
4.3 订阅流程图
plantuml
- @startuml
- participant CarService
- box
- participant VehicleHalManager
- participant SubscriptionManager
- participant HalClient
- participant HalClientVector
- participant EmulatedVehicleHal
- participant RecurrentTimer
- endbox
- CarService -> VehicleHalManager: subscribe(const sp<IVehicleCallback> &callback, \n\tconst hidl_vec<SubscribeOptions> &options)
- VehicleHalManager -> SubscriptionManager: addOrUpdateSubscription(\n\tClientId clientId, \n\tconst sp<IVehicleCallback> &callback, \n\tconst hidl_vec<SubscribeOptions> &optionList, \n\tstd::list<SubscribeOptions>* outUpdatedSubscriptions)
- SubscriptionManager -> SubscriptionManager: getClientId(const sp<IVehicleCallback>& callback)
- SubscriptionManager -> SubscriptionManager: getOrCreateHalClientLocked(ClientId clientId, \n\tconst sp<IVehicleCallback>& callback)
- alt not in mClients
- SubscriptionManager -> HalClient: new HalClient(const sp<IVehicleCallback> &callback)
- HalClient -> SubscriptionManager: client
- SubscriptionManager -> SubscriptionManager: mClients.insert({clientId, client})
- end
- loop i in optionList.size
- SubscriptionManager -> HalClient: addOrUpdateSubscription(const SubscribeOptions &opts)
- alt not in mSubscriptions
- HalClient -> HalClient: emplace(opts.propId, opts)
- else in mSubscriptions
- HalClient -> HalClient: mergeSubscribeOptions(oldOpts, opts, &updatedOptions)
- HalClient -> HalClient: erase(it)
- HalClient -> HalClient: emplace(opts.propId, opts)
- end
- SubscriptionManager -> SubscriptionManager: addClientToPropMapLocked(opts.propId, client)
- alt not in mPropToClients
- SubscriptionManager -> HalClientVector: new HalClientVector()
- HalClientVector -> SubscriptionManager: propClients
- SubscriptionManager -> SubscriptionManager: mPropToClients.insert(std::make_pair(propId, propClients));
- end
- SubscriptionManager -> SubscriptionManager: propClients->addOrUpdate(client)
- end
- loop opt in updatedOptions
- SubscriptionManager -> EmulatedVehicleHal: subscribe(opt.propId, opt.sampleRate)
- alt isContinuousProperty
- EmulatedVehicleHal -> RecurrentTimer: registerRecurrentEvent(hertzToNanoseconds(sampleRate), property)
- RecurrentTimer -> RecurrentTimer: mCookieToEventsMap[cookie] = \n\t{ interval, cookie, absoluteTime }
- end
- end
- @enduml
复制代码 流程图如下:
5 取消订阅流程
5.1 取消订阅流程源码分析
取消订阅入口也是在VehicleHalManager中
- Return<StatusCode> VehicleHalManager::unsubscribe(const sp<IVehicleCallback>& callback,
- int32_t propId) {
- mSubscriptionManager.unsubscribe(getClientId(callback), propId);
- return StatusCode::OK;
- }
复制代码 根据callback获取ClientId,并转到SubscriptionManager中处置惩罚
- void SubscriptionManager::unsubscribe(ClientId clientId,
- int32_t propId) {
- MuxGuard g(mLock);
- auto propertyClients = getClientsForPropertyLocked(propId);
- auto clientIter = mClients.find(clientId);
- if (clientIter == mClients.end()) {
- ALOGW("Unable to unsubscribe: no callback found, propId: 0x%x", propId);
- } else {
- auto client = clientIter->second;
- if (propertyClients != nullptr) {
- propertyClients->remove(client);
- if (propertyClients->isEmpty()) {
- mPropToClients.erase(propId);
- }
- }
- bool isClientSubscribedToOtherProps = false;
- for (const auto& propClient : mPropToClients) {
- if (propClient.second->indexOf(client) >= 0) {
- isClientSubscribedToOtherProps = true;
- break;
- }
- }
- if (!isClientSubscribedToOtherProps) {
- auto res = client->getCallback()->unlinkToDeath(mCallbackDeathRecipient);
- if (!res.isOk()) {
- ALOGW("%s failed to unlink to death, client: %p, err: %s",
- __func__, client->getCallback().get(), res.description().c_str());
- }
- mClients.erase(clientIter);
- }
- }
- if (propertyClients == nullptr || propertyClients->isEmpty()) {
- mHalEventSubscribeOptions.erase(propId);
- mOnPropertyUnsubscribed(propId);
- }
- }
- sp<HalClientVector> SubscriptionManager::getClientsForPropertyLocked(
- int32_t propId) const {
- auto it = mPropToClients.find(propId);
- return it == mPropToClients.end() ? nullptr : it->second;
- }
复制代码 起首,调用getClientsForPropertyLocked函数,根据propId获取HalClientVector对象。然后从mClients中根据ClientId找到对应的HalClient对象,如果该HalClient存在,则从HalClientVector中移除,如果HalClientVector中是最后一个HalClient,则从mPropToClients中移除这个propId的HalClientVector对象。
如果这个client还订阅了其他propId,则不把这个client从mClients中移除,如果没有订阅其他的propId,则从mClients中移除。
同时,如果这个HalClientVector为空了,则移除mHalEventSubscribeOptions中的对应propId的订阅属性,并调用mOnPropertyUnsubscribed这个回调函数。
- void VehicleHalManager::onAllClientsUnsubscribed(int32_t propertyId) {
- mHal->unsubscribe(propertyId);
- }
- StatusCode EmulatedVehicleHal::unsubscribe(int32_t property) {
- ALOGI("%s propId: 0x%x", __func__, property);
- if (isContinuousProperty(property)) {
- mRecurrentTimer.unregisterRecurrentEvent(property);
- }
- return StatusCode::OK;
- }
- void unregisterRecurrentEvent(int32_t cookie) {
- {
- std::lock_guard<std::mutex> g(mLock);
- mCookieToEventsMap.erase(cookie);
- }
- mCond.notify_one();
- }
复制代码 这个地方就是对连续属性的取消订阅处置惩罚,从mCookieToEventsMap中移除。
5.2 取消订阅流程图
plantuml
- @startuml
- participant CarService
- box
- participant VehicleHalManager
- participant SubscriptionManager
- participant EmulatedVehicleHal
- participant RecurrentTimer
- endbox
- CarService -> VehicleHalManager: unsubscribe(const sp<IVehicleCallback>& callback,\n\t int32_t propId)
- VehicleHalManager -> SubscriptionManager: unsubscribe(getClientId(callback), propId)
- SubscriptionManager -> SubscriptionManager: propertyClients = getClientsForPropertyLocked(propId)
- alt client in mClients
- SubscriptionManager -> SubscriptionManager: propertyClients->remove(client)
- alt propertyClients->isEmpty()
- SubscriptionManager -> SubscriptionManager: mPropToClients.erase(propId)
- end
- loop propClient in mPropToClients
- alt client in propClient
- SubscriptionManager -> SubscriptionManager: isClientSubscribedToOtherProps = true
- end
- end
- alt isClientSubscribedToOtherProps == false
- SubscriptionManager -> SubscriptionManager: client->getCallback()->\n\tunlinkToDeath(mCallbackDeathRecipient)
- end
- end
- alt propertyClients == nullptr || propertyClients->isEmpty()
- SubscriptionManager -> VehicleHalManager: onAllClientsUnsubscribed(propertyId)
- VehicleHalManager -> EmulatedVehicleHal: unsubscribe(property)
- alt isContinuousProperty
- EmulatedVehicleHal -> RecurrentTimer: unregisterRecurrentEvent(property)
- RecurrentTimer -> RecurrentTimer: mCookieToEventsMap.erase(cookie)
- end
- end
- @enduml
复制代码 流程图:
6 属性上报流程
6.1 属性上报流程源码分析
- void onPropertyValueFromCar(const VehiclePropValue& value, bool updateStatus) override {
- return this->onPropertyValue(value, updateStatus);
- }
复制代码 由于EmulatedVehicleConnector同时继承VehicleHalServer和VehicleHalClient,所以这个onPropertyValue继承于VehicleHalClient,调用的是VehicleHalClient中的onPropertyValue函数。
- void VehicleHalClient::onPropertyValue(const VehiclePropValue& value, bool updateStatus) {
- if (!mPropCallback) {
- LOG(ERROR) << __func__ << ": PropertyCallBackType is not registered!";
- return;
- }
- return mPropCallback(value, updateStatus);
- }
复制代码 调用mPropCallback这个注册的回调函数,这个回调函数是:
- void EmulatedVehicleHal::onPropertyValue(const VehiclePropValue& value, bool updateStatus) {
- VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(value);
- if (mPropStore->writeValue(*updatedPropValue, updateStatus)) {
- getEmulatorOrDie()->doSetValueFromClient(*updatedPropValue);
- doHalEvent(std::move(updatedPropValue));
- }
- }
复制代码 起首,将上报的属性写入缓存中。然后调用doSetValueFromClient
- void VehicleEmulator::doSetValueFromClient(const VehiclePropValue& propValue) {
- vhal_proto::EmulatorMessage msg;
- vhal_proto::VehiclePropValue* val = msg.add_value();
- populateProtoVehiclePropValue(val, &propValue);
- msg.set_status(vhal_proto::RESULT_OK);
- msg.set_msg_type(vhal_proto::SET_PROPERTY_ASYNC);
- mSocketComm->sendMessage(msg);
- if (mPipeComm) {
- mPipeComm->sendMessage(msg);
- }
- }
复制代码 这里会通过SocketComm和PipeComm通知其他客户端。
然后会调用doHalEvent上报给CarService。
- void doHalEvent(VehiclePropValuePtr v) {
- mOnHalEvent(std::move(v));
- }
复制代码 mOnHalEvent是VehicleHalManager:nHalEvent函数
- void VehicleHalManager::onHalEvent(VehiclePropValuePtr v) {
- mEventQueue.push(std::move(v));
- }
复制代码 将VehiclePropValuePtr传入mEventQueue,这个是初始化的时候与BatchingConsumer中的mQueue绑定的一个queue,用于处置惩罚上报事件。同时BatchingConsumer这个类初始化的时候也会创建一个线程来处置惩罚上报事件,运行的函数为:
- void runInternal(const OnBatchReceivedFunc& onBatchReceived) {
- if (mState.exchange(State::RUNNING) == State::INIT) {
- while (State::RUNNING == mState) {
- mQueue->waitForItems();
- if (State::STOP_REQUESTED == mState) break;
- std::this_thread::sleep_for(mBatchInterval);
- if (State::STOP_REQUESTED == mState) break;
- std::vector<T> items = mQueue->flush();
- if (items.size() > 0) {
- onBatchReceived(items);
- }
- }
- }
- mState = State::STOPPED;
- }
- void waitForItems() {
- std::unique_lock<std::mutex> g(mLock);
- while (mQueue.empty() && mIsActive) {
- mCond.wait(g);
- }
- }
- std::vector<T> flush() {
- std::vector<T> items;
- MuxGuard g(mLock);
- if (mQueue.empty() || !mIsActive) {
- return items;
- }
- while (!mQueue.empty()) {
- items.push_back(std::move(mQueue.front()));
- mQueue.pop();
- }
- return items;
- }
- void push(T&& item) {
- {
- MuxGuard g(mLock);
- if (!mIsActive) {
- return;
- }
- mQueue.push(std::move(item));
- }
- mCond.notify_one();
- }
复制代码 当没有上报事件时,会waitForItems壅闭线程。如果有事件,则会在循环中处置惩罚,等待一个时间间隔mBatchInterval=10,如果在这个事件内没有上报事件,会等10s,如果有,则会在push的时候立马叫醒线程实行。
然后将queue中的所有事件都取出,调用回调函数处置惩罚,回调函数是:
- void VehicleHalManager::onBatchHalEvent(const std::vector<VehiclePropValuePtr>& values) {
- const auto& clientValues =
- mSubscriptionManager.distributeValuesToClients(values, SubscribeFlags::EVENTS_FROM_CAR);
- for (const HalClientValues& cv : clientValues) {
- auto vecSize = cv.values.size();
- hidl_vec<VehiclePropValue> vec;
- if (vecSize < kMaxHidlVecOfVehiclPropValuePoolSize) {
- vec.setToExternal(&mHidlVecOfVehiclePropValuePool[0], vecSize);
- } else {
- vec.resize(vecSize);
- }
- int i = 0;
- for (VehiclePropValue* pValue : cv.values) {
- shallowCopy(&(vec)[i++], *pValue);
- }
- auto status = cv.client->getCallback()->onPropertyEvent(vec);
- if (!status.isOk()) {
- ALOGE("Failed to notify client %s, err: %s",
- toString(cv.client->getCallback()).c_str(),
- status.description().c_str());
- }
- }
- }
复制代码 先看下封装
- std::list<HalClientValues> SubscriptionManager::distributeValuesToClients(
- const std::vector<recyclable_ptr<VehiclePropValue>>& propValues,
- SubscribeFlags flags) const {
- //创建一个map,key是HalClient,value是VehiclePropValue
- std::map<sp<HalClient>, std::list<VehiclePropValue*>> clientValuesMap;
- {
- MuxGuard g(mLock);
- //遍历所有的propValue
- for (const auto& propValue: propValues) {
- VehiclePropValue* v = propValue.get();
- //获取所有订阅了该属性的客户端HalClient对象
- auto clients = getSubscribedClientsLocked(v->prop, flags);
- //遍历所有HalClient,并将其和propValue一起封装加入clientValuesMap中
- for (const auto& client : clients) {
- clientValuesMap[client].push_back(v);
- }
- }
- }
- //遍历map中所有的对象,并封装成HalClientValues对象,存入clientValues中
- std::list<HalClientValues> clientValues;
- for (const auto& entry : clientValuesMap) {
- clientValues.push_back(HalClientValues {
- .client = entry.first,
- .values = entry.second
- });
- }
- return clientValues;
- }
- std::list<sp<HalClient>> SubscriptionManager::getSubscribedClientsLocked(
- int32_t propId, SubscribeFlags flags) const {
- std::list<sp<HalClient>> subscribedClients;
-
- //通过propId获取该id对应的HalClientVector对象
- sp<HalClientVector> propClients = getClientsForPropertyLocked(propId);
- if (propClients.get() != nullptr) {
- //遍历HalClientVector中HalClient,并返回
- for (size_t i = 0; i < propClients->size(); i++) {
- const auto& client = propClients->itemAt(i);
- if (client->isSubscribed(propId, flags)) {
- subscribedClients.push_back(client);
- }
- }
- }
- return subscribedClients;
- }
- sp<HalClientVector> SubscriptionManager::getClientsForPropertyLocked(
- int32_t propId) const {
- auto it = mPropToClients.find(propId);
- return it == mPropToClients.end() ? nullptr : it->second;
- }
复制代码 对客户端和属性值进行封装,然后遍历封装后的数组,逐个调用其回调函数onPropertyEvent,这个就是客户端传入的回调函数。
6.2 连续属性上报流程源码分析
连续属性订阅之后,会根据传入的采样率转换后的频率进行上报,订阅时,将订阅事件保存在mCookieToEventsMap这个map中,并叫醒了处置惩罚线程。
这个线程是什么时候初始化,在实行什么呢?这个可以参考https://editor.csdn.net/md/?articleId=140752076
- void loop(const Action& action) {
- static constexpr auto kInvalidTime = TimePoint(Nanos::max());
- std::vector<int32_t> cookies;
- while (!mStopRequested) {
- auto now = Clock::now();
- auto nextEventTime = kInvalidTime;
- cookies.clear();
- {
- std::unique_lock<std::mutex> g(mLock);
- for (auto&& it : mCookieToEventsMap) {
- RecurrentEvent& event = it.second;
- if (event.absoluteTime <= now) {
- event.updateNextEventTime(now);
- cookies.push_back(event.cookie);
- }
- if (nextEventTime > event.absoluteTime) {
- nextEventTime = event.absoluteTime;
- }
- }
- }
- if (cookies.size() != 0) {
- action(cookies);
- }
- std::unique_lock<std::mutex> g(mLock);
- mCond.wait_until(g, nextEventTime); // nextEventTime can be nanoseconds::max()
- }
- }
复制代码 叫醒这个线程,并在这个内里从mCookieToEventsMap中取出RecurrentEvent,判断时间戳,如果已经到时了,则实行内里的action回调函数。
- void EmulatedVehicleHal::onContinuousPropertyTimer(const std::vector<int32_t>& properties) {
- VehiclePropValuePtr v;
- auto& pool = *getValuePool();
- for (int32_t property : properties) {
- if (isContinuousProperty(property)) {
- auto internalPropValue = mPropStore->readValueOrNull(property);
- if (internalPropValue != nullptr) {
- v = pool.obtain(*internalPropValue);
- }
- } else {
- ALOGE("Unexpected onContinuousPropertyTimer for property: 0x%x", property);
- }
- if (v.get()) {
- v->timestamp = elapsedRealtimeNano();
- doHalEvent(std::move(v));
- }
- }
- }
复制代码 如果是连续属性,则从VehiclePropertyStore读取缓存,并调用doHalEvent往上报,这个和6.1节中的上报流程雷同。
6.3 属性上报流程图
plantuml
- @startuml
- participant CarService
- box
- participant EmulatedVehicleHal
- participant VehicleHalManager
- participant SubscriptionManager
- participant HalClient
- participant IPassThroughConnector
- participant VehicleHalClient
- participant VehiclePropertyStore
- participant VehicleEmulator
- participant SocketComm
- participant ConcurrentQueue
- participant BatchingConsumer
- endbox
- EmulatedVehicleHal -> IPassThroughConnector: onPropertyValueFromCar(*updatedPropValue, updateStatus)
- IPassThroughConnector -> VehicleHalClient: onPropertyValue(value, updateStatus)
- VehicleHalClient -> EmulatedVehicleHal: onPropertyValue(value, updateStatus)
- EmulatedVehicleHal -> VehiclePropertyStore: writeValue(*updatedPropValue, updateStatus)
- alt writeValue success
- EmulatedVehicleHal -> VehicleEmulator: doSetValueFromClient(*updatedPropValue)
- VehicleEmulator -> SocketComm: sendMessage(msg)
- EmulatedVehicleHal -> EmulatedVehicleHal: doHalEvent(std::move(updatedPropValue))
- EmulatedVehicleHal -> VehicleHalManager::onHalEvent(updatedPropValue)
- VehicleHalManager -> VehicleHalManager: mEventQueue.push(std::move(updatedPropValue))
- VehicleHalManager -> ConcurrentQueue: mQueue.push(updatedPropValue)
- ConcurrentQueue -> ConcurrentQueue: mCond.notify_one()
- ConcurrentQueue -> BatchingConsumer: runInternal(const OnBatchReceivedFunc& onBatchReceived)
- BatchingConsumer -> VehicleHalManager: onBatchHalEvent(const std::vector<VehiclePropValuePtr>& values)
- VehicleHalManager -> SubscriptionManager: distributeValuesToClients(values, \n\tSubscribeFlags::EVENTS_FROM_CAR)
- SubscriptionManager -> VehicleHalManager: clientValues
- loop cv in clientValues
- VehicleHalManager -> HalClient: getCallback()
- HalClient -> VehicleHalManager: callback
- VehicleHalManager -> CarService: callback->onPropertyEvent(values)
- end
- end
- @enduml
复制代码 流程图
连续属性上报流程图省略,大致和这个上面差不多,只是触发在定时器中。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |