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 |
---|
android.hardware.automotive.vehicle@2.0 |
vhal_v2_0_defaults |
vhal_v2_0_target_defaults |
android.hardware.automotive.vehicle@2.0-manager-lib |
android.hardware.automotive.vehicle@2.0-default-impl-lib |
android.hardware.automotive.vehicle@2.0-emulated-user-hal-lib |
android.hardware.automotive.vehicle@2.0-server-common-lib |
android.hardware.automotive.vehicle@2.0-server-impl-lib |
android.hardware.automotive.vehicle@2.0-manager-unit-tests |
android.hardware.automotive.vehicle@2.0-default-impl-unit-tests |
android.hardware.automotive.vehicle@2.0-service |
android.hardware.automotive.vehicle@2.0-libproto-native |
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: "android.hardware.automotive.vehicle@2.0-service",defaults: ["vhal_v2_0_target_defaults"],vintf_fragments: ["android.hardware.automotive.vehicle@2.0-service.xml",],init_rc: ["android.hardware.automotive.vehicle@2.0-service.rc"],vendor: true,relative_install_path: "hw",srcs: ["VehicleService.cpp"],shared_libs: ["libbase","libjsoncpp","libprotobuf-cpp-lite",],static_libs: ["android.hardware.automotive.vehicle@2.0-manager-lib","android.hardware.automotive.vehicle@2.0-default-impl-lib","android.hardware.automotive.vehicle@2.0-libproto-native","libqemu_pipe",],
}
init_rc: ["android.hardware.automotive.vehicle@2.0-service.rc"]
指定启动的配置文件。
rc
文件:hardware/interfaces/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc
service vendor.vehicle-hal-2.0 /vendor/bin/hw/android.hardware.automotive.vehicle@2.0-serviceclass haluser vehicle_networkgroup system inet
VehicleService::main
VehicleService
启动的主函数就是main
方法。
int main(int /* argc */, char* /* argv */ []) {auto store = std::make_unique<VehiclePropertyStore>(); //初始化VehiclePropertyStoreauto connector = impl::makeEmulatedPassthroughConnector(); //创建一个连接者 EmulatedPassthroughConnectorauto userHal = connector->getEmulatedUserHal(); //获取getEmulatedUserHalauto hal = std::make_unique<impl::EmulatedVehicleHal>(store.get(), connector.get(), userHal); //初始化EmulatedVehicleHalauto emulator = std::make_unique<impl::VehicleEmulator>(hal.get()); //初始化VehicleEmulatorauto service = std::make_unique<VehicleHalManager>(hal.get()); //初始化VehicleHalManagerconnector->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 */)); //初始化looperstd::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;
}
- 初始化
VehiclePropertyStore
,得到store
指针 - 创建一个连接者
EmulatedPassthroughConnector
- 获取
getEmulatedUserHal
- 初始化
EmulatedVehicleHal
,得到hal
指针,初始化时,将VehiclePropertyStore
指针作为参数传输了EmulatedVehicleHal
构造方法中 - 初始化
VehicleEmulator
,得到emulator
指针,初始化时,将EmulatedVehicleHal
指针作为参数传入VehicleEmulator
的构造方法中。 - 初始化
VehicleHalManager
,获得service
智能指针。VehicleHalManager
继承自IVehicle hidl
接口,该接口在编译的时候自动生成了registerAsService
方法,该方法就是将服务本身通过binder
注册到hwservicemanager
里面供其他进程连接。 - 创建
value
池 - 初始化RPC线程池
- 初始化Binder线程池
- 初始化
looper
- 初始化
watchdog
- 启动
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; //propConfigTokenFunction tokenFunction; //propValue};struct RecordId {int32_t prop; //propint32_t area; //areaint64_t token; //tokenbool operator==(const RecordId& other) const; // ==重载操作符bool operator<(const RecordId& other) const; // <重载操作符};using PropertyMap = std::map<RecordId, VehiclePropValue>; //recordId和vehiclePropValue的mapusing 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); //移除一个值用propIdstd::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; //VehiclePropConfigconst VehiclePropConfig* getConfigOrDie(int32_t propId) const; //VehiclePropConfigprivate:RecordId getRecordIdLocked(const VehiclePropValue& valuePrototype) const; //获取RecordIdconst VehiclePropValue* getValueOrNullLocked(const RecordId& recId) const; //获取VehiclePropValuePropertyMapRange findRangeLocked(int32_t propId) const; //获取PropertyMapRangeprivate: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; //propConfigTokenFunction tokenFunction; //propValue
};
VehiclePropertyStore::RecordId
属性记录
struct RecordId {int32_t prop; //propint32_t area; //areaint64_t token; //tokenbool 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
的连接器,里面实现了VehicleHalClient
和VehicleHalServer
#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.cppclass EmulatedPassthroughConnector : public PassthroughConnector
//EmulatedVehicleConnector.husing PassthroughConnector = IPassThroughConnector<VehicleHalClient, VehicleHalServer>;
//VehicleConnector.htemplate <typename VehicleClientType, typename VehicleServerType>class IPassThroughConnector : public VehicleClientType, public VehicleServerType {
也就是说**EmulatedVehicleConnector
继承了VehicleHalClient
和VehicleHalServer
**
这里对一些方法做了实现
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
时会执行到VehicleHalServer
的onSetProperty
方法。
当调用onPropertyValueFromCar
时会执行到VehicleHalClient
的onPropertyValue
方法。
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 IVehicleServerstd::vector<VehiclePropConfig> onGetAllPropertyConfig() const override;StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) override;// Set the Property Value Pool used in this servervoid 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 membersprotected: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 HALauto 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 valuesusing PropertyCallBackType = std::function<void(const VehiclePropValue&, bool updateStatus)>;// Method from IVehicleClientvoid 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 VehicleHalvoid 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 EmulatedVehicleHalIfacebool 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
继承VehicleHal
。VehicleHal
定义了和IVehicle
中同样的接口,也就是说EmulatedVehicleHal
对IVehcle
中的接口做了实现。
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();}
}
-
auto hal = std::make_unique<impl::EmulatedVehicleHal>(store.get(), connector.get(), userHal);
前面在VehicleService
中创建EmulatedVehicleHal
时,传入了前面创建的三个变量。 -
mPropStore(propStore)
存储车辆属性变化的一个容器。 -
mVehicleClient(client)
回调通知用的 -
mRecurrentTimer(std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this
一个处理持续变化Continuous
车辆属性的计时器。 -
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
容器。 -
mPropStore->registerProperty(kVehicleProperties[i].config)
和initStaticConfig
好像重复了。 -
mVehicleClient->registerPropertyValueCallback(std::bind(&EmulatedVehicleHal::onPropertyValue,
将callback
函数注册给mVehicleClient
。回调时会触发onPropertyValue
-
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;
}
auto internalPropValue = mPropStore->readValueOrNull(requestedPropValue)
这里从mPropStrore
中取一个车辆属性,也就是从维护的数据容器中获取对应车辆属性的值。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)) {//这里是判断当前属性值是否属于空调电源开关,如果是的情况下,去拿它值,如果当前开关没开,则返回当前状态不可用,设置失败的CODEauto 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 codeswitch (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默认值为AVAILABLEif (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 hardwarereturn StatusCode::INVALID_ARG;}//读取该属性值id的当前存储的Propauto 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 propertyreturn 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 fixedreturn 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;
}
-
auto currentPropValue = mPropStore->readValueOrNull(propValue);
从数据容器中读取一下当前的车辆属性值。 -
在检查了所有条件(例如属性是否可用)后,真正的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. */
-
auto setValueStatus = mVehicleClient->setProperty(propValue, updateStatus)
这里实际是将值发送到车辆服务,服务将与(真实或模拟的)发送给汽车。
这里对车辆属性的设置实际交给VehicleHalClient
处理
VehicleHalClient
实际是VehicleConnector
对象,最后会调用VehicleServer
的onSetProperty
方法。
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;
}
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));
当被调用VehicleHalClient
的onPropertyValue
函数时,则会执行EmulatedVehicleHal
的onPropertyValue
。
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 IVehicleReturn<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 VehicleHalvoid onHalEvent(VehiclePropValuePtr v);void onHalPropertySetError(StatusCode errorCode, int32_t property,int32_t areaId);// ---------------------------------------------------------------------------------------------// This method will be called from BatchingConsumer threadvoid 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();
}
-
const auto* config = getPropConfigOrNull(requestedPropValue.prop)
获取车辆属性的配置 -
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;} }
-
_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);
}
const auto* config = getPropConfigOrNull(prop);
先检查有没有这个车辆属性。checkWritePermission(*config)
检查权限handlePropertySetEvent(value)
通知订阅者此车辆属性被设置了。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;
}
const auto* config = getPropConfigOrNull(prop)
获取车辆属性,判断是否有此配置isSubscribable(*config, ops.flags)
判断是否已经订阅ops.sampleRate = checkSampleRate(*config, ops.sampleRate);
检查订阅的频率auto res = mSubscriptionManager.addOrUpdateSubscription
更新订阅的状态。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);}
}
mBatchingConsumer.run(&mEventQueu
运行处理回调的处理者mHal->init(&mValueObjectPool
设置回调的响应函数onHalEvent
和onHalPropertySetError
。
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());}}
}
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 USErepeated 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 datarequired int32 prop = 1;optional int32 value_type = 2;optional int64 timestamp = 3; // required for valid data from HAL, skipped for setoptional VehiclePropStatus status = 10; // required for valid data from HAL, skipped for set// valuesoptional 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 messagesrepeated VehiclePropGet prop = 3; // Provided for getConfig, getProperty commandsrepeated VehiclePropConfig config = 4;repeated VehiclePropValue value = 5;
};
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.dgrt.cn/a/58377.html
如若内容造成侵权/违法违规/事实不符,请联系我爱学习网进行投诉反馈,一经查实,立即删除!相关文章:

Android Automotive(七) VehicleService
Android Automotive(七) VehicleService VehicleService 是Android Automotive在硬件抽象层的一个核心native服务。处理和车辆相关功能,为系统提供获取车身信息以及设置相关状态的接口。 HAL接口 从Android O (8.0) 开始,Googl…...

贪心c++(结合LeetCode例题)
目录 前言 LeetCode455分发饼干 思考 算法思路 LeetCode376摆动序列 思考 思路 代码 前言 有1元,5元10,元,20元,100元,200,元的钞票无穷多张。先使用这些钞票支付x元支付x元,最少需要…...
【python】文本处理:删除包含关键词的行、删除指定列、删除指定字符、替换关键字……...
目录 1、行处理 删除文件中包含关键词的行 删除TXT中的带/不带指定字符的行(并保留带指定字符的行) 删除匹配or不匹配某些条件的行 2、字符处理 删除特定字符 1.1、删除特定位置的字符 1.2、删除指定字符 1.3、删除每一行首/尾匹配条件的字符 正则表达式 替换文件里的字符 3、列…...

手写节流防抖函数
1. 认识防抖和节流函数 防抖和节流的概念最早不是出现在软件工程中,防抖是出现在电子元件中,节流是出现的流体流动中。 而javascript是事件驱动的,大量的操作会触发事件,加入到事件队列中处理而对于某些频繁的事件处理会造成性能…...

camunda_11_connector
Camunda 的 service task 推荐使用 external task, 它有很多优点: 流程引擎可以做到轻量级, 流程引擎实例可以支持更多的业务.解耦流程引擎和业务代码, 以后的升级和部署将非常方便.借助external task SDK, 业务代码实现也非常简单external task 采用 pull 模式, 由 external t…...

通达信自动交易接口设置止损程序解析
通达信自动交易接口设置止损程序并不是很难,对于交易者来说,还是需要去学习一些编程知识,像交易中的止损程序,可以这样去编写和输入你的止损策略: (1)# 设置买卖止损值 def set_stop_lose_n…...

MySQL事务的理解
什么是事务 事务是是数据库操作的最小的单元,它包含了一个或者多个操作命令,这些命令作为一个整体来执 行,要么一起成功要么一起失败,事务是不可在分的一个整体的操作集合。 事务具备的四大特性 原子性:事务是一个…...

ubantu服务器崩溃,重装系统如何使用之前的账号
1.进入root账户下: sudo su 2.查看账号拥有者和所属组 ls -la 2.给现在系统,添加原来相同的已存在账号名: adduser newusername 注意:报告已存在用户名称!不用管,这个错误。已经添加到新系统中了。 3.修…...

Python 逻辑回归
逻辑回归分类 训练二元分类器 加载仅有两个分类的数据 from sklearn.linear_model import LogisticRegression from sklearn import datasets from sklearn.preprocessing import StandardScaleriris datasets.load_iris() features iris.data[:100,:] target iris.target…...

web前端面试题附答案016-怎么让顶部轮播图渲染的更快?
一、为什么强调轮播图? 很多时候我们强调用户体验,而这里更多时候我们更强调完美的首屏体验,而现在几乎每个网站顶部第一个大模块就是轮播图。轮播图占得区域最大,图片质量也更高,几乎一张图片的面积,体积就…...

springboot-内置Tomcat的配置和切换
基本介绍1.SpringBoot支持的webServer:Tomcat,Jetty,or Undertow2.SpringBoot应用启动是Web应用时。web场景包-导入tomcat3.支持对Tomcat(也可以是Jetty、Undertow)的配置和切换配置Tomcat方法一:通过application.yml完成配置(推荐方式&#…...

NAND VT Distribution 和失效模式
Vt Distribution是NAND Flash非常重要的一个特性。 1 从NMOS Vt到FGNMOS Vt 阈值电压(Vt或Vth)的概念是从MOS(Metal-Oxide-Semicondutor)来的。MOS的工作原理就像一个水库,Gate就是闸,闸抬起来(VGate≥Vth)电流就可以流过沟道(Channel),闸放下去(VGate<Vth)电流就不可以流…...

【C语言】编程初学者入门训练(1)
文章目录1. 实践出真知2. 我是大V3. 有容乃大4. 小飞机5. 缩短2进制6. 十六进制转十进制7. printf的返回值8. 成绩输入输出9. 学生基本信息输入输出10. 字符圣诞树1. 实践出真知 题目内容:于老师经常告诉我们“学习编程最好的办法就是上机实践,因为你要对…...

Python numpy.interp实例讲
本文章向大家介绍Python numpy.interp实例讲解,主要分析其语法、参数、返回值和注意事项,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。用法: numpy.interp(x, xp, fp, leftNone, rightNone, periodN…...

Xavier参数初始化方法和Kaiming参数初始化方法详细介绍及其原理详解
相关文章 梯度下降算法、随机梯度下降算法、动量随机梯度下降算法、AdaGrad算法、RMSProp算法、Adam算法详细介绍及其原理详解反向传播算法和计算图详细介绍及其原理详解激活函数、Sigmoid激活函数、tanh激活函数、ReLU激活函数、Leaky ReLU激活函数、Parametric ReLU激活函数…...

线程池EterfreeA/ThreadPool的使用
在GitHub上有个线程池项目,地址为 https://github.com/EterfreeA/ThreadPool ,开源,它的License为AFL-3.0,这里了解学习下,code中有较多的中文说明: (1).Core.hpp: 一些define和size函数 (2).DoubleQueue.…...

Python科学计算:用NumPy快速处理数据
NumPy是Python 中一个非常重要的第三方库 它不仅是 Python 中使用最多的第三方库,而且还是 SciPy、Pandas 等数据科学的基础 库。它所提供的数据结构比 Python 自身的“更高级、更高效”,可以这么说,NumPy 所 提供的数据结构是 Python 数据…...

基于python实现的生成对抗网络GAN
项目简介 这篇文章主要介绍了生成对抗网络(Generative Adversarial Network),简称 GAN。 GAN 可以看作是一种可以生成特定分布数据的模型。 2.生成人脸图像 下面的代码是使用 Generator 来生成人脸图像,Generator 已经训练好保存在 pkl 文件中,只需要加载参数即可。由…...

Matlab----绘图以及文件储存
目录 二维曲线 基础函数:plot/fplot 绘制图形的辅助操作 文件存储 二维曲线 基础函数:plot/fplot (1)plot函数的基本用法:plot(x,y)其中x和y分别用于储存x坐标和y坐标数据 (2)最简单plot函…...

Docker - 12. 容器卷基本概念
目录 1. 容器卷是什么? 2. 容器卷的特点 1. 容器卷是什么? 卷就是目录或文件,存在于一个或者多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能够绕过联合文件系统而提供一些用于存储或共享数…...