Android车载——VehicleHal运行流程(Android 11)

张春  金牌会员 | 2024-10-8 03:59:43 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 844|帖子 844|积分 2532

1 概述

本篇重要讲解VehicleHal的重要运行流程,包括设置属性、获取属性、订阅属性、取消订阅、持续上报属性订阅等。
2 获取属性流程

2.1 获取属性流程源码分析

作为服务注册到hwServiceManager中的类是VehicleHalManager,所以,CarService对服务端的调用的hidl接口都是调用到了VehicleHalManager中。
  1. get(VehiclePropValue requestedPropValue)
  2.           generates (StatusCode status, VehiclePropValue propValue);
复制代码
IVehicle这个hidl接口中的界说如上
  1. Return<void> VehicleHalManager::get(const VehiclePropValue& requestedPropValue, get_cb _hidl_cb) {
  2.     const auto* config = getPropConfigOrNull(requestedPropValue.prop);
  3.     if (config == nullptr) {
  4.         ALOGE("Failed to get value: config not found, property: 0x%x",
  5.               requestedPropValue.prop);
  6.         _hidl_cb(StatusCode::INVALID_ARG, kEmptyValue);
  7.         return Void();
  8.     }
  9.     if (!checkReadPermission(*config)) {
  10.         _hidl_cb(StatusCode::ACCESS_DENIED, kEmptyValue);
  11.         return Void();
  12.     }
  13.     StatusCode status;
  14.     auto value = mHal->get(requestedPropValue, &status);
  15.     _hidl_cb(status, value.get() ? *value : kEmptyValue);
  16.     return Void();
  17. }
复制代码
调用之后会调用到VehicleHalManager中的get函数
  1. const VehiclePropConfig* VehicleHalManager::getPropConfigOrNull(
  2.         int32_t prop) const {
  3.     return mConfigIndex->hasConfig(prop)
  4.            ? &mConfigIndex->getConfig(prop) : nullptr;
  5. }
复制代码
起首,会从属性设置列表中是否存在这个属性,这个是初始化的时候缓存的,缓存的是所有的属性设置。
如果获取的属性不在属性设置列表中,则不能够获取,如果存在,会判断访问权限,访问权限校验通过之后,会调用mHal的get函数。
  1. VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get(
  2.         const VehiclePropValue& requestedPropValue, StatusCode* outStatus) {
  3.     auto propId = requestedPropValue.prop;
  4.     ALOGV("get(%d)", propId);
  5.     auto& pool = *getValuePool();
  6.     VehiclePropValuePtr v = nullptr;
  7.     switch (propId) {
  8.         case OBD2_FREEZE_FRAME:
  9.             v = pool.obtainComplex();
  10.             *outStatus = fillObd2FreezeFrame(requestedPropValue, v.get());
  11.             break;
  12.         case OBD2_FREEZE_FRAME_INFO:
  13.             v = pool.obtainComplex();
  14.             *outStatus = fillObd2DtcInfo(v.get());
  15.             break;
  16.         default:
  17.             if (mEmulatedUserHal != nullptr && mEmulatedUserHal->isSupported(propId)) {
  18.                 ALOGI("get(): getting value for prop %d from User HAL", propId);
  19.                 const auto& ret = mEmulatedUserHal->onGetProperty(requestedPropValue);
  20.                 if (!ret.ok()) {
  21.                     ALOGE("get(): User HAL returned error: %s", ret.error().message().c_str());
  22.                     *outStatus = StatusCode(ret.error().code());
  23.                 } else {
  24.                     auto value = ret.value().get();
  25.                     if (value != nullptr) {
  26.                         ALOGI("get(): User HAL returned value: %s", toString(*value).c_str());
  27.                         v = getValuePool()->obtain(*value);
  28.                         *outStatus = StatusCode::OK;
  29.                     } else {
  30.                         ALOGE("get(): User HAL returned null value");
  31.                         *outStatus = StatusCode::INTERNAL_ERROR;
  32.                     }
  33.                 }
  34.                 break;
  35.             }
  36.             auto internalPropValue = mPropStore->readValueOrNull(requestedPropValue);
  37.             if (internalPropValue != nullptr) {
  38.                 v = getValuePool()->obtain(*internalPropValue);
  39.             }
  40.             *outStatus = v != nullptr ? StatusCode::OK : StatusCode::INVALID_ARG;
  41.             break;
  42.     }
  43.     if (v.get()) {
  44.         v->timestamp = elapsedRealtimeNano();
  45.     }
  46.     return v;
  47. }
复制代码
起首,会对userhal的一些判断操作,这个EmulatedUserHal是跟用户身份相关的hal界说,用于处置惩罚用户切换相关事件。如果是用户hal相关的prop获取,则获取完成之后就直接跳出。如果不是,则走普通的property获取路径,从VehiclePropertyStore中读取。
  1. using PropertyMap = std::map<RecordId, VehiclePropValue>;
  2. PropertyMap mPropertyValues;
  3. std::unique_ptr<VehiclePropValue> VehiclePropertyStore::readValueOrNull(
  4.         int32_t prop, int32_t area, int64_t token) const {
  5.     RecordId recId = {prop, isGlobalProp(prop) ? 0 : area, token };
  6.     MuxGuard g(mLock);
  7.     const VehiclePropValue* internalValue = getValueOrNullLocked(recId);
  8.     return internalValue ? std::make_unique<VehiclePropValue>(*internalValue) : nullptr;
  9. }
  10. const VehiclePropValue* VehiclePropertyStore::getValueOrNullLocked(
  11.         const VehiclePropertyStore::RecordId& recId) const  {
  12.     auto it = mPropertyValues.find(recId);
  13.     return it == mPropertyValues.end() ? nullptr : &it->second;
  14. }
复制代码
从mPropertyValues这个map中去获取对应propId的property。mPropertyValues内里的值是在哪添补的呢?
  1. bool VehiclePropertyStore::writeValue(const VehiclePropValue& propValue,
  2.                                         bool updateStatus) {
  3.     MuxGuard g(mLock);
  4.     if (!mConfigs.count(propValue.prop)) return false;
  5.     RecordId recId = getRecordIdLocked(propValue);
  6.     VehiclePropValue* valueToUpdate = const_cast<VehiclePropValue*>(getValueOrNullLocked(recId));
  7.     if (valueToUpdate == nullptr) {
  8.         mPropertyValues.insert({ recId, propValue });
  9.         return true;
  10.     }
  11.     // propValue is outdated and drops it.
  12.     if (valueToUpdate->timestamp > propValue.timestamp) {
  13.         return false;
  14.     }
  15.     // update the propertyValue.
  16.     // The timestamp in propertyStore should only be updated by the server side. It indicates
  17.     // the time when the event is generated by the server.
  18.     valueToUpdate->timestamp = propValue.timestamp;
  19.     valueToUpdate->value = propValue.value;
  20.     if (updateStatus) {
  21.         valueToUpdate->status = propValue.status;
  22.     }
  23.     return true;
  24. }
复制代码
是在这个函数中,这个函数是在VHAL初始化的时候调用的,初始化的时候,会遍历一个界说了所有支持属性的列表,并调用writeValue函数将属性设置和属性值缓存到VehiclePropertyStore中。
以上就是CarService从VHAL获取属性的流程,总结来说就是:从VHAL的缓存map中获取属性。
2.2 获取属性流程图

plantuml
  1. @startuml
  2. participant CarService
  3. box
  4. participant VehicleHalManager
  5. participant EmulatedVehicleHal
  6. participant VehiclePropertyStore
  7. endbox
  8. CarService -> VehicleHalManager: get(const VehiclePropValue& \n\trequestedPropValue, get_cb _hidl_cb)
  9. VehicleHalManager -> EmulatedVehicleHal: get(const VehiclePropValue& \n\trequestedPropValue, get_cb _hidl_cb)
  10. EmulatedVehicleHal -> VehiclePropertyStore: readValueOrNull(int32_t prop, \n\tint32_t area, int64_t token)
  11. VehiclePropertyStore -> EmulatedVehicleHal: propValue
  12. EmulatedVehicleHal -> VehicleHalManager: propValue
  13. VehicleHalManager -> CarService: _hidl_cb(propValue)
  14. @enduml
复制代码

3 设置属性流程

3.1 设置属性流程源码分析

hidl调用后照旧从VehicleHalManager开始的
  1. Return<StatusCode> VehicleHalManager::set(const VehiclePropValue &value) {
  2.     auto prop = value.prop;
  3.     const auto* config = getPropConfigOrNull(prop);
  4.     if (config == nullptr) {
  5.         ALOGE("Failed to set value: config not found, property: 0x%x", prop);
  6.         return StatusCode::INVALID_ARG;
  7.     }
  8.     if (!checkWritePermission(*config)) {
  9.         return StatusCode::ACCESS_DENIED;
  10.     }
  11.     handlePropertySetEvent(value);
  12.     auto status = mHal->set(value);
  13.     return Return<StatusCode>(status);
  14. }
复制代码
起首判断缓存中是否有该属性的属性设置,有才支持后续的set操作
handlePropertySetEvent是对带有EVENTS_FROM_ANDROID这个订阅标签属性的处置惩罚,这种属性的设置必要直接上报给上层。
然后是调用EmulatedVehicleHal的set函数
  1. StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) {
  2.     constexpr bool updateStatus = false;
  3.         //这里是模拟车辆属性
  4.     if (propValue.prop == kGenerateFakeDataControllingProperty) {
  5.         // Send the generator controlling request to the server.
  6.         // 'updateStatus' flag is only for the value sent by setProperty (propValue in this case)
  7.         // instead of the generated values triggered by it. 'propValue' works as a control signal
  8.         // here, since we never send the control signal back, the value of 'updateStatus' flag
  9.         // does not matter here.
  10.         auto status = mVehicleClient->setProperty(propValue, updateStatus);
  11.         return status;
  12.     //处理空调相关的属性
  13.     } else if (mHvacPowerProps.count(propValue.prop)) {
  14.         auto hvacPowerOn = mPropStore->readValueOrNull(
  15.             toInt(VehicleProperty::HVAC_POWER_ON),
  16.             (VehicleAreaSeat::ROW_1_LEFT | VehicleAreaSeat::ROW_1_RIGHT |
  17.              VehicleAreaSeat::ROW_2_LEFT | VehicleAreaSeat::ROW_2_CENTER |
  18.              VehicleAreaSeat::ROW_2_RIGHT));
  19.         if (hvacPowerOn && hvacPowerOn->value.int32Values.size() == 1
  20.                 && hvacPowerOn->value.int32Values[0] == 0) {
  21.             return StatusCode::NOT_AVAILABLE;
  22.         }
  23.     } else {
  24.         // Handle property specific code
  25.         switch (propValue.prop) {
  26.             case OBD2_FREEZE_FRAME_CLEAR:
  27.                 return clearObd2FreezeFrames(propValue);
  28.             case VEHICLE_MAP_SERVICE:
  29.                 // Placeholder for future implementation of VMS property in the default hal. For
  30.                 // now, just returns OK; otherwise, hal clients crash with property not supported.
  31.                 return StatusCode::OK;
  32.         }
  33.     }
  34.     if (propValue.status != VehiclePropertyStatus::AVAILABLE) {
  35.         // Android side cannot set property status - this value is the
  36.         // purview of the HAL implementation to reflect the state of
  37.         // its underlying hardware
  38.         return StatusCode::INVALID_ARG;
  39.     }
  40.     //读取当前值
  41.     auto currentPropValue = mPropStore->readValueOrNull(propValue);
  42.     if (currentPropValue == nullptr) {
  43.         return StatusCode::INVALID_ARG;
  44.     }
  45.     if (currentPropValue->status != VehiclePropertyStatus::AVAILABLE) {
  46.         // do not allow Android side to set() a disabled/error property
  47.         return StatusCode::NOT_AVAILABLE;
  48.     }
  49.     /**
  50.      * After checking all conditions, such as the property is available, a real vhal will
  51.      * sent the events to Car ECU to take actions.
  52.      */
  53.     // Send the value to the vehicle server, the server will talk to the (real or emulated) car
  54.     //设置属性到VehicleClient,通过这个设置到模拟车辆或者实际车辆
  55.     auto setValueStatus = mVehicleClient->setProperty(propValue, updateStatus);
  56.     if (setValueStatus != StatusCode::OK) {
  57.         return setValueStatus;
  58.     }
  59.     return StatusCode::OK;
  60. }
复制代码
其中mVehicleClient是初始化时传入的EmulatedVehicleConnector对象,所以调用的是EmulatedVehicleConnector的setProperty函数。
  1. StatusCode setProperty(const VehiclePropValue& value, bool updateStatus) override {
  2.     return this->onSetProperty(value, updateStatus);
  3. }
复制代码
setProperty函数在EmulatedVehicleConnector的父类IPassThroughConnector中,然后调用onSetProperty函数,这个函数在EmulatedVehicleConnector类中。
  1. StatusCode EmulatedVehicleConnector::onSetProperty(const VehiclePropValue& value,
  2.                                                    bool updateStatus) {
  3.     if (mEmulatedUserHal.isSupported(value.prop)) {
  4.         LOG(INFO) << "onSetProperty(): property " << value.prop << " will be handled by UserHal";
  5.         const auto& ret = mEmulatedUserHal.onSetProperty(value);
  6.         if (!ret.ok()) {
  7.             LOG(ERROR) << "onSetProperty(): HAL returned error: " << ret.error().message();
  8.             return StatusCode(ret.error().code());
  9.         }
  10.         auto updatedValue = ret.value().get();
  11.         if (updatedValue != nullptr) {
  12.             LOG(INFO) << "onSetProperty(): updating property returned by HAL: "
  13.                       << toString(*updatedValue);
  14.             onPropertyValueFromCar(*updatedValue, updateStatus);
  15.         }
  16.         return StatusCode::OK;
  17.     }
  18.     return this->VehicleHalServer::onSetProperty(value, updateStatus);
  19. }
复制代码
起首处置惩罚UserHal相关的属性操作。然后调用VehicleHalServer中的onSetProperty函数。
  1. StatusCode VehicleHalServer::onSetProperty(const VehiclePropValue& value, bool updateStatus) {
  2.     LOG(DEBUG) << "onSetProperty(" << value.prop << ")";
  3.     // Some properties need to be treated non-trivially
  4.     switch (value.prop) {
  5.         case kGenerateFakeDataControllingProperty:
  6.             return handleGenerateFakeDataRequest(value);
  7.         // set the value from vehicle side, used in end to end test.
  8.         case kSetIntPropertyFromVehicleForTest: {
  9.             auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::INT32, 1);
  10.             updatedPropValue->prop = value.value.int32Values[0];
  11.             updatedPropValue->value.int32Values[0] = value.value.int32Values[1];
  12.             updatedPropValue->timestamp = value.value.int64Values[0];
  13.             updatedPropValue->areaId = value.areaId;
  14.             onPropertyValueFromCar(*updatedPropValue, updateStatus);
  15.             return StatusCode::OK;
  16.         }
  17.         case kSetFloatPropertyFromVehicleForTest: {
  18.             auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::FLOAT, 1);
  19.             updatedPropValue->prop = value.value.int32Values[0];
  20.             updatedPropValue->value.floatValues[0] = value.value.floatValues[0];
  21.             updatedPropValue->timestamp = value.value.int64Values[0];
  22.             updatedPropValue->areaId = value.areaId;
  23.             onPropertyValueFromCar(*updatedPropValue, updateStatus);
  24.             return StatusCode::OK;
  25.         }
  26.         case kSetBooleanPropertyFromVehicleForTest: {
  27.             auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::BOOLEAN, 1);
  28.             updatedPropValue->prop = value.value.int32Values[1];
  29.             updatedPropValue->value.int32Values[0] = value.value.int32Values[0];
  30.             updatedPropValue->timestamp = value.value.int64Values[0];
  31.             updatedPropValue->areaId = value.areaId;
  32.             onPropertyValueFromCar(*updatedPropValue, updateStatus);
  33.             return StatusCode::OK;
  34.         }
  35.         case AP_POWER_STATE_REPORT:
  36.             switch (value.value.int32Values[0]) {
  37.                 case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT):
  38.                 case toInt(VehicleApPowerStateReport::SHUTDOWN_CANCELLED):
  39.                 case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL):
  40.                     // CPMS is in WAIT_FOR_VHAL state, simply move to ON
  41.                     // Send back to HAL
  42.                     // ALWAYS update status for generated property value
  43.                     onPropertyValueFromCar(*createApPowerStateReq(VehicleApPowerStateReq::ON, 0),
  44.                                            true /* updateStatus */);
  45.                     break;
  46.                 case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY):
  47.                 case toInt(VehicleApPowerStateReport::SHUTDOWN_START):
  48.                     // CPMS is in WAIT_FOR_FINISH state, send the FINISHED command
  49.                     // Send back to HAL
  50.                     // ALWAYS update status for generated property value
  51.                     onPropertyValueFromCar(
  52.                             *createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0),
  53.                             true /* updateStatus */);
  54.                     break;
  55.                 case toInt(VehicleApPowerStateReport::ON):
  56.                 case toInt(VehicleApPowerStateReport::SHUTDOWN_POSTPONE):
  57.                 case toInt(VehicleApPowerStateReport::SHUTDOWN_PREPARE):
  58.                     // Do nothing
  59.                     break;
  60.                 default:
  61.                     // Unknown state
  62.                     break;
  63.             }
  64.             break;
  65.         default:
  66.             break;
  67.     }
  68.     // In the real vhal, the value will be sent to Car ECU.
  69.     // We just pretend it is done here and send back to HAL
  70.     auto updatedPropValue = getValuePool()->obtain(value);
  71.     updatedPropValue->timestamp = elapsedRealtimeNano();
  72.     onPropertyValueFromCar(*updatedPropValue, updateStatus);
  73.     return StatusCode::OK;
  74. }
复制代码
上面是模拟属性设置流程,这里就相当于模拟属性设置完成了。更新属性的值和时间戳之后,调用onPropertyValueFromCar模拟属性设置成功的上报操作
3.2 设置属性流程图

plantuml
  1. @startuml
  2. participant CarService
  3. box
  4. participant VehicleHalManager
  5. participant SubscriptionManager
  6. participant EmulatedVehicleHal
  7. participant IPassThroughConnector
  8. participant EmulatedVehicleConnector
  9. participant VehicleHalServer
  10. endbox
  11. CarService -> VehicleHalManager: set(const VehiclePropValue& value)
  12. VehicleHalManager -> VehicleHalManager: handlePropertySetEvent(const VehiclePropValue& value)
  13. VehicleHalManager -> SubscriptionManager: getSubscribedClients(int32_t propId, SubscribeFlags flags)
  14. SubscriptionManager -> VehicleHalManager: value
  15. alt flags == SubscribeFlags::EVENTS_FROM_ANDROID
  16.     VehicleHalManager -> CarService: onPropertySet(value)
  17. end
  18. VehicleHalManager -> EmulatedVehicleHal: set(const VehiclePropValue& value)
  19. EmulatedVehicleHal -> IPassThroughConnector: setProperty(const VehiclePropValue& \n\tvalue, bool updateStatus)
  20. IPassThroughConnector -> EmulatedVehicleConnector: onSetProperty(const VehiclePropValue& \n\tvalue, bool updateStatus)
  21. EmulatedVehicleConnector -> VehicleHalServer: onSetProperty(const VehiclePropValue& value, bool updateStatus)
  22. @enduml
复制代码
流程图:

这里由于没有实际车辆,没有往下设置,OEM厂商必要设置到ECU中。至于设置之后,VHAL缓存的改变则是由设置成功的通知上报之后才会写入缓存的。
4 订阅属性流程

4.1 普通订阅属性流程源码分析

订阅入口也是在VehicleHalManager中
  1. Return<StatusCode> VehicleHalManager::subscribe(const sp<IVehicleCallback> &callback,
  2.                                                 const hidl_vec<SubscribeOptions> &options) {
  3.     hidl_vec<SubscribeOptions> verifiedOptions(options);
  4.     for (size_t i = 0; i < verifiedOptions.size(); i++) {
  5.         SubscribeOptions& ops = verifiedOptions[i];
  6.         auto prop = ops.propId;
  7.         const auto* config = getPropConfigOrNull(prop);
  8.         if (config == nullptr) {
  9.             ALOGE("Failed to subscribe: config not found, property: 0x%x",
  10.                   prop);
  11.             return StatusCode::INVALID_ARG;
  12.         }
  13.         if (ops.flags == SubscribeFlags::UNDEFINED) {
  14.             ALOGE("Failed to subscribe: undefined flag in options provided");
  15.             return StatusCode::INVALID_ARG;
  16.         }
  17.         if (!isSubscribable(*config, ops.flags)) {
  18.             ALOGE("Failed to subscribe: property 0x%x is not subscribable",
  19.                   prop);
  20.             return StatusCode::INVALID_ARG;
  21.         }
  22.         ops.sampleRate = checkSampleRate(*config, ops.sampleRate);
  23.     }
  24.     std::list<SubscribeOptions> updatedOptions;
  25.     auto res = mSubscriptionManager.addOrUpdateSubscription(getClientId(callback),
  26.                                                             callback, verifiedOptions,
  27.                                                             &updatedOptions);
  28.     if (StatusCode::OK != res) {
  29.         ALOGW("%s failed to subscribe, error code: %d", __func__, res);
  30.         return res;
  31.     }
  32.     for (auto opt : updatedOptions) {
  33.         mHal->subscribe(opt.propId, opt.sampleRate);
  34.     }
  35.     return StatusCode::OK;
  36. }
复制代码
起首判断属性设置是否存在,存在才支持订阅
然后判断是否可以订阅
  1. bool VehicleHalManager::isSubscribable(const VehiclePropConfig& config,
  2.                                        SubscribeFlags flags) {
  3.     bool isReadable = config.access & VehiclePropertyAccess::READ;
  4.     if (!isReadable && (SubscribeFlags::EVENTS_FROM_CAR & flags)) {
  5.         ALOGW("Cannot subscribe, property 0x%x is not readable", config.prop);
  6.         return false;
  7.     }
  8.     if (config.changeMode == VehiclePropertyChangeMode::STATIC) {
  9.         ALOGW("Cannot subscribe, property 0x%x is static", config.prop);
  10.         return false;
  11.     }
  12.     return true;
  13. }
复制代码
判断访问权限,判断flag,如果flag是从car来的,则返回false。然后是判断属性的changeMode,如果changeMode是STATIC,表现属性不变,则不支持订阅。
然后添加订阅addOrUpdateSubscription,添加之前起首创建clientId
  1. using ClientId = uint64_t;
  2. ClientId VehicleHalManager::getClientId(const sp<IVehicleCallback>& callback) {
  3.     //TODO(b/32172906): rework this to get some kind of unique id for callback interface when this
  4.     // feature is ready in HIDL.
  5.     if (callback->isRemote()) {
  6.         BpHwVehicleCallback* hwCallback = static_cast<BpHwVehicleCallback*>(callback.get());
  7.         return static_cast<ClientId>(reinterpret_cast<intptr_t>(hwCallback->onAsBinder()));
  8.     } else {
  9.         return static_cast<ClientId>(reinterpret_cast<intptr_t>(callback.get()));
  10.     }
  11. }
复制代码
根据传入的回调函数的额指针来强转成ClientId这种int范例,作为客户端的唯一标识。
  1. StatusCode SubscriptionManager::addOrUpdateSubscription(
  2.         ClientId clientId,
  3.         const sp<IVehicleCallback> &callback,
  4.         const hidl_vec<SubscribeOptions> &optionList,
  5.         std::list<SubscribeOptions>* outUpdatedSubscriptions) {
  6.     outUpdatedSubscriptions->clear();
  7.     MuxGuard g(mLock);
  8.     ALOGI("SubscriptionManager::addOrUpdateSubscription, callback: %p", callback.get());
  9.     const sp<HalClient>& client = getOrCreateHalClientLocked(clientId, callback);
  10.     if (client.get() == nullptr) {
  11.         return StatusCode::INTERNAL_ERROR;
  12.     }
  13.     for (size_t i = 0; i < optionList.size(); i++) {
  14.         const SubscribeOptions& opts = optionList[i];
  15.         ALOGI("SubscriptionManager::addOrUpdateSubscription, prop: 0x%x", opts.propId);
  16.         client->addOrUpdateSubscription(opts);
  17.         addClientToPropMapLocked(opts.propId, client);
  18.         if (SubscribeFlags::EVENTS_FROM_CAR & opts.flags) {
  19.             SubscribeOptions updated;
  20.             if (updateHalEventSubscriptionLocked(opts, &updated)) {
  21.                 outUpdatedSubscriptions->push_back(updated);
  22.             }
  23.         }
  24.     }
  25.     return StatusCode::OK;
  26. }
复制代码
起首,创建客户端对象HalClient
  1. std::map<ClientId, sp<HalClient>> mClients;
  2. sp<HalClient> SubscriptionManager::getOrCreateHalClientLocked(
  3.         ClientId clientId, const sp<IVehicleCallback>& callback) {
  4.     auto it = mClients.find(clientId);
  5.     if (it == mClients.end()) {
  6.         uint64_t cookie = reinterpret_cast<uint64_t>(clientId);
  7.         ALOGI("Creating new client and linking to death recipient, cookie: 0x%" PRIx64, cookie);
  8.         auto res = callback->linkToDeath(mCallbackDeathRecipient, cookie);
  9.         if (!res.isOk()) {  // Client is already dead?
  10.             ALOGW("%s failed to link to death, client %p, err: %s",
  11.                   __func__, callback.get(), res.description().c_str());
  12.             return nullptr;
  13.         }
  14.         sp<HalClient> client = new HalClient(callback);
  15.         mClients.insert({clientId, client});
  16.         return client;
  17.     } else {
  18.         return it->second;
  19.     }
  20. }
复制代码
mClients是保存订阅客户端的map,key是ClientId,value是HalClient对象。这里会先判断mClients这个map中是否存在对应的客户端,如果没有,则创建HalClient对象,并到场到这个map之中,如果有则直接返回。
然后for循环遍历所有的订阅项,由于订阅的时候,CarService传入的是SubscribeOptions的列表:
  1. struct SubscribeOptions {
  2.     /** Property to subscribe */
  3.     int32_t propId;
  4.     /**
  5.      * Sample rate in Hz.
  6.      *
  7.      * Must be provided for properties with
  8.      * VehiclePropertyChangeMode::CONTINUOUS. The value must be within
  9.      * VehiclePropConfig#minSamplingRate .. VehiclePropConfig#maxSamplingRate
  10.      * for a given property.
  11.      * This value indicates how many updates per second client wants to receive.
  12.      */
  13.     float sampleRate;
  14.     /** Flags that indicate to which event sources to listen. */
  15.     SubscribeFlags flags;
  16. };
复制代码
所以可以一次性订阅多个属性。但是这多个属性是一次订阅,也是走一个回调函数上去的。这里会遍历所有的SubscribeOptions,然后调用addOrUpdateSubscription函数。
  1. std::map<int32_t, SubscribeOptions> mSubscriptions;
  2. void HalClient::addOrUpdateSubscription(const SubscribeOptions &opts)  {
  3.     ALOGI("%s opts.propId: 0x%x", __func__, opts.propId);
  4.     auto it = mSubscriptions.find(opts.propId);
  5.     if (it == mSubscriptions.end()) {
  6.         mSubscriptions.emplace(opts.propId, opts);
  7.     } else {
  8.         const SubscribeOptions& oldOpts = it->second;
  9.         SubscribeOptions updatedOptions;
  10.         if (mergeSubscribeOptions(oldOpts, opts, &updatedOptions)) {
  11.             mSubscriptions.erase(it);
  12.             mSubscriptions.emplace(opts.propId, updatedOptions);
  13.         }
  14.     }
  15. }
  16. bool mergeSubscribeOptions(const SubscribeOptions &oldOpts,
  17.                            const SubscribeOptions &newOpts,
  18.                            SubscribeOptions *outResult) {
  19.     float updatedRate = std::max(oldOpts.sampleRate, newOpts.sampleRate);
  20.     SubscribeFlags updatedFlags = SubscribeFlags(oldOpts.flags | newOpts.flags);
  21.     bool updated = (updatedRate > oldOpts.sampleRate) || (updatedFlags != oldOpts.flags);
  22.     if (updated) {
  23.         *outResult = oldOpts;
  24.         outResult->sampleRate = updatedRate;
  25.         outResult->flags = updatedFlags;
  26.     }
  27.     return updated;
  28. }
复制代码
起首判断这个SubscribeOptions中包含的propId是否已经存在于mSubscriptions这个map中,如果存在,则更新flag和采样率和相应的SubscribeOptions对象,如果不存在,则添加。
这个map的key是propId,value是SubscribeOptions。
  1. std::map<int32_t, sp<HalClientVector>> mPropToClients;
  2. void SubscriptionManager::addClientToPropMapLocked(
  3.         int32_t propId, const sp<HalClient> &client) {
  4.     auto it = mPropToClients.find(propId);
  5.     sp<HalClientVector> propClients;
  6.     if (it == mPropToClients.end()) {
  7.         propClients = new HalClientVector();
  8.         mPropToClients.insert(std::make_pair(propId, propClients));
  9.     } else {
  10.         propClients = it->second;
  11.     }
  12.     propClients->addOrUpdate(client);
  13. }
复制代码
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中进行处置惩罚
  1. StatusCode EmulatedVehicleHal::subscribe(int32_t property, float sampleRate) {
  2.     ALOGI("%s propId: 0x%x, sampleRate: %f", __func__, property, sampleRate);
  3.     if (isContinuousProperty(property)) {
  4.         mRecurrentTimer.registerRecurrentEvent(hertzToNanoseconds(sampleRate), property);
  5.     }
  6.     return StatusCode::OK;
  7. }
  8. bool EmulatedVehicleHal::isContinuousProperty(int32_t propId) const {
  9.     const VehiclePropConfig* config = mPropStore->getConfigOrNull(propId);
  10.     if (config == nullptr) {
  11.         ALOGW("Config not found for property: 0x%x", propId);
  12.         return false;
  13.     }
  14.     return config->changeMode == VehiclePropertyChangeMode::CONTINUOUS;
  15. }
复制代码
重要就是通过属性设置的changeMode是否是CONTINUOUS来判断,判断如果还连续属性,调用registerRecurrentEvent
  1. std::unordered_map<int32_t, RecurrentEvent> mCookieToEventsMap;
  2. void registerRecurrentEvent(std::chrono::nanoseconds interval, int32_t cookie) {
  3.     TimePoint now = Clock::now();
  4.     // Align event time point among all intervals. Thus if we have two intervals 1ms and 2ms,
  5.     // during every second wake-up both intervals will be triggered.
  6.     TimePoint absoluteTime = now - Nanos(now.time_since_epoch().count() % interval.count());
  7.     {
  8.         std::lock_guard<std::mutex> g(mLock);
  9.         mCookieToEventsMap[cookie] = { interval, cookie, absoluteTime };
  10.     }
  11.     mCond.notify_one();
  12. }
复制代码
用propId作为key,将定时势件的定时周期,propId,当前转换后时间封装成RecurrentEvent对象,存储到mCookieToEventsMap这个map中,然后通过mCond叫醒线程,至此连续订阅完成,等待特定时间上报。
4.3 订阅流程图

plantuml
  1. @startuml
  2. participant CarService
  3. box
  4. participant VehicleHalManager
  5. participant SubscriptionManager
  6. participant HalClient
  7. participant HalClientVector
  8. participant EmulatedVehicleHal
  9. participant RecurrentTimer
  10. endbox
  11. CarService -> VehicleHalManager: subscribe(const sp<IVehicleCallback> &callback, \n\tconst hidl_vec<SubscribeOptions> &options)
  12. VehicleHalManager -> SubscriptionManager: addOrUpdateSubscription(\n\tClientId clientId, \n\tconst sp<IVehicleCallback> &callback, \n\tconst hidl_vec<SubscribeOptions> &optionList, \n\tstd::list<SubscribeOptions>* outUpdatedSubscriptions)
  13. SubscriptionManager -> SubscriptionManager: getClientId(const sp<IVehicleCallback>& callback)
  14. SubscriptionManager -> SubscriptionManager: getOrCreateHalClientLocked(ClientId clientId, \n\tconst sp<IVehicleCallback>& callback)
  15. alt not in mClients
  16.     SubscriptionManager -> HalClient: new HalClient(const sp<IVehicleCallback> &callback)
  17.     HalClient -> SubscriptionManager: client
  18.     SubscriptionManager -> SubscriptionManager: mClients.insert({clientId, client})
  19. end
  20. loop i in optionList.size
  21.     SubscriptionManager -> HalClient: addOrUpdateSubscription(const SubscribeOptions &opts)
  22.     alt not in mSubscriptions
  23.         HalClient -> HalClient: emplace(opts.propId, opts)
  24.     else in mSubscriptions
  25.         HalClient -> HalClient: mergeSubscribeOptions(oldOpts, opts, &updatedOptions)
  26.         HalClient -> HalClient: erase(it)
  27.         HalClient -> HalClient: emplace(opts.propId, opts)
  28.     end
  29.     SubscriptionManager -> SubscriptionManager: addClientToPropMapLocked(opts.propId, client)
  30.     alt not in mPropToClients
  31.         SubscriptionManager -> HalClientVector: new HalClientVector()
  32.         HalClientVector -> SubscriptionManager: propClients
  33.         SubscriptionManager -> SubscriptionManager: mPropToClients.insert(std::make_pair(propId, propClients));
  34.     end
  35.     SubscriptionManager -> SubscriptionManager: propClients->addOrUpdate(client)
  36. end
  37. loop opt in updatedOptions
  38.     SubscriptionManager -> EmulatedVehicleHal: subscribe(opt.propId, opt.sampleRate)
  39.     alt isContinuousProperty
  40.         EmulatedVehicleHal -> RecurrentTimer: registerRecurrentEvent(hertzToNanoseconds(sampleRate), property)
  41.         RecurrentTimer -> RecurrentTimer: mCookieToEventsMap[cookie] = \n\t{ interval, cookie, absoluteTime }
  42.     end
  43. end
  44. @enduml
复制代码
流程图如下:

5 取消订阅流程

5.1 取消订阅流程源码分析

取消订阅入口也是在VehicleHalManager中
  1. Return<StatusCode> VehicleHalManager::unsubscribe(const sp<IVehicleCallback>& callback,
  2.                                                   int32_t propId) {
  3.     mSubscriptionManager.unsubscribe(getClientId(callback), propId);
  4.     return StatusCode::OK;
  5. }
复制代码
根据callback获取ClientId,并转到SubscriptionManager中处置惩罚
  1. void SubscriptionManager::unsubscribe(ClientId clientId,
  2.                                       int32_t propId) {
  3.     MuxGuard g(mLock);
  4.     auto propertyClients = getClientsForPropertyLocked(propId);
  5.     auto clientIter = mClients.find(clientId);
  6.     if (clientIter == mClients.end()) {
  7.         ALOGW("Unable to unsubscribe: no callback found, propId: 0x%x", propId);
  8.     } else {
  9.         auto client = clientIter->second;
  10.         if (propertyClients != nullptr) {
  11.             propertyClients->remove(client);
  12.             if (propertyClients->isEmpty()) {
  13.                 mPropToClients.erase(propId);
  14.             }
  15.         }
  16.         bool isClientSubscribedToOtherProps = false;
  17.         for (const auto& propClient : mPropToClients) {
  18.             if (propClient.second->indexOf(client) >= 0) {
  19.                 isClientSubscribedToOtherProps = true;
  20.                 break;
  21.             }
  22.         }
  23.         if (!isClientSubscribedToOtherProps) {
  24.             auto res = client->getCallback()->unlinkToDeath(mCallbackDeathRecipient);
  25.             if (!res.isOk()) {
  26.                 ALOGW("%s failed to unlink to death, client: %p, err: %s",
  27.                       __func__, client->getCallback().get(), res.description().c_str());
  28.             }
  29.             mClients.erase(clientIter);
  30.         }
  31.     }
  32.     if (propertyClients == nullptr || propertyClients->isEmpty()) {
  33.         mHalEventSubscribeOptions.erase(propId);
  34.         mOnPropertyUnsubscribed(propId);
  35.     }
  36. }
  37. sp<HalClientVector> SubscriptionManager::getClientsForPropertyLocked(
  38.         int32_t propId) const {
  39.     auto it = mPropToClients.find(propId);
  40.     return it == mPropToClients.end() ? nullptr : it->second;
  41. }
复制代码
起首,调用getClientsForPropertyLocked函数,根据propId获取HalClientVector对象。然后从mClients中根据ClientId找到对应的HalClient对象,如果该HalClient存在,则从HalClientVector中移除,如果HalClientVector中是最后一个HalClient,则从mPropToClients中移除这个propId的HalClientVector对象。
如果这个client还订阅了其他propId,则不把这个client从mClients中移除,如果没有订阅其他的propId,则从mClients中移除。
同时,如果这个HalClientVector为空了,则移除mHalEventSubscribeOptions中的对应propId的订阅属性,并调用mOnPropertyUnsubscribed这个回调函数。
  1. void VehicleHalManager::onAllClientsUnsubscribed(int32_t propertyId) {
  2.     mHal->unsubscribe(propertyId);
  3. }
  4. StatusCode EmulatedVehicleHal::unsubscribe(int32_t property) {
  5.     ALOGI("%s propId: 0x%x", __func__, property);
  6.     if (isContinuousProperty(property)) {
  7.         mRecurrentTimer.unregisterRecurrentEvent(property);
  8.     }
  9.     return StatusCode::OK;
  10. }
  11. void unregisterRecurrentEvent(int32_t cookie) {
  12.         {
  13.             std::lock_guard<std::mutex> g(mLock);
  14.             mCookieToEventsMap.erase(cookie);
  15.         }
  16.         mCond.notify_one();
  17.     }
复制代码
这个地方就是对连续属性的取消订阅处置惩罚,从mCookieToEventsMap中移除。
5.2 取消订阅流程图

plantuml
  1. @startuml
  2. participant CarService
  3. box
  4. participant VehicleHalManager
  5. participant SubscriptionManager
  6. participant EmulatedVehicleHal
  7. participant RecurrentTimer
  8. endbox
  9. CarService -> VehicleHalManager: unsubscribe(const sp<IVehicleCallback>& callback,\n\t int32_t propId)
  10. VehicleHalManager -> SubscriptionManager: unsubscribe(getClientId(callback), propId)
  11. SubscriptionManager -> SubscriptionManager: propertyClients = getClientsForPropertyLocked(propId)
  12. alt client in mClients
  13.     SubscriptionManager -> SubscriptionManager: propertyClients->remove(client)
  14.     alt propertyClients->isEmpty()
  15.         SubscriptionManager -> SubscriptionManager: mPropToClients.erase(propId)
  16.     end
  17.     loop propClient in mPropToClients
  18.         alt client in propClient
  19.             SubscriptionManager -> SubscriptionManager: isClientSubscribedToOtherProps = true
  20.         end
  21.     end
  22.     alt isClientSubscribedToOtherProps == false
  23.         SubscriptionManager -> SubscriptionManager: client->getCallback()->\n\tunlinkToDeath(mCallbackDeathRecipient)
  24.     end
  25. end
  26. alt propertyClients == nullptr || propertyClients->isEmpty()
  27.     SubscriptionManager -> VehicleHalManager: onAllClientsUnsubscribed(propertyId)
  28.     VehicleHalManager -> EmulatedVehicleHal: unsubscribe(property)
  29.     alt isContinuousProperty
  30.         EmulatedVehicleHal -> RecurrentTimer: unregisterRecurrentEvent(property)
  31.         RecurrentTimer -> RecurrentTimer: mCookieToEventsMap.erase(cookie)
  32.     end
  33. end
  34. @enduml
复制代码
流程图:

6 属性上报流程

6.1 属性上报流程源码分析

  1. void onPropertyValueFromCar(const VehiclePropValue& value, bool updateStatus) override {
  2.     return this->onPropertyValue(value, updateStatus);
  3. }
复制代码
由于EmulatedVehicleConnector同时继承VehicleHalServer和VehicleHalClient,所以这个onPropertyValue继承于VehicleHalClient,调用的是VehicleHalClient中的onPropertyValue函数。
  1. void VehicleHalClient::onPropertyValue(const VehiclePropValue& value, bool updateStatus) {
  2.     if (!mPropCallback) {
  3.         LOG(ERROR) << __func__ << ": PropertyCallBackType is not registered!";
  4.         return;
  5.     }
  6.     return mPropCallback(value, updateStatus);
  7. }
复制代码
调用mPropCallback这个注册的回调函数,这个回调函数是:
  1. void EmulatedVehicleHal::onPropertyValue(const VehiclePropValue& value, bool updateStatus) {
  2.     VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(value);
  3.     if (mPropStore->writeValue(*updatedPropValue, updateStatus)) {
  4.         getEmulatorOrDie()->doSetValueFromClient(*updatedPropValue);
  5.         doHalEvent(std::move(updatedPropValue));
  6.     }
  7. }
复制代码
起首,将上报的属性写入缓存中。然后调用doSetValueFromClient
  1. void VehicleEmulator::doSetValueFromClient(const VehiclePropValue& propValue) {
  2.     vhal_proto::EmulatorMessage msg;
  3.     vhal_proto::VehiclePropValue* val = msg.add_value();
  4.     populateProtoVehiclePropValue(val, &propValue);
  5.     msg.set_status(vhal_proto::RESULT_OK);
  6.     msg.set_msg_type(vhal_proto::SET_PROPERTY_ASYNC);
  7.     mSocketComm->sendMessage(msg);
  8.     if (mPipeComm) {
  9.         mPipeComm->sendMessage(msg);
  10.     }
  11. }
复制代码
这里会通过SocketComm和PipeComm通知其他客户端。
然后会调用doHalEvent上报给CarService。
  1. void doHalEvent(VehiclePropValuePtr v) {
  2.     mOnHalEvent(std::move(v));
  3. }
复制代码
mOnHalEvent是VehicleHalManager:nHalEvent函数
  1. void VehicleHalManager::onHalEvent(VehiclePropValuePtr v) {
  2.     mEventQueue.push(std::move(v));
  3. }
复制代码
将VehiclePropValuePtr传入mEventQueue,这个是初始化的时候与BatchingConsumer中的mQueue绑定的一个queue,用于处置惩罚上报事件。同时BatchingConsumer这个类初始化的时候也会创建一个线程来处置惩罚上报事件,运行的函数为:
  1. void runInternal(const OnBatchReceivedFunc& onBatchReceived) {
  2.     if (mState.exchange(State::RUNNING) == State::INIT) {
  3.         while (State::RUNNING == mState) {
  4.             mQueue->waitForItems();
  5.             if (State::STOP_REQUESTED == mState) break;
  6.             std::this_thread::sleep_for(mBatchInterval);
  7.             if (State::STOP_REQUESTED == mState) break;
  8.             std::vector<T> items = mQueue->flush();
  9.             if (items.size() > 0) {
  10.                 onBatchReceived(items);
  11.             }
  12.         }
  13.     }
  14.     mState = State::STOPPED;
  15. }
  16. void waitForItems() {
  17.     std::unique_lock<std::mutex> g(mLock);
  18.     while (mQueue.empty() && mIsActive) {
  19.         mCond.wait(g);
  20.     }
  21. }
  22. std::vector<T> flush() {
  23.     std::vector<T> items;
  24.     MuxGuard g(mLock);
  25.     if (mQueue.empty() || !mIsActive) {
  26.         return items;
  27.     }
  28.     while (!mQueue.empty()) {
  29.         items.push_back(std::move(mQueue.front()));
  30.         mQueue.pop();
  31.     }
  32.     return items;
  33. }
  34. void push(T&& item) {
  35.     {
  36.         MuxGuard g(mLock);
  37.         if (!mIsActive) {
  38.             return;
  39.         }
  40.         mQueue.push(std::move(item));
  41.     }
  42.     mCond.notify_one();
  43. }
复制代码
当没有上报事件时,会waitForItems壅闭线程。如果有事件,则会在循环中处置惩罚,等待一个时间间隔mBatchInterval=10,如果在这个事件内没有上报事件,会等10s,如果有,则会在push的时候立马叫醒线程实行。
然后将queue中的所有事件都取出,调用回调函数处置惩罚,回调函数是:
  1. void VehicleHalManager::onBatchHalEvent(const std::vector<VehiclePropValuePtr>& values) {
  2.     const auto& clientValues =
  3.         mSubscriptionManager.distributeValuesToClients(values, SubscribeFlags::EVENTS_FROM_CAR);
  4.     for (const HalClientValues& cv : clientValues) {
  5.         auto vecSize = cv.values.size();
  6.         hidl_vec<VehiclePropValue> vec;
  7.         if (vecSize < kMaxHidlVecOfVehiclPropValuePoolSize) {
  8.             vec.setToExternal(&mHidlVecOfVehiclePropValuePool[0], vecSize);
  9.         } else {
  10.             vec.resize(vecSize);
  11.         }
  12.         int i = 0;
  13.         for (VehiclePropValue* pValue : cv.values) {
  14.             shallowCopy(&(vec)[i++], *pValue);
  15.         }
  16.         auto status = cv.client->getCallback()->onPropertyEvent(vec);
  17.         if (!status.isOk()) {
  18.             ALOGE("Failed to notify client %s, err: %s",
  19.                   toString(cv.client->getCallback()).c_str(),
  20.                   status.description().c_str());
  21.         }
  22.     }
  23. }
复制代码
先看下封装
  1. std::list<HalClientValues> SubscriptionManager::distributeValuesToClients(
  2.         const std::vector<recyclable_ptr<VehiclePropValue>>& propValues,
  3.         SubscribeFlags flags) const {
  4.     //创建一个map,key是HalClient,value是VehiclePropValue
  5.     std::map<sp<HalClient>, std::list<VehiclePropValue*>> clientValuesMap;
  6.     {
  7.         MuxGuard g(mLock);
  8.         //遍历所有的propValue
  9.         for (const auto& propValue: propValues) {
  10.             VehiclePropValue* v = propValue.get();
  11.             //获取所有订阅了该属性的客户端HalClient对象
  12.             auto clients = getSubscribedClientsLocked(v->prop, flags);
  13.             //遍历所有HalClient,并将其和propValue一起封装加入clientValuesMap中
  14.             for (const auto& client : clients) {
  15.                 clientValuesMap[client].push_back(v);
  16.             }
  17.         }
  18.     }
  19.         //遍历map中所有的对象,并封装成HalClientValues对象,存入clientValues中
  20.     std::list<HalClientValues> clientValues;
  21.     for (const auto& entry : clientValuesMap) {
  22.         clientValues.push_back(HalClientValues {
  23.             .client = entry.first,
  24.             .values = entry.second
  25.         });
  26.     }
  27.     return clientValues;
  28. }
  29. std::list<sp<HalClient>> SubscriptionManager::getSubscribedClientsLocked(
  30.     int32_t propId, SubscribeFlags flags) const {
  31.     std::list<sp<HalClient>> subscribedClients;
  32.        
  33.         //通过propId获取该id对应的HalClientVector对象
  34.     sp<HalClientVector> propClients = getClientsForPropertyLocked(propId);
  35.     if (propClients.get() != nullptr) {
  36.             //遍历HalClientVector中HalClient,并返回
  37.         for (size_t i = 0; i < propClients->size(); i++) {
  38.             const auto& client = propClients->itemAt(i);
  39.             if (client->isSubscribed(propId, flags)) {
  40.                 subscribedClients.push_back(client);
  41.             }
  42.         }
  43.     }
  44.     return subscribedClients;
  45. }
  46. sp<HalClientVector> SubscriptionManager::getClientsForPropertyLocked(
  47.         int32_t propId) const {
  48.     auto it = mPropToClients.find(propId);
  49.     return it == mPropToClients.end() ? nullptr : it->second;
  50. }
复制代码
对客户端和属性值进行封装,然后遍历封装后的数组,逐个调用其回调函数onPropertyEvent,这个就是客户端传入的回调函数。
6.2 连续属性上报流程源码分析

连续属性订阅之后,会根据传入的采样率转换后的频率进行上报,订阅时,将订阅事件保存在mCookieToEventsMap这个map中,并叫醒了处置惩罚线程。
这个线程是什么时候初始化,在实行什么呢?这个可以参考https://editor.csdn.net/md/?articleId=140752076
  1. void loop(const Action& action) {
  2.     static constexpr auto kInvalidTime = TimePoint(Nanos::max());
  3.     std::vector<int32_t> cookies;
  4.     while (!mStopRequested) {
  5.         auto now = Clock::now();
  6.         auto nextEventTime = kInvalidTime;
  7.         cookies.clear();
  8.         {
  9.             std::unique_lock<std::mutex> g(mLock);
  10.             for (auto&& it : mCookieToEventsMap) {
  11.                 RecurrentEvent& event = it.second;
  12.                 if (event.absoluteTime <= now) {
  13.                     event.updateNextEventTime(now);
  14.                     cookies.push_back(event.cookie);
  15.                 }
  16.                 if (nextEventTime > event.absoluteTime) {
  17.                     nextEventTime = event.absoluteTime;
  18.                 }
  19.             }
  20.         }
  21.         if (cookies.size() != 0) {
  22.             action(cookies);
  23.         }
  24.         std::unique_lock<std::mutex> g(mLock);
  25.         mCond.wait_until(g, nextEventTime);  // nextEventTime can be nanoseconds::max()
  26.     }
  27. }
复制代码
叫醒这个线程,并在这个内里从mCookieToEventsMap中取出RecurrentEvent,判断时间戳,如果已经到时了,则实行内里的action回调函数。
  1. void EmulatedVehicleHal::onContinuousPropertyTimer(const std::vector<int32_t>& properties) {
  2.     VehiclePropValuePtr v;
  3.     auto& pool = *getValuePool();
  4.     for (int32_t property : properties) {
  5.         if (isContinuousProperty(property)) {
  6.             auto internalPropValue = mPropStore->readValueOrNull(property);
  7.             if (internalPropValue != nullptr) {
  8.                 v = pool.obtain(*internalPropValue);
  9.             }
  10.         } else {
  11.             ALOGE("Unexpected onContinuousPropertyTimer for property: 0x%x", property);
  12.         }
  13.         if (v.get()) {
  14.             v->timestamp = elapsedRealtimeNano();
  15.             doHalEvent(std::move(v));
  16.         }
  17.     }
  18. }
复制代码
如果是连续属性,则从VehiclePropertyStore读取缓存,并调用doHalEvent往上报,这个和6.1节中的上报流程雷同。
6.3 属性上报流程图

plantuml
  1. @startuml
  2. participant CarService
  3. box
  4. participant EmulatedVehicleHal
  5. participant VehicleHalManager
  6. participant SubscriptionManager
  7. participant HalClient
  8. participant IPassThroughConnector
  9. participant VehicleHalClient
  10. participant VehiclePropertyStore
  11. participant VehicleEmulator
  12. participant SocketComm
  13. participant ConcurrentQueue
  14. participant BatchingConsumer
  15. endbox
  16. EmulatedVehicleHal -> IPassThroughConnector: onPropertyValueFromCar(*updatedPropValue, updateStatus)
  17. IPassThroughConnector -> VehicleHalClient: onPropertyValue(value, updateStatus)
  18. VehicleHalClient -> EmulatedVehicleHal: onPropertyValue(value, updateStatus)
  19. EmulatedVehicleHal -> VehiclePropertyStore: writeValue(*updatedPropValue, updateStatus)
  20. alt writeValue success
  21.     EmulatedVehicleHal -> VehicleEmulator: doSetValueFromClient(*updatedPropValue)
  22.     VehicleEmulator -> SocketComm: sendMessage(msg)
  23.     EmulatedVehicleHal -> EmulatedVehicleHal: doHalEvent(std::move(updatedPropValue))
  24.     EmulatedVehicleHal -> VehicleHalManager::onHalEvent(updatedPropValue)
  25.     VehicleHalManager -> VehicleHalManager: mEventQueue.push(std::move(updatedPropValue))
  26.     VehicleHalManager -> ConcurrentQueue: mQueue.push(updatedPropValue)
  27.     ConcurrentQueue -> ConcurrentQueue: mCond.notify_one()
  28.     ConcurrentQueue -> BatchingConsumer: runInternal(const OnBatchReceivedFunc& onBatchReceived)
  29.     BatchingConsumer -> VehicleHalManager: onBatchHalEvent(const std::vector<VehiclePropValuePtr>& values)
  30.     VehicleHalManager -> SubscriptionManager: distributeValuesToClients(values, \n\tSubscribeFlags::EVENTS_FROM_CAR)
  31.     SubscriptionManager -> VehicleHalManager: clientValues
  32.     loop cv in clientValues
  33.         VehicleHalManager -> HalClient: getCallback()
  34.         HalClient -> VehicleHalManager: callback
  35.         VehicleHalManager -> CarService: callback->onPropertyEvent(values)
  36.     end
  37. end
  38. @enduml
复制代码
流程图

连续属性上报流程图省略,大致和这个上面差不多,只是触发在定时器中。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

张春

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表