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-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;
}
- 初始化
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; //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
的连接器,里面实现了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.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
继承了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 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
继承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)) {
//这里是判断当前属性值是否属于空调电源开关,如果是的情况下,去拿它值,如果当前开关没开,则返回当前状态不可用,设置失败的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;
}
-
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 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();
}
-
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 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;
};