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

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 s
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值