Android Automotive(七) VehicleService

Android Automotive(七) VehicleService

VehicleService 是Android Automotive在硬件抽象层的一个核心native服务。处理和车辆相关功能,为系统提供获取车身信息以及设置相关状态的接口。

HAL接口

从Android O (8.0) 开始,Google推出了HIDL架构,HIDL定义的接口以.hal为后缀名。

定义了三个HIDL接口文件。

文件 说明
IVehicle.hal 接口定义
IVehicleCallback.hal 回调接口使用的数据结构
types.hal 车辆属性和数据定义

IVehicle

定义了Android Automtive在硬件抽象层和系统框架层的接口。实际也支持硬件抽象层-硬件抽象层、系统框架层-系统框架层的通信。

IVehicle代码路径:hardware/interfaces/automotive/vehicle/2.0/IVehicle.hal

package android.hardware.automotive.vehicle@2.0;

import IVehicleCallback;

interface IVehicle {
    
    
  /**
   * Returns a list of all property configurations supported by this vehicle
   * HAL.
   */
  getAllPropConfigs() generates (vec<VehiclePropConfig> propConfigs);

  /**
   * Returns a list of property configurations for given properties.
   *
   * If requested VehicleProperty wasn't found it must return
   * StatusCode::INVALID_ARG, otherwise a list of vehicle property
   * configurations with StatusCode::OK
   */
  getPropConfigs(vec<int32_t> props)
          generates (StatusCode status, vec<VehiclePropConfig> propConfigs);

  /**
   * Get a vehicle property value.
   *
   * For VehiclePropertyChangeMode::STATIC properties, this method must always
   * return the same value always.
   * For VehiclePropertyChangeMode::ON_CHANGE properties, it must return the
   * latest available value.
   *
   * Some properties like RADIO_PRESET requires to pass additional data in
   * GET request in VehiclePropValue object.
   *
   * If there is no data available yet, which can happen during initial stage,
   * this call must return immediately with an error code of
   * StatusCode::TRY_AGAIN.
   */
  get(VehiclePropValue requestedPropValue)
          generates (StatusCode status, VehiclePropValue propValue);

  /**
   * Set a vehicle property value.
   *
   * Timestamp of data must be ignored for set operation.
   *
   * Setting some properties require having initial state available. If initial
   * data is not available yet this call must return StatusCode::TRY_AGAIN.
   * For a property with separate power control this call must return
   * StatusCode::NOT_AVAILABLE error if property is not powered on.
   */
  set(VehiclePropValue propValue) generates (StatusCode status);

  /**
   * Subscribes to property events.
   *
   * Clients must be able to subscribe to multiple properties at a time
   * depending on data provided in options argument.
   *
   * @param listener This client must be called on appropriate event.
   * @param options List of options to subscribe. SubscribeOption contains
   *                information such as property Id, area Id, sample rate, etc.
   */
  subscribe(IVehicleCallback callback, vec<SubscribeOptions> options)
          generates (StatusCode status);

  /**
   * Unsubscribes from property events.
   *
   * If this client wasn't subscribed to the given property, this method
   * must return StatusCode::INVALID_ARG.
   */
  unsubscribe(IVehicleCallback callback, int32_t propId)
          generates (StatusCode status);

  /**
   * Print out debugging state for the vehicle hal.
   *
   * The text must be in ASCII encoding only.
   *
   * Performance requirements:
   *
   * The HAL must return from this call in less than 10ms. This call must avoid
   * deadlocks, as it may be called at any point of operation. Any synchronization
   * primitives used (such as mutex locks or semaphores) must be acquired
   * with a timeout.
   *
   */
  debugDump() generates (string s);
};
接口名称
getAllPropConfigs() generates (vec propConfigs); 获取全部车辆属性配置
getPropConfigs(vec<int32_t> props) generates (StatusCode status, vec propConfigs); 获取一个车辆属性配置
get(VehiclePropValue requestedPropValue) generates (StatusCode status, VehiclePropValue propValue); 获取一个车辆属性值
set(VehiclePropValue propValue) generates (StatusCode status); 设置一个车辆属性值
subscribe(IVehicleCallback callback, vec options) generates (StatusCode status); 订阅一个车辆属性变化
unsubscribe(IVehicleCallback callback, int32_t propId) generates (StatusCode status); 取消订阅一个车辆属性变化
debugDump() generates (string s); dump信息

IVehicleCallback

回调接口使用的数据结构

代码路径:

hardware/interfaces/automotive/vehicle/2.0/IVehicleCallback.hal

interface IVehicleCallback {
    
    

    /**
     * Event callback happens whenever a variable that the API user has
     * subscribed to needs to be reported. This may be based purely on
     * threshold and frequency (a regular subscription, see subscribe call's
     * arguments) or when the IVehicle#set method was called and the actual
     * change needs to be reported.
     *
     * These callbacks are chunked.
     *
     * @param values that has been updated.
     */
    oneway onPropertyEvent(vec<VehiclePropValue> propValues);

    /**
     * This method gets called if the client was subscribed to a property using
     * SubscribeFlags::EVENTS_FROM_ANDROID flag and IVehicle#set(...) method was called.
     *
     * These events must be delivered to subscriber immediately without any
     * batching.
     *
     * @param value Value that was set by a client.
     */
    oneway onPropertySet(VehiclePropValue propValue);

    /**
     * Set property value is usually asynchronous operation. Thus even if
     * client received StatusCode::OK from the IVehicle::set(...) this
     * doesn't guarantee that the value was successfully propagated to the
     * vehicle network. If such rare event occurs this method must be called.
     *
     * @param errorCode - any value from StatusCode enum.
     * @param property - a property where error has happened.
     * @param areaId - bitmask that specifies in which areas the problem has
     *                 occurred, must be 0 for global properties
     */
    oneway onPropertySetError(StatusCode errorCode,
                              int32_t propId,
                              int32_t areaId);
};
oneway onPropertyEvent(vec propValues); 车辆属性变化通知
oneway onPropertySet(VehiclePropValue propValue); 车辆属性设置通知
oneway onPropertySetError(StatusCode errorCode, int32_t propId, int32_t areaId); 车辆属性设置错误通知

types.hal

车辆属性和数据定义。

代码路径:hardware/interfaces/automotive/vehicle/2.0/types.hal

VehiclePropertyType enum
VehicleArea enum
VehiclePropertyGroup enum
VehicleProperty enum
VehicleVendorPermission enum
VehiclePropertyChangeMode enum
VehiclePropertyAccess enum
VehiclePropertyStatus enum
VehicleAreaSeat enum
VehicleAreaWindow enum
VehicleAreaDoor enum
VehicleAreaMirror enum
VehicleAreaWheel enum
VehicleAreaConfig struct
VehiclePropConfig struct
VehiclePropValue struct

编译模块

Android Automotive在硬件抽象层提供了很多模块,来支持系统编译和运行。

Module
[email protected]
vhal_v2_0_defaults
vhal_v2_0_target_defaults
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]

VehicleService

Android Automtive在硬件抽象层的主要服务。代码路径:hardware/interfaces/automotive/vehicle/2.0/default/VehicleService.cpp

启动

通过init.rc启动,init.rc配置在android.bp文件中

代码路径:hardware/interfaces/automotive/vehicle/2.0/default/Android.bp

cc_binary {
    
    
    name: "[email protected]",
    defaults: ["vhal_v2_0_target_defaults"],
    vintf_fragments: [
        "[email protected]",
    ],
    init_rc: ["[email protected]"],
    vendor: true,
    relative_install_path: "hw",
    srcs: ["VehicleService.cpp"],
    shared_libs: [
        "libbase",
        "libjsoncpp",
        "libprotobuf-cpp-lite",
    ],
    static_libs: [
        "[email protected]",
        "[email protected]",
        "[email protected]",
        "libqemu_pipe",
    ],
}

init_rc: ["[email protected]"]指定启动的配置文件。

rc文件:hardware/interfaces/automotive/vehicle/2.0/default/[email protected]

service vendor.vehicle-hal-2.0 /vendor/bin/hw/android.hardware.automotive.vehicle@2.0-service
    class hal
    user vehicle_network
    group system inet

VehicleService::main

VehicleService启动的主函数就是main方法。

int main(int /* argc */, char* /* argv */ []) {
    auto store = std::make_unique<VehiclePropertyStore>(); //初始化VehiclePropertyStore
    auto connector = impl::makeEmulatedPassthroughConnector(); //创建一个连接者 EmulatedPassthroughConnector
    auto userHal = connector->getEmulatedUserHal(); //获取getEmulatedUserHal
    auto hal = std::make_unique<impl::EmulatedVehicleHal>(store.get(), connector.get(), userHal); //初始化EmulatedVehicleHal
    auto emulator = std::make_unique<impl::VehicleEmulator>(hal.get()); //初始化VehicleEmulator
    auto service = std::make_unique<VehicleHalManager>(hal.get()); //初始化VehicleHalManager
    connector->setValuePool(hal->getValuePool()); //创建value池

    configureRpcThreadpool(4, false /* callerWillJoin */); //初始化rpc线程池

    status_t status = service->registerAsService();

    if (status != OK) {
        ALOGE("Unable to register vehicle service (%d)", status);
        return 1;
    }

    // Setup a binder thread pool to be a car watchdog client.
    ABinderProcess_setThreadPoolMaxThreadCount(1); //初始化Binder线程池
    ABinderProcess_startThreadPool();
    sp<Looper> looper(Looper::prepare(0 /* opts */)); //初始化looper
    std::shared_ptr<WatchdogClient> watchdogClient =
            ndk::SharedRefBase::make<WatchdogClient>(looper, service.get()); //初始化watchdog
    // The current health check is done in the main thread, so it falls short of capturing the real
    // situation. Checking through HAL binder thread should be considered.
    if (!watchdogClient->initialize()) {
        ALOGE("Failed to initialize car watchdog client");
        return 1;
    }
    ALOGI("Ready");
    while (true) {
        looper->pollAll(-1 /* timeoutMillis */); //启动looper
    }

    return 1;
}
  1. 初始化VehiclePropertyStore,得到store指针
  2. 创建一个连接者 EmulatedPassthroughConnector
  3. 获取getEmulatedUserHal
  4. 初始化EmulatedVehicleHal,得到hal指针,初始化时,将VehiclePropertyStore指针作为参数传输了EmulatedVehicleHal构造方法中
  5. 初始化VehicleEmulator,得到emulator指针,初始化时,将EmulatedVehicleHal指针作为参数传入VehicleEmulator的构造方法中。
  6. 初始化VehicleHalManager,获得service智能指针。VehicleHalManager继承自IVehicle hidl接口,该接口在编译的时候自动生成了registerAsService方法,该方法就是将服务本身通过binder注册到hwservicemanager里面供其他进程连接。
  7. 创建value
  8. 初始化RPC线程池
  9. 初始化Binder线程池
  10. 初始化looper
  11. 初始化watchdog
  12. 启动looper

VehiclePropertyStore

用于记录和存储车辆属性。相当一个数据容器,保存了所有车辆属性的配置以及值的记录。

代码路径:

hardware/interfaces/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehiclePropertyStore.h

hardware/interfaces/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp

#ifndef android_hardware_automotive_vehicle_V2_0_impl_PropertyDb_H_
#define android_hardware_automotive_vehicle_V2_0_impl_PropertyDb_H_

#include <cstdint>
#include <unordered_map>
#include <memory>
#include <mutex>

#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>

namespace android {
namespace hardware {
namespace automotive {
namespace vehicle {
namespace V2_0 {

/**
 * Encapsulates work related to storing and accessing configuration, storing and modifying
 * vehicle property values.
 *
 * VehiclePropertyValues stored in a sorted map thus it makes easier to get range of values, e.g.
 * to get value for all areas for particular property.
 *
 * This class is thread-safe, however it uses blocking synchronization across all methods.
 */
class VehiclePropertyStore {
public:
    /* Function that used to calculate unique token for given VehiclePropValue */
    using TokenFunction = std::function<int64_t(const VehiclePropValue& value)>;

private:
    struct RecordConfig { //一条记录
        VehiclePropConfig propConfig; //propConfig
        TokenFunction tokenFunction; //propValue
    };

    struct RecordId {
        int32_t prop; //prop
        int32_t area; //area
        int64_t token; //token

        bool operator==(const RecordId& other) const; // ==重载操作符
        bool operator<(const RecordId& other) const; // <重载操作符
    };

    using PropertyMap = std::map<RecordId, VehiclePropValue>; //recordId和vehiclePropValue的map
    using PropertyMapRange = std::pair<PropertyMap::const_iterator, PropertyMap::const_iterator>; //将两个数据合成一个返回

public:
    void registerProperty(const VehiclePropConfig& config, TokenFunction tokenFunc = nullptr); //注册一个车辆属性

    /* Stores provided value. Returns true if value was written returns false if config for
     * example wasn't registered. */
    bool writeValue(const VehiclePropValue& propValue, bool updateStatus); //写一个值

    void removeValue(const VehiclePropValue& propValue); //移除一个值
    void removeValuesForProperty(int32_t propId); //移除一个值用propId

    std::vector<VehiclePropValue> readAllValues() const; // 读取所有的值
    std::vector<VehiclePropValue> readValuesForProperty(int32_t propId) const; //读取一个值
    std::unique_ptr<VehiclePropValue> readValueOrNull(const VehiclePropValue& request) const; //读取一个值
    std::unique_ptr<VehiclePropValue> readValueOrNull(int32_t prop, int32_t area = 0,
                                                      int64_t token = 0) const; //读取一个值

    std::vector<VehiclePropConfig> getAllConfigs() const; //获取全部的配置
    const VehiclePropConfig* getConfigOrNull(int32_t propId) const; //VehiclePropConfig
    const VehiclePropConfig* getConfigOrDie(int32_t propId) const; //VehiclePropConfig

private:
    RecordId getRecordIdLocked(const VehiclePropValue& valuePrototype) const; //获取RecordId
    const VehiclePropValue* getValueOrNullLocked(const RecordId& recId) const; //获取VehiclePropValue
    PropertyMapRange findRangeLocked(int32_t propId) const; //获取PropertyMapRange

private:
    using MuxGuard = std::lock_guard<std::mutex>; //锁
    mutable std::mutex mLock;
    std::unordered_map<int32_t /* VehicleProperty */, RecordConfig> mConfigs;

    PropertyMap mPropertyValues;  // Sorted map of RecordId : VehiclePropValue.
};

}  // namespace V2_0
}  // namespace vehicle
}  // namespace automotive
}  // namespace hardware
}  // namespace android

#endif //android_hardware_automotive_vehicle_V2_0_impl_PropertyDb_H_
类型 名称
数据结构 RecordConfig
数据结构 RecordId
方法 registerProperty
方法 writeValue
方法 removeValue
方法 removeValuesForProperty
方法 readAllValues
方法 readValuesForProperty
方法 readValueOrNull
方法 readValueOrNull
方法 getAllConfigs
方法 getConfigOrNull
方法 getConfigOrDie
属性 mLock
属性 mConfigs
属性 mPropertyValues
方法 getRecordIdLocked
方法 getValueOrNullLocked
方法 findRangeLocked

VehiclePropertyStore::RecordConfig

属性记录配置

struct RecordConfig { //一条记录
    VehiclePropConfig propConfig; //propConfig
    TokenFunction tokenFunction; //propValue
};

VehiclePropertyStore::RecordId

属性记录

struct RecordId {
    int32_t prop; //prop
    int32_t area; //area
    int64_t token; //token

    bool operator==(const RecordId& other) const; // ==重载操作符
    bool operator<(const RecordId& other) const; // <重载操作符
};

VehiclePropertyStore::mPropertyValues

定义了一个PropertyMap的map表来保存属性值。

using PropertyMap = std::map<RecordId, VehiclePropValue>;
PropertyMap mPropertyValues;  // Sorted map of RecordId : VehiclePropValue.

VehiclePropertyStore::mConfigs

定义了一个无序map来保存属性配置

std::unordered_map<int32_t /* VehicleProperty */, RecordConfig> mConfigs;

VehiclePropertyStore::mLock

一个锁

VehiclePropertyStore::registerProperty

注册一个车辆属性

void VehiclePropertyStore::registerProperty(const VehiclePropConfig& config,
                                            VehiclePropertyStore::TokenFunction tokenFunc) {
    
    
    MuxGuard g(mLock);
    ALOGW("%s: mConfigs : 0x%x", __func__, config.prop);
    //很简单,mConfigs键值对插入key为config.prop, 值为RecordConfig, RecordConfig是个结构体,成员就是VehiclePropConfig跟一个函数指针。
    mConfigs.insert({
    
     config.prop, RecordConfig {
    
     config, tokenFunc } }); //注册property
}

VehiclePropertyStore::writeValue

写入属性值

bool VehiclePropertyStore::writeValue(const VehiclePropValue& propValue,
                                        bool updateStatus) {
    
    
    MuxGuard g(mLock);
    //首先从键值对的key集合里面查看是否当前需要写入属性值的属性id是否已经注册,如果当前属性id没有注册,则返回false,写入失败。
    if (!mConfigs.count(propValue.prop)) return false; //不包含属性返回

    RecordId recId = getRecordIdLocked(propValue); //获取RecordId
    //根据RecordId从map中获取Value值
    VehiclePropValue* valueToUpdate = const_cast<VehiclePropValue*>(getValueOrNullLocked(recId));
    //如果当前没有保存该属性,则加入一条新的记录,否则的话,更新对应的值
    if (valueToUpdate == nullptr) {
    
    
        mPropertyValues.insert({
    
     recId, propValue });
        //插入更新的值
        ALOGW("%s: mPropertyValues : 0x%x", __func__, recId.prop);
        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) {
    
    
        ALOGW("%s: valueToUpdate : 0x%x", __func__, recId.prop);
        //更新状态
        valueToUpdate->status = propValue.status;
    }
    return true;
}

VehiclePropertyStore::removeValue

移除一个VehiclePropValue

VehiclePropertyStore::removeValuesForProperty

根据propertyId移除一个VehiclePropValue

VehiclePropertyStore::readAllValues

读取全部的VehiclePropValue

VehiclePropertyStore::readValuesForProperty

根据propertyId读取VehiclePropValue

VehiclePropertyStore::readValueOrNull

读取一个VehiclePropValue

VehiclePropertyStore::getAllConfigs

获取全部的RecordConfig

VehiclePropertyStore::getConfigOrNull

获取一个RecordConfig

VehiclePropertyStore::getConfigOrDie

获取一个RecordConfig

DefaultConfig

定义车辆属性的配置,避免冲枚举到整型int的转换。

所有的配置都存储在kVehicleProperties数组中。

代码路径:automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h

const ConfigDeclaration kVehicleProperties[]{
        {.config =
                 {
                         .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
                         .access = VehiclePropertyAccess::READ,
                         .changeMode = VehiclePropertyChangeMode::STATIC,
                 },
         .initialValue = {.floatValues = {15000.0f}}},

EmulatedVehicleConnector

一个虚拟的VehicleService的连接器,里面实现了VehicleHalClientVehicleHalServer

#ifndef android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleConnector_H_
#define android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleConnector_H_

#include <vhal_v2_0/VehicleConnector.h>

#include "VehicleHalClient.h"
#include "VehicleHalServer.h"

namespace android {
namespace hardware {
namespace automotive {
namespace vehicle {
namespace V2_0 {

namespace impl {

using PassthroughConnector = IPassThroughConnector<VehicleHalClient, VehicleHalServer>;
using PassthroughConnectorPtr = std::unique_ptr<PassthroughConnector>;

PassthroughConnectorPtr makeEmulatedPassthroughConnector();

}  // namespace impl

}  // namespace V2_0
}  // namespace vehicle
}  // namespace automotive
}  // namespace hardware
}  // namespace android

#endif  // android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleConnector_H_

VehicleConnector

VehicleConnector这里的继承关系有点复杂

//EmulatedVehicleConnector.cpp
	class EmulatedPassthroughConnector : public PassthroughConnector
//EmulatedVehicleConnector.h
	using PassthroughConnector = IPassThroughConnector<VehicleHalClient, VehicleHalServer>;
//VehicleConnector.h
	template <typename VehicleClientType, typename VehicleServerType>
	class IPassThroughConnector : public VehicleClientType, public VehicleServerType {

也就是说**EmulatedVehicleConnector继承了VehicleHalClientVehicleHalServer**

这里对一些方法做了实现

StatusCode setProperty(const VehiclePropValue& value, bool updateStatus) override {
    return this->onSetProperty(value, updateStatus);
}

void onPropertyValueFromCar(const VehiclePropValue& value, bool updateStatus) override {
    return this->onPropertyValue(value, updateStatus);
}

当调用setProperty时会执行到VehicleHalServeronSetProperty方法。

当调用onPropertyValueFromCar时会执行到VehicleHalClientonPropertyValue方法。

VehicleHalServer

这包含本机和虚拟化 VHAL 服务器将使用的常见服务器操作。请注意,在虚拟化方案中,服务器可能在与 Android 不同的操作系统上运行。

代码路径:

hardware/interfaces/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleServer.h

hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h

hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp

继承关系:VehicleServer <-- VehicleHalServer <-- VehicleHalServer

类型 名称
方法 onGetAllPropertyConfig
方法 onSetProperty
方法 onPropertyValueFromCar
方法 onDump
方法 setValuePool
方法 getEmulatedUserHal
方法 getGenerator
方法 getValuePool
方法 onFakeValueGenerated
方法 handleGenerateFakeDataRequest
方法 createApPowerStateReq
方法 createHwInputKeyProp
属性 mEmulatedUserHal
属性 mGeneratorHub
属性 mValuePool
#pragma once

#include <vhal_v2_0/VehicleObjectPool.h>
#include <vhal_v2_0/VehicleServer.h>

#include "EmulatedUserHal.h"
#include "GeneratorHub.h"

namespace android::hardware::automotive::vehicle::V2_0::impl {

// This contains the common server operations that will be used by
// both native and virtualized VHAL server. Notice that in the virtualized
// scenario, the server may be run on a different OS than Android.
class VehicleHalServer : public IVehicleServer {
  public:
    // Methods from IVehicleServer

    std::vector<VehiclePropConfig> onGetAllPropertyConfig() const override;

    StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) override;

    // Set the Property Value Pool used in this server
    void setValuePool(VehiclePropValuePool* valuePool);

    EmulatedUserHal* getEmulatedUserHal();

  private:
    using VehiclePropValuePtr = recyclable_ptr<VehiclePropValue>;

    GeneratorHub* getGenerator();

    VehiclePropValuePool* getValuePool() const;

    void onFakeValueGenerated(const VehiclePropValue& value);

    StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request);

    VehiclePropValuePtr createApPowerStateReq(VehicleApPowerStateReq req, int32_t param);

    VehiclePropValuePtr createHwInputKeyProp(VehicleHwKeyInputAction action, int32_t keyCode,
                                             int32_t targetDisplay);

    // data members

  protected:
    EmulatedUserHal mEmulatedUserHal;

  private:
    GeneratorHub mGeneratorHub{
            std::bind(&VehicleHalServer::onFakeValueGenerated, this, std::placeholders::_1)};

    VehiclePropValuePool* mValuePool{nullptr};
};

}  // namespace android::hardware::automotive::vehicle::V2_0::impl
  • VehicleHalServer::onSetProperty
StatusCode VehicleHalServer::onSetProperty(const VehiclePropValue& value, bool updateStatus) {
     
    //......

    // Some properties need to be treated non-trivially

    // 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会将变化通知回VehicleHalClient

void onPropertyValueFromCar(const VehiclePropValue& value, bool updateStatus) override {
    return this->onPropertyValue(value, updateStatus);
}

VehicleHalClient

本机和虚拟化 VHAL 客户端可能使用的常见客户端操作。

代码路径:

hardware/interfaces/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleClient.h

hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.h

hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.cpp

继承关系:VehicleClient <-- VehicleHalClient <-- VehicleHalClient

类型 名称
方法 VehicleHalClient
方法 setProperty
方法 onPropertyValue
方法 dump
方法 onPropertyValue
方法 registerPropertyValueCallback
属性 PropertyCallBackType
#pragma once

#include <vhal_v2_0/VehicleClient.h>

namespace android::hardware::automotive::vehicle::V2_0::impl {

// The common client operations that may be used by both native and
// virtualized VHAL clients.
class VehicleHalClient : public IVehicleClient {
  public:
    // Type of callback function for handling the new property values
    using PropertyCallBackType = std::function<void(const VehiclePropValue&, bool updateStatus)>;

    // Method from IVehicleClient
    void onPropertyValue(const VehiclePropValue& value, bool updateStatus) override;

    void registerPropertyValueCallback(PropertyCallBackType&& callback);

  private:
    PropertyCallBackType mPropCallback;
};

}  // namespace android::hardware::automotive::vehicle::V2_0::impl

EmulatedUserHal

用于通过lshal 调试请求模拟用户 HAL 行为的类。

EmulatedVehicleHal

实现了连接到仿真器而不是实车网络的车载HAL ,仿真器的实现逻辑与实际的逻辑相同。

代码路径 hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp

hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h

#ifndef android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleHal_H_
#define android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleHal_H_

#include <map>
#include <memory>
#include <sys/socket.h>
#include <thread>
#include <unordered_set>

#include <utils/SystemClock.h>

#include <vhal_v2_0/RecurrentTimer.h>
#include <vhal_v2_0/VehicleHal.h>
#include "vhal_v2_0/VehiclePropertyStore.h"

#include "DefaultConfig.h"
#include "EmulatedUserHal.h"
#include "EmulatedVehicleConnector.h"
#include "GeneratorHub.h"
#include "VehicleEmulator.h"

namespace android {
namespace hardware {
namespace automotive {
namespace vehicle {
namespace V2_0 {

namespace impl {

/** Implementation of VehicleHal that connected to emulator instead of real vehicle network. */
class EmulatedVehicleHal : public EmulatedVehicleHalIface {
public:
    EmulatedVehicleHal(VehiclePropertyStore* propStore, VehicleHalClient* client,
                       EmulatedUserHal* emulatedUserHal = nullptr);
    ~EmulatedVehicleHal() = default;

    //  Methods from VehicleHal
    void onCreate() override;
    std::vector<VehiclePropConfig> listProperties() override;
    VehiclePropValuePtr get(const VehiclePropValue& requestedPropValue,
                            StatusCode* outStatus) override;
    StatusCode set(const VehiclePropValue& propValue) override;
    StatusCode subscribe(int32_t property, float sampleRate) override;
    StatusCode unsubscribe(int32_t property) override;
    bool dump(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;

    //  Methods from EmulatedVehicleHalIface
    bool setPropertyFromVehicle(const VehiclePropValue& propValue) override;
    std::vector<VehiclePropValue> getAllProperties() const override;
    void getAllPropertiesOverride();

private:
    constexpr std::chrono::nanoseconds hertzToNanoseconds(float hz) const {
        return std::chrono::nanoseconds(static_cast<int64_t>(1000000000L / hz));
    }

    StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request);
    void onPropertyValue(const VehiclePropValue& value, bool updateStatus);

    void onContinuousPropertyTimer(const std::vector<int32_t>& properties);
    bool isContinuousProperty(int32_t propId) const;
    void initStaticConfig();
    void initObd2LiveFrame(const VehiclePropConfig& propConfig);
    void initObd2FreezeFrame(const VehiclePropConfig& propConfig);
    StatusCode fillObd2FreezeFrame(const VehiclePropValue& requestedPropValue,
                                   VehiclePropValue* outValue);
    StatusCode fillObd2DtcInfo(VehiclePropValue* outValue);
    StatusCode clearObd2FreezeFrames(const VehiclePropValue& propValue);

    /* Private members */
    VehiclePropertyStore* mPropStore;
    std::unordered_set<int32_t> mHvacPowerProps;
    RecurrentTimer mRecurrentTimer;
    VehicleHalClient* mVehicleClient;
    bool mInEmulator;
    bool mInitVhalValueOverride;
    std::vector<VehiclePropValue> mVehiclePropertiesOverride;
    EmulatedUserHal* mEmulatedUserHal;
};

}  // impl

}  // namespace V2_0
}  // namespace vehicle
}  // namespace automotive
}  // namespace hardware
}  // namespace android


#endif  // android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleHal_H_

属性接口

类型 名称
方法 onCreate
方法 listProperties
方法 get
方法 set
方法 subscribe
方法 unsubscribe
方法 dump
方法 setPropertyFromVehicle
方法 getAllProperties
方法 getAllPropertiesOverride
方法 handleGenerateFakeDataRequest
方法 onPropertyValue
方法 onContinuousPropertyTimer
方法 isContinuousProperty
方法 initStaticConfig
方法 initObd2LiveFrame
方法 initObd2FreezeFrame
方法 fillObd2FreezeFrame
方法 fillObd2DtcInfo
方法 clearObd2FreezeFrames
属性 mPropStore
属性 mHvacPowerProps
属性 mRecurrentTimer
属性 mVehicleClient
属性 mInEmulator
属性 mInitVhalValueOverride
属性 mVehiclePropertiesOverride
属性 mEmulatedUserHal

EmulatedVehicleHal::EmulatedVehicleHal

EmulatedVehicleHal继承EmulatedVehicleHalIface,而EmulatedVehicleHalIface继承VehicleHalVehicleHal定义了和IVehicle中同样的接口,也就是说EmulatedVehicleHalIVehcle中的接口做了实现。

EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore, VehicleHalClient* client,
                                       EmulatedUserHal* emulatedUserHal)
    : mPropStore(propStore),
      mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)),
      //mRecurrentTimer是一个工具类,内部维护一个线程,用来处理指定时间触发的事件,这个跟上层的Handler比较类似。
      mRecurrentTimer(std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this,
                                std::placeholders::_1)),
      mVehicleClient(client),
      mEmulatedUserHal(emulatedUserHal) {
    //注册DefaultConfig.h中定义的属性值
    initStaticConfig();
    for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
        mPropStore->registerProperty(kVehicleProperties[i].config);
    }
    mVehicleClient->registerPropertyValueCallback(std::bind(&EmulatedVehicleHal::onPropertyValue,
                                                            this, std::placeholders::_1,
                                                            std::placeholders::_2));

    mInitVhalValueOverride =
            android::base::GetBoolProperty("persist.vendor.vhal_init_value_override", false);
    if (mInitVhalValueOverride) {
        getAllPropertiesOverride();
    }
}
  1. auto hal = std::make_unique<impl::EmulatedVehicleHal>(store.get(), connector.get(), userHal);前面在VehicleService中创建EmulatedVehicleHal时,传入了前面创建的三个变量。

  2. mPropStore(propStore) 存储车辆属性变化的一个容器。

  3. mVehicleClient(client) 回调通知用的

  4. mRecurrentTimer(std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this一个处理持续变化Continuous车辆属性的计时器。

  5. initStaticConfig() 初始化车辆属性的配置

    void EmulatedVehicleHal::initStaticConfig() {
        for (auto&& it = std::begin(kVehicleProperties); it != std::end(kVehicleProperties); ++it) {
            const auto& cfg = it->config;
            VehiclePropertyStore::TokenFunction tokenFunction = nullptr;
    
            switch (cfg.prop) {
                case OBD2_FREEZE_FRAME: {
                    tokenFunction = [](const VehiclePropValue& propValue) {
                        return propValue.timestamp;
                    };
                    break;
                }
                default:
                    break;
            }
    
            mPropStore->registerProperty(cfg, tokenFunction);
        }
    }
    

    kVehicleProperties定义在DefaultConfig.h中,保存所有支持的车辆属性配置。

    mPropStore->registerProperty(cfg, tokenFunction)将所有的初始化配置存入mPropStore容器。

  6. mPropStore->registerProperty(kVehicleProperties[i].config)initStaticConfig好像重复了。

  7. mVehicleClient->registerPropertyValueCallback(std::bind(&EmulatedVehicleHal::onPropertyValue,callback函数注册给mVehicleClient。回调时会触发onPropertyValue

  8. getAllPropertiesOverride更新一些需要重写的车辆属性配置。

EmulatedVehicleHal::get

获取一个车辆属性值

VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get(
        const VehiclePropValue& requestedPropValue, StatusCode* outStatus) {
    //当前我们要拿的属性值的属性ID是多少
    auto propId = requestedPropValue.prop;
    ALOGV("get(%d)", propId);
    //这个pool是一个用于存储VehiclePropValue的对象池,这个跟Message的实现好像。
    auto& pool = *getValuePool();
    VehiclePropValuePtr v = nullptr;
    //这个就是根据propId来获取值了,OBD2_FREEZE_FRAME是OBD检测到故障信息,
    //OBD2_FREEZE_FRAME_INFO是故障检测到得时间戳。一般要获取OBD2_FREEZE_FRAME的数据之前,都要通过OBD2_FREEZE_FRAME_INFO获取时间戳。
    //除了这两个属性值,其他的都直接从临时的Store里面获取当前属性的状态值。
    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;
}
  1. auto internalPropValue = mPropStore->readValueOrNull(requestedPropValue)这里从mPropStrore中取一个车辆属性,也就是从维护的数据容器中获取对应车辆属性的值。
  2. v->timestamp = elapsedRealtimeNano();更新获取当前车辆属性的时间戳。

EmulatedVehicleHal::set

设置一个车辆属性值,先将属性值写入到内存中保存,然后再通知车身更新该属性值,doSetValueFromClient这个函数就实现了相关的功能,这里暂且按下不表。这个set事件是来自客户端的调用,那车身信息如果发生变化时,如何set呢,答案是该模块还有一个名称setPropertyFromVehicle的函数,正是这个函数实现了车身数据变化之后,更新缓存的属性,并通知上层。

StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) {
    //这个常量定义为false,是因为这个set函数是给上层调用的,Android层
    //不能够改变属性值的状态,只有车身发送了该属性值过来了,才可改变属性状态,这个在下面会有体现。
    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)) {
        //这里是判断当前属性值是否属于空调电源开关,如果是的情况下,去拿它值,如果当前开关没开,则返回当前状态不可用,设置失败的CODE
        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;
        }
    }
    //status默认值为AVAILABLE
    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;
    }
    //读取该属性值id的当前存储的Prop
    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;
    }

    if (mInEmulator && propValue.prop == toInt(VehicleProperty::DISPLAY_BRIGHTNESS)) {
        // Emulator does not support remote brightness control, b/139959479
        // do not send it down so that it does not bring unnecessary property change event
        // return other error code, such NOT_AVAILABLE, causes Emulator to be freezing
        // TODO: return StatusCode::NOT_AVAILABLE once the above issue is fixed
        return StatusCode::OK;
    }

    /**
     * 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
    //通知汽车,设置属性值,这里是告诉模拟器,该值需要重新设置,调用的这个函数等下再说。
    auto setValueStatus = mVehicleClient->setProperty(propValue, updateStatus);
    if (setValueStatus != StatusCode::OK) {
        return setValueStatus;
    }

    return StatusCode::OK;
}
  1. auto currentPropValue = mPropStore->readValueOrNull(propValue);从数据容器中读取一下当前的车辆属性值。

  2. 在检查了所有条件(例如属性是否可用)后,真正的vhal会将事件发送到车辆的ECU以采取行动。

    /**
    * After checking all conditions, such as the property is available, a real vhal will
    * sent the events to Car ECU to take actions.
    */
    
  3. auto setValueStatus = mVehicleClient->setProperty(propValue, updateStatus)这里实际是将值发送到车辆服务,服务将与(真实或模拟的)发送给汽车。
    这里对车辆属性的设置实际交给VehicleHalClient处理
    VehicleHalClient实际是VehicleConnector对象,最后会调用VehicleServeronSetProperty方法。

EmulatedVehicleHal::subscribe

订阅车辆属性

StatusCode EmulatedVehicleHal::subscribe(int32_t property, float sampleRate) {
    ALOGI("%s propId: 0x%x, sampleRate: %f", __func__, property, sampleRate);

    if (isContinuousProperty(property)) {// sampleRate是属性值更新的频率
        mRecurrentTimer.registerRecurrentEvent(hertzToNanoseconds(sampleRate), property);
    }
    return StatusCode::OK;
}
  1. isContinuousProperty主要是判断该属性值的change类型是不是连续类型的,如果是连续类型Continuous的,就向RecurrentTimer中注册事件
    RecurrentTimer是一个工具类,可以把它理解为一个另类的Handler, 其内部运行着一个线程维护着一个循环,当向其注册一个事件时,内部根据事件频率算出触发事件的事件,然后定期触发回调方法,跟Handler唯一不同的是,Handler的sendMesssageAtTime发完就没了,这个RecurrentTimer是如果你注册了事件,如果不取消注册,则事件会一直定期触发。

EmulatedVehicleHal::unsubscribe

取消订阅一个车辆属性

StatusCode EmulatedVehicleHal::unsubscribe(int32_t property) {
    
    
    ALOGI("%s propId: 0x%x", __func__, property);
    if (isContinuousProperty(property)) {
    
    
        mRecurrentTimer.unregisterRecurrentEvent(property);
    }
    return StatusCode::OK;
}

EmulatedVehicleHal::onContinuousPropertyTimer

订阅了一个车辆,当达到时间后会触发onContinuousPropertyTimer,这个函数指针在EmulatedVehicleHal初始化的时候,就作为参数传给RecurrentTimer,然后在这个函数中调用 doHalEvent(std::move(v)); 触发回调事件,将属性值上报。

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));
        }
    }
}

代码路径:automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h

void doHalEvent(VehiclePropValuePtr v) {
    mOnHalEvent(std::move(v));//vehiclehal.h
}

mOnHalEvent是一个函数指针,其对应函数定义在VehicleHalManager中,如下

void VehicleHalManager::onHalEvent(VehiclePropValuePtr v) {
    mEventQueue.push(std::move(v));
}

最终由BatchingConsumer取出该事件,回调给上层;mOnHalEvent函数指针在VehicleHalManager初始化的时候,会将其作为参数传给EmulatedVehicleHal

mHal->init(&mValueObjectPool,
               std::bind(&VehicleHalManager::onHalEvent, this, _1),
               std::bind(&VehicleHalManager::onHalPropertySetError, this,
                         _1, _2, _3));

EmulatedVehicleHal::onPropertyValue

当车辆属性值发生变化时,会执行此方法进行通知。

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));
    }
}

doHalEvent(std::move(updatedPropValue));同上,最后也会由VehicleHalManager回调上层。

该方法的注册在EmulatedVehicleHal的构造函数中。

mVehicleClient->registerPropertyValueCallback(std::bind(&EmulatedVehicleHal::onPropertyValue,
                                                            this, std::placeholders::_1,
                                                            std::placeholders::_2));

当被调用VehicleHalClientonPropertyValue函数时,则会执行EmulatedVehicleHalonPropertyValue


VehicleHalManager

VehicleHalManager 是实现了IVehicle接口的类,处理HIDL接口调用的逻辑。

VehicleHalManager继承自IVehicle hidl接口,该接口在编译的时候自动生成了registerAsService方法,该方法就是将服务本身通过binder注册到hwservicemanager里面供其他进程连接。VehicleHalManager实际就是HIDL中IVehicle的服务端,它实现了IVehicle定义的接口。

  • getAllPropConfigs
    获取所有的车辆属性配置
  • getPropConfigs
    获取对应车辆属性的配置
  • set
    设置车辆属性值
  • get
    获取车辆属性值
#ifndef android_hardware_automotive_vehicle_V2_0_VehicleHalManager_H_
#define android_hardware_automotive_vehicle_V2_0_VehicleHalManager_H_

#include <inttypes.h>
#include <stdint.h>
#include <sys/types.h>

#include <list>
#include <map>
#include <memory>
#include <set>

#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>

#include "ConcurrentQueue.h"
#include "SubscriptionManager.h"
#include "VehicleHal.h"
#include "VehicleObjectPool.h"
#include "VehiclePropConfigIndex.h"

namespace android {
namespace hardware {
namespace automotive {
namespace vehicle {
namespace V2_0 {

/**
 * This class is a thick proxy between IVehicle HIDL interface and vendor's implementation.
 *
 * It has some boilerplate code like batching and caching property values, checking permissions,
 * etc. Vendors must implement VehicleHal class.
 */
class VehicleHalManager : public IVehicle {
public:
    VehicleHalManager(VehicleHal* vehicleHal)
        : mHal(vehicleHal),
          mSubscriptionManager(std::bind(&VehicleHalManager::onAllClientsUnsubscribed,
                                         this, std::placeholders::_1)) {
        init();
    }

    virtual ~VehicleHalManager();

    void init();

    // ---------------------------------------------------------------------------------------------
    // Methods derived from IVehicle
    Return<void> getAllPropConfigs(getAllPropConfigs_cb _hidl_cb)  override;
    Return<void> getPropConfigs(const hidl_vec<int32_t>& properties,
                                getPropConfigs_cb _hidl_cb)  override;
    Return<void> get(const VehiclePropValue& requestedPropValue,
                     get_cb _hidl_cb)  override;
    Return<StatusCode> set(const VehiclePropValue& value)  override;
    Return<StatusCode> subscribe(const sp<IVehicleCallback>& callback,
                                const hidl_vec<SubscribeOptions>& options)  override;
    Return<StatusCode> unsubscribe(const sp<IVehicleCallback>& callback,
                                   int32_t propId)  override;
    Return<void> debugDump(debugDump_cb _hidl_cb = nullptr) override;

    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;

  private:
    using VehiclePropValuePtr = VehicleHal::VehiclePropValuePtr;
    // Returns true if needs to call again shortly.
    using RetriableAction = std::function<bool()>;

    // ---------------------------------------------------------------------------------------------
    // Events received from VehicleHal
    void onHalEvent(VehiclePropValuePtr  v);
    void onHalPropertySetError(StatusCode errorCode, int32_t property,
                               int32_t areaId);

    // ---------------------------------------------------------------------------------------------
    // This method will be called from BatchingConsumer thread
    void onBatchHalEvent(const std::vector<VehiclePropValuePtr >& values);

    void handlePropertySetEvent(const VehiclePropValue& value);

    const VehiclePropConfig* getPropConfigOrNull(int32_t prop) const;

    bool checkWritePermission(const VehiclePropConfig &config) const;
    bool checkReadPermission(const VehiclePropConfig &config) const;
    void onAllClientsUnsubscribed(int32_t propertyId);

    // Dump and commands
    // TODO: most functions below (exception dump() and cmdSetOne()) should be const, but they rely
    // on IVehicle.get(), which isn't...
    void cmdDump(int fd, const hidl_vec<hidl_string>& options);
    void cmdDumpOneProperty(int fd, int32_t prop, int32_t areaId);
    void cmdDumpOneProperty(int fd, int rowNumber, const VehiclePropConfig& config);

    static bool checkArgumentsSize(int fd, const hidl_vec<hidl_string>& options, size_t minSize);
    static bool checkCallerHasWritePermissions(int fd);
    static bool safelyParseInt(int fd, int index, std::string s, int* out);
    void cmdHelp(int fd) const;
    void cmdListAllProperties(int fd) const;
    void cmdDumpAllProperties(int fd);
    void cmdDumpSpecificProperties(int fd, const hidl_vec<hidl_string>& options);
    void cmdSetOneProperty(int fd, const hidl_vec<hidl_string>& options);

    static bool isSubscribable(const VehiclePropConfig& config,
                               SubscribeFlags flags);
    static bool isSampleRateFixed(VehiclePropertyChangeMode mode);
    static float checkSampleRate(const VehiclePropConfig& config,
                                 float sampleRate);
    static ClientId getClientId(const sp<IVehicleCallback>& callback);
private:
    VehicleHal* mHal;
    std::unique_ptr<VehiclePropConfigIndex> mConfigIndex;
    SubscriptionManager mSubscriptionManager;

    hidl_vec<VehiclePropValue> mHidlVecOfVehiclePropValuePool;

    ConcurrentQueue<VehiclePropValuePtr> mEventQueue;
    BatchingConsumer<VehiclePropValuePtr> mBatchingConsumer;
    VehiclePropValuePool mValueObjectPool;
};

}  // namespace V2_0
}  // namespace vehicle
}  // namespace automotive
}  // namespace hardware
}  // namespace android

VehicleHalManager::get

获取一个车辆属性

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();
}
  1. const auto* config = getPropConfigOrNull(requestedPropValue.prop)获取车辆属性的配置

  2. checkReadPermission(*config)检查车辆属性的权限

    bool VehicleHalManager::checkReadPermission(const VehiclePropConfig &config) const {
        if (!(config.access & VehiclePropertyAccess::READ)) {
            ALOGW("Property 0%x has no read access", config.prop);
            return false;
        } else {
            return true;
        }
    }
    
  3. _hidl_cb(status, value.get() ? *value : kEmptyValue)返回获取结果。

VehicleHalManager::set

设置一个车辆属性

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);
}
  1. const auto* config = getPropConfigOrNull(prop);先检查有没有这个车辆属性。
  2. checkWritePermission(*config)检查权限
  3. handlePropertySetEvent(value)通知订阅者此车辆属性被设置了。
  4. auto status = mHal->set(value)交给EmulatedVehicleHal设置车辆属性

VehicleHalManager::subscribe

订阅对车辆属性

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;
}
  1. const auto* config = getPropConfigOrNull(prop)获取车辆属性,判断是否有此配置
  2. isSubscribable(*config, ops.flags)判断是否已经订阅
  3. ops.sampleRate = checkSampleRate(*config, ops.sampleRate);检查订阅的频率
  4. auto res = mSubscriptionManager.addOrUpdateSubscription更新订阅的状态。
  5. mHal->subscribe(opt.propId, opt.sampleRate)通知EmulatedVehicleHal更新订阅信息。

VehicleHalManager::unsubscribe

取消订阅车辆属性

VehicleHalManager::init

初始化VehicleHalManager配置

void VehicleHalManager::init() {
    ALOGI("VehicleHalManager::init");

    mHidlVecOfVehiclePropValuePool.resize(kMaxHidlVecOfVehiclPropValuePoolSize);


    mBatchingConsumer.run(&mEventQueue,
                          kHalEventBatchingTimeWindow,
                          std::bind(&VehicleHalManager::onBatchHalEvent,
                                    this, _1));

    mHal->init(&mValueObjectPool,
               std::bind(&VehicleHalManager::onHalEvent, this, _1),
               std::bind(&VehicleHalManager::onHalPropertySetError, this,
                         _1, _2, _3));

    // Initialize index with vehicle configurations received from VehicleHal.
    auto supportedPropConfigs = mHal->listProperties();
    mConfigIndex.reset(new VehiclePropConfigIndex(supportedPropConfigs));

    std::vector<int32_t> supportedProperties(
        supportedPropConfigs.size());
    for (const auto& config : supportedPropConfigs) {
        supportedProperties.push_back(config.prop);
    }
}
  1. mBatchingConsumer.run(&mEventQueu运行处理回调的处理者
  2. mHal->init(&mValueObjectPool设置回调的响应函数onHalEventonHalPropertySetError

VehicleHalManager::onHalEvent

将事件添加到消息队列

void VehicleHalManager::onHalEvent(VehiclePropValuePtr v) {
    mEventQueue.push(std::move(v));
}

VehicleHalManager::onHalPropertySetError

通知订阅者设置失败的情况。

void VehicleHalManager::onHalPropertySetError(StatusCode errorCode,
                                              int32_t property,
                                              int32_t areaId) {
    const auto& clients =
        mSubscriptionManager.getSubscribedClients(property, SubscribeFlags::EVENTS_FROM_CAR);

    for (const auto& client : clients) {
        client->getCallback()->onPropertySetError(errorCode, property, areaId);
    }
}

VehicleHalManager::onBatchHalEvent

回调给应用的车辆属性变化

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());
        }
    }
}
  1. auto status = cv.client->getCallback()->onPropertyEvent(vec)回调给订阅者车辆属性变化

VehicleEmulator

车辆模拟器使用的车辆HAL的扩展,可以基于此接口进行socket通信来实现依稀VHAL的功能。

运用Pipe管道或者socket通讯的方式,跟模拟器之间收发通过protobuf封装的数据,模块内部实现了protobuf数据的解析与封装,用来触发设置,获取属性值的事件等。

VehicleEmulator::processMessage

处理一条接收的消息,消息可以分为五类

  • GET_CONFIG_CMD
  • GET_CONFIG_ALL_CMD
  • GET_PROPERTY_CMD
  • GET_PROPERTY_ALL_CMD
  • SET_PROPERTY_CMD
void VehicleEmulator::processMessage(vhal_proto::EmulatorMessage const& rxMsg,
                                     vhal_proto::EmulatorMessage& respMsg) {
    switch (rxMsg.msg_type()) {
        case vhal_proto::GET_CONFIG_CMD:
            doGetConfig(rxMsg, respMsg);
            break;
        case vhal_proto::GET_CONFIG_ALL_CMD:
            doGetConfigAll(rxMsg, respMsg);
            break;
        case vhal_proto::GET_PROPERTY_CMD:
            doGetProperty(rxMsg, respMsg);
            break;
        case vhal_proto::GET_PROPERTY_ALL_CMD:
            doGetPropertyAll(rxMsg, respMsg);
            break;
        case vhal_proto::SET_PROPERTY_CMD:
            doSetProperty(rxMsg, respMsg);
            break;
        default:
            ALOGW("%s: Unknown message received, type = %d", __func__, rxMsg.msg_type());
            respMsg.set_status(vhal_proto::ERROR_UNIMPLEMENTED_CMD);
            break;
    }
}

VehicleHalProto

通信数据使用proto封装。数据定义在hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto

syntax = "proto2";

package vhal_proto;

// CMD messages are from workstation --> VHAL
// RESP messages are from VHAL --> workstation
enum MsgType {
    
    
    GET_CONFIG_CMD                      = 0;
    GET_CONFIG_RESP                     = 1;
    GET_CONFIG_ALL_CMD                  = 2;
    GET_CONFIG_ALL_RESP                 = 3;
    GET_PROPERTY_CMD                    = 4;
    GET_PROPERTY_RESP                   = 5;
    GET_PROPERTY_ALL_CMD                = 6;
    GET_PROPERTY_ALL_RESP               = 7;
    SET_PROPERTY_CMD                    = 8;
    SET_PROPERTY_RESP                   = 9;
    SET_PROPERTY_ASYNC                  = 10;
}
enum Status {
    
    
    RESULT_OK                           = 0;
    ERROR_UNKNOWN                       = 1;
    ERROR_UNIMPLEMENTED_CMD             = 2;
    ERROR_INVALID_PROPERTY              = 3;
    ERROR_INVALID_AREA_ID               = 4;
    ERROR_PROPERTY_UNINITIALIZED        = 5;
    ERROR_WRITE_ONLY_PROPERTY           = 6;
    ERROR_MEMORY_ALLOC_FAILED           = 7;
    ERROR_INVALID_OPERATION             = 8;
}

enum VehiclePropStatus {
    
    
    AVAILABLE                           = 0;
    UNAVAILABLE                         = 1;
    ERROR                               = 2;
}

message VehicleAreaConfig {
    
    
    required int32  area_id             = 1;
    optional sint32 min_int32_value     = 2;
    optional sint32 max_int32_value     = 3;
    optional sint64 min_int64_value     = 4;
    optional sint64 max_int64_value     = 5;
    optional float  min_float_value     = 6;
    optional float  max_float_value     = 7;
}

message VehiclePropConfig {
    
    
    required int32             prop                = 1;
    optional int32             access              = 2;
    optional int32             change_mode         = 3;
    optional int32             value_type          = 4;
    optional int32             supported_areas     = 5;     // Deprecated - DO NOT USE
    repeated VehicleAreaConfig area_configs        = 6;
    optional int32             config_flags        = 7;
    repeated int32             config_array        = 8;
    optional string            config_string       = 9;
    optional float             min_sample_rate     = 10;
    optional float             max_sample_rate     = 11;
};

message VehiclePropValue {
    
    
    // common data
    required int32  prop                = 1;
    optional int32  value_type          = 2;
    optional int64  timestamp           = 3;    // required for valid data from HAL, skipped for set
    optional VehiclePropStatus  status  = 10;   // required for valid data from HAL, skipped for set

    // values
    optional int32  area_id             = 4;
    repeated sint32 int32_values        = 5;    // this also covers boolean value.
    repeated sint64 int64_values        = 6;
    repeated float  float_values        = 7;
    optional string string_value        = 8;
    optional bytes  bytes_value         = 9;
};

// This structure is used to notify what values to get from the Vehicle HAL
message VehiclePropGet {
    
    
    required int32 prop                 = 1;
    optional int32 area_id              = 2;
};

message EmulatorMessage {
    
    
    required MsgType           msg_type = 1;
    optional Status            status   = 2;    // Only for RESP messages
    repeated VehiclePropGet    prop     = 3;    // Provided for getConfig, getProperty commands
    repeated VehiclePropConfig config   = 4;
    repeated VehiclePropValue  value    = 5;
};

猜你喜欢

转载自blog.csdn.net/Jun_P/article/details/127116736