Android-S Vehicle HAL架构
VehicleHAL 简介¶
-
源码位置 : hardware/interfaces/automotive/vehicle/2.0/
-
VehicleHAL 类图
接口文件¶
- types.hal 定义的是一些数据结构
- IVehicle.hal 定义的是从 CarService 往 HAL 调用的接口
- IVehicleCallback.hal 则是 HAL 往 CarService 上报回调的接口
2. VehicleHal初始化流程¶
初始化从执行 hardware/interfaces/automotive/vehicle/2.0/default/VehicleService.cpp 的main函数开始:
- 创建 VehiclePropertyStore 对象
- 创建 EmulatedVehicleConnector 对象
- 创建 EmulatedUserHal 对象
- 创建 EmulatedVehicleHal 对象
- 创建 VehicleEmulator 对象
- 创建 VehicleHalManager 对象
hardware/interfaces/automotive/vehicle/2.0/default/VehicleService.cpp
int main(int /* argc */, char* /* argv */ []) {
//1. 创建一个 VehiclePropertyStore 对象,并使用std::make_unique进行智能指针的初始化
auto store = std::make_unique<VehiclePropertyStore>();
//2. 创建一个 EmulatedVehicleConnector 对象,并使用std::make_unique进行智能指针的初始化
auto connector = std::make_unique<impl::EmulatedVehicleConnector>();
// 载入配置声明
connector->LoadConfigDeclarations(impl::kVehicleProperties);
//3. 获取 EmulatedUserHal 对象
auto userHal = connector->getEmulatedUserHal();
//4. 创建一个 EmulatedVehicleHal 对象,并使用std::make_unique进行智能指针的初始化
auto hal = std::make_unique<impl::EmulatedVehicleHal>(store.get(), connector.get(), userHal);
//5. 创建一个 VehicleEmulator 对象,并使用std::make_unique进行智能指针的初始化
auto emulator = std::make_unique<impl::VehicleEmulator>(hal.get());
// 创建一个 VehicleHalManager 对象,并使用std::make_unique进行智能指针的初始化
auto service = std::make_unique<VehicleHalManager>(hal.get());
// 设置connector的value pool
connector->setValuePool(hal->getValuePool());
// 配置RPC线程池
configureRpcThreadpool(4, true /* callerWillJoin */);
ALOGI("Registering as service...");
// 注册为服务
status_t status = service->registerAsService();
if (status != OK) {
ALOGE("Unable to register vehicle service (%d)", status);
return 1;
}
ALOGI("Ready");
// 加入RPC线程池
joinRpcThreadpool();
return 1;
}
VehiclePropertyStore¶
VehiclePropertyStore的类,用于存储和访问车辆属性的配置和值。
- registerProperty:注册车辆属性的配置。
- writeValue:存储提供的属性值。
- removeValue:删除指定的属性值。
- removeValuesForProperty:删除指定属性的所有值。
- readAllValues:读取所有属性的值。
- readValuesForProperty:读取指定属性的所有值。
- readValueOrNull:根据请求读取属性值,如果不存在则返回空指针。
- getConfigOrNull:根据属性ID获取属性配置,如果不存在则返回空指针。
- getConfigOrDie:根据属性ID获取属性配置,如果不存在则抛出异常。
hardware/interfaces/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehiclePropertyStore.h
class VehiclePropertyStore {
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);
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;
const VehiclePropConfig* getConfigOrDie(int32_t propId) const;
...
};
EmulatedVehicleConnector¶
EmulatedVehicleConnector 继承自 IPassThroughConnector
该代码的功能是实现了一个模拟车辆连接器,用于处理车辆属性的设置和转储请求,并与 EmulatedUserHal 进行交互。
- getEmulatedUserHal() 的函数,返回一个 EmulatedUserHal 类型的指针。
- 实现了 VehicleHalServer 接口中的 triggerSendAllValues() 函数。用于触发将所有值发送给客户端。
- 实现了 VehicleHalServer 接口中的 onSetProperty() 函数。用于处理设置属性的请求,如果属性由 EmulatedUserHal 支持,则调用 EmulatedUserHal 的 onSetProperty() 函数进行处理,并根据返回值更新属性的值。
- 实现了 VehicleHalServer 接口中的 onDump() 函数。
hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h
class EmulatedVehicleConnector : public IPassThroughConnector<VehicleHalClient, VehicleHalServer> {
public:
EmulatedVehicleConnector() = default;
EmulatedUserHal* getEmulatedUserHal();
// Methods from VehicleHalServer
void triggerSendAllValues() override;
StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) override;
bool onDump(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
private:
EmulatedUserHal mEmulatedUserHal;
};
hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp
...
VehicleHalServer::LoadConfigDeclarations()¶
我们在 EmulatedVehicleConnector 里并没有看到 LoadConfigDeclarations() 函数,那么是在哪里呢?
hardware/interfaces/automotive/vehicle/2.0/default/VehicleService.cpp
auto connector = std::make_unique<impl::EmulatedVehicleConnector>();
connector->LoadConfigDeclarations(impl::kVehicleProperties);
前面什么提到过 EmulatedVehicleConnector 继承自 IPassThroughConnector
hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h
class EmulatedVehicleConnector : public IPassThroughConnector<VehicleHalClient, VehicleHalServer> {
}
果然,我们在 VehicleHalServer 里找到函数 LoadConfigDeclarations()
hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h
class VehicleHalServer : public IVehicleServer {
void LoadConfigDeclarations(const std::vector<ConfigDeclaration> additionalProperties);
}
把 hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h 里声明的 kVehicleProperties 配置全部加载。
EmulatedUserHal¶
EmulatedUserHal 用于模拟用户 HAL 的行为,通过使用 lshal 调试请求来实现。
- isSupported():检查模拟器是否支持给定的属性。
- onSetProperty():允许模拟器设置属性,并返回更新后的属性和状态码。
- onGetProperty():从模拟器获取属性值,并返回属性值和状态码。
- dump():lshal 命令 dump
hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.h
hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.cpp
EmulatedVehicleHal¶
EmulatedVehicleHal 类是 EmulatedVehicleHalIface、VehicleHal 的实现 用于连接到模拟器而不是真实的车辆网络。
- initStaticConfig() : 用于初始化静态配置。
- 实现 VehicleHal 接口的方法 : onCreate()、listProperties()、get()、set()、subscribe()、unsubscribe() 和 dump()。
- 实现 EmulatedVehicleHalIface 接口的方法 : setPropertyFromVehicle()、getAllProperties() 和 getAllPropertiesOverride()。
hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h
class EmulatedVehicleHalIface : public VehicleHal {
}
hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
/** 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);
// 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:
VehiclePropertyStore* mPropStore;
VehicleHalClient* mVehicleClient;
EmulatedUserHal* mEmulatedUserHal;
};
VehicleEmulator¶
hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h
class VehicleEmulator : public MessageProcessor {
public:
VehicleEmulator(EmulatedVehicleHalIface* hal);
private:
EmulatedVehicleHalIface* mHal;
std::unique_ptr<SocketComm> mSocketComm;
std::unique_ptr<PipeComm> mPipeComm;
};
hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
VehicleEmulator::VehicleEmulator(EmulatedVehicleHalIface* hal) : mHal{hal} {
mHal->registerEmulator(this);
ALOGI("Starting SocketComm");
mSocketComm = std::make_unique<SocketComm>(this);
mSocketComm->start();
if (isInEmulator()) {
ALOGI("Starting PipeComm");
mPipeComm = std::make_unique<PipeComm>(this);
mPipeComm->start();
}
}
VehicleHalManager¶
- 重置 HidlVecOfVehiclePropValuePool HIDL属性对象池大小
- 开启事件消费着队列
- VehicleHal 初始化
hardware/interfaces/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h
class VehicleHalManager : public IVehicle {
public:
VehicleHalManager(VehicleHal* vehicleHal)
: mHal(vehicleHal),
// 1. mSubscriptionManager成员变量被初始化为一个绑定到onAllClientsUnsubscribed方法的函数对象。
// 该函数对象使用std::bind绑定了this指针和std::placeholders::_1占位符。
mSubscriptionManager(std::bind(&VehicleHalManager::onAllClientsUnsubscribed,
this, std::placeholders::_1)) {
init();
}
...
}
hardware/interfaces/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
void VehicleHalManager::init() {
ALOGI("VehicleHalManager::init");
// 调整 mHidlVecOfVehiclePropValuePool 的大小为 20
// constexpr auto kMaxHidlVecOfVehiclePropValuePoolSize = 20;
mHidlVecOfVehiclePropValuePool.resize(kMaxHidlVecOfVehiclePropValuePoolSize);
// 开启事件消费着队列
mBatchingConsumer.run(&mEventQueue, // 启动批处理消费者线程
kHalEventBatchingTimeWindow, // 批处理时间窗口
std::bind(&VehicleHalManager::onBatchHalEvent, // 绑定 onBatchHalEvent 函数
this, _1));
// 初始化 VehicleHal
mHal->init(&mValueObjectPool,
std::bind(&VehicleHalManager::onHalEvent, this, _1), // 绑定 onHalEvent 函数
std::bind(&VehicleHalManager::onHalPropertySetError, this, // 绑定 onHalPropertySetError 函数
_1, _2, _3));
// 初始化从 VehicleHal 收到的 vehicle 属性的索引
auto supportedPropConfigs = mHal->listProperties(); // 获取支持的属性配置列表
mConfigIndex.reset(new VehiclePropConfigIndex(supportedPropConfigs)); // 使用支持的属性配置列表创建VehiclePropConfigIndex对象
std::vector<int32_t> supportedProperties( // 创建支持的属性列表
supportedPropConfigs.size());
for (const auto& config : supportedPropConfigs) {
supportedProperties.push_back(config.prop); // 将支持的属性添加到列表中
}
}
VehicleHal.init()¶
VehicleHal.h 初始化做了以下操作: - 初始化 mValuePool - 初始化 mOnHalEvent - 初始化 mOnHalPropertySetError 变量 - 调用 onCreate()
hardware/interfaces/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h
class VehicleHal {
...
/**
* Override this method if you need to do one-time initialization.
*/
virtual void onCreate() {}
void init(
VehiclePropValuePool* valueObjectPool,
const HalEventFunction& onHalEvent,
const HalErrorFunction& onHalError) {
mValuePool = valueObjectPool;
mOnHalEvent = onHalEvent;
mOnHalPropertySetError = onHalError;
onCreate();
}
...
}
调用 onCreate() 函数,遍历属性列表并以 mPropStore,即 VehiclePropertyStore 保存当前值
hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h
class EmulatedVehicleHalIface : public VehicleHal {
}
hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
class EmulatedVehicleHal : public EmulatedVehicleHalIface {
// Methods from VehicleHal
void onCreate() override;
}
hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
// 解析支持的属性列表并生成包含当前值的属性值向量。
void EmulatedVehicleHal::onCreate() {
...
}
VehicleHal启动序列图¶
sequenceDiagram
VehicleService ->> VehicleService:main()
Note over VehicleService : 进程主入口,初始化 VehicleHal 等,并注册服务
VehicleService ->> VehiclePropertyStore:EmulatedVehicleHal()
Note over VehiclePropertyStore : 并使用 std::make_unique 进行智能指针的初始化,并返回对象 store
VehicleService ->> EmulatedVehicleConnector:EmulatedVehicleConnector()
Note over EmulatedVehicleConnector : 并使用 std::make_unique 进行智能指针的初始化,并返回对象 connector
VehicleService ->> EmulatedVehicleHal:EmulatedVehicleHal()
Note over EmulatedVehicleHal : 并使用 std::make_unique 进行智能指针的初始化,构造函数传入VehiclePropertyStore、VehicleHalClient、EmulatedUserHal,并返回对象 hal
VehicleService ->> VehicleEmulator::VehicleEmulator(EmulatedVehicleHalIface* hal)
Note over VehicleEmulator : 并使用 std::make_unique 进行智能指针的初始化,构造函数传入EmulatedVehicleHalIface,并返回对象 emulator
VehicleService ->> VehicleHalManager::VehicleHalManager(VehicleHal* vehicleHal)
Note over VehicleHalManager : 并使用 std::make_unique 进行智能指针的初始化,VehicleHal,并返回对象 service
types.hal¶
VehiclePropertyType¶
车辆属性类型
hardware/interfaces/automotive/vehicle/2.0/types.hal
/**
* 枚举支持的车辆属性数据类型。
*
* 用于在VehicleProperty枚举中创建属性ID。
*/
enum VehiclePropertyType : int32_t {
STRING = 0x00100000, // 字符串类型,1048576
BOOLEAN = 0x00200000, // 布尔类型,2097152
INT32 = 0x00400000, // 32位整数类型,4194304
INT32_VEC = 0x00410000, // 32位整数向量类型,4259840
INT64 = 0x00500000, // 64位整数类型,5242880
INT64_VEC = 0x00510000, // 64位整数向量类型,5308416
FLOAT = 0x00600000, // 浮点数类型,6291456
FLOAT_VEC = 0x00610000, // 浮点数向量类型,6356992
BYTES = 0x00700000, // 字节类型,7340032
/**
* 标量或向量类型的任意组合。具体格式必须在属性的描述中提供。
*
* 对于供应商的混合类型属性,configArray需要按照以下结构进行格式化。
*
* configArray[0],1表示属性具有字符串值
* configArray[1],1表示属性具有布尔值。
* configArray[2],1表示属性具有整数值。
* configArray[3],数字表示属性中整数数组的大小。
* configArray[4],1表示属性具有长整数值。
* configArray[5],数字表示属性中长整数数组的大小。
* configArray[6],1表示属性具有浮点数值。
* configArray[7],数字表示属性中浮点数数组的大小。
* configArray[8],数字表示属性中字节数组的大小。
* 例如:
* {@code configArray = {1, 1, 1, 3, 0, 0, 0, 0, 0}} 表示属性具有
* 字符串值、布尔值、整数值和一个包含3个整数的数组。
*/
MIXED = 0x00e00000, // 混合类型,14680064
MASK = 0x00ff0000 // 属性类型掩码,16711680
};
VehicleArea¶
车辆区域类型
hardware/interfaces/automotive/vehicle/2.0/types.hal
/**
* 车辆区域
* 用于构建 VehicleProperty 枚举中的属性ID。
*
* 一些属性可能与特定的车辆区域相关联。例如,VehicleProperty:DOOR_LOCK 属性必须与特定的车门相关联,
* 因此该属性必须标记为 VehicleArea:DOOR 标志。
*
* 其他属性可能与特定的车辆区域无关。这些属性必须具有 VehicleArea:GLOBAL 标志。
*
* [定义] 区域:区域表示 AreaType 的一个唯一元素。例如,如果 AreaType 是 WINDOW ,则一个区域可以是 FRONT_WINDSHIELD 。
*
* [定义] 区域ID:区域ID 是一个或多个区域的组合,使用 Area 枚举的位掩码表示。不同的 AreaType 不能在一个单独的 AreaID 中混合。
* 例如,窗口区域不能与座位区域组合在一个 AreaID 中。
*
* 映射分区属性到区域ID 的规则:
* - 属性必须映射到一个在属性值更改时受影响的 AreaID 数组。
* - 数组中的每个元素必须表示一个 AreaID ,在该 AreaID 中,属性值只能在 AreaID 中的所有区域中同时更改,而不能独立更改。
* 也就是说,当属性值在数组中的一个区域中更改时,它必须自动在 AreaID 中的所有其他区域中更改。
* - 属性值必须在数组中的任意两个不同的 AreaID 中独立可控。
* - 区域在 AreaID 数组中只能出现一次。也就是说,一个区域只能是 AreaID 数组中的一个区域。
*
* [定义] 全局属性:适用于整个车辆并且不与特定区域相关联的属性。例如,FUEL_LEVEL,HVAC_STEERING_WHEEL_HEAT。
*
* 映射全局属性到区域ID 的规则:
* - 全局属性不得映射到区域ID。
*/
enum VehicleArea : int32_t {
GLOBAL = 0x01000000, // 16777216
WINDOW = 0x03000000, // WINDOW映射到VehicleAreaWindow枚举,50331648
MIRROR = 0x04000000, // MIRROR映射到VehicleAreaMirror枚举,67108864
SEAT = 0x05000000, // SEAT映射到VehicleAreaSeat枚举,83886080
DOOR = 0x06000000, // DOOR映射到VehicleAreaDoor枚举,100663296
WHEEL = 0x07000000, // WHEEL映射到VehicleAreaWheel枚举,117440512
MASK = 0x0f000000, //251658240
};
VehiclePropertyGroup¶
车辆属性分组类型
hardware/interfaces/automotive/vehicle/2.0/types.hal
/**
* 定义了属性组的枚举类型。
*
* 用于在VehicleProperty枚举中创建属性ID。
*/
enum VehiclePropertyGroup : int32_t {
/**
*
*/
SYSTEM = 0x10000000, // 在AOSP中声明的属性必须使用此标志, 268435456
/**
*
*/
VENDOR = 0x20000000, // 由供应商声明的属性必须使用此标志, 536870912
MASK = 0xf0000000, // -268435456 ?
};
VehicleAreaWindow¶
车辆窗户区域属性
hardware/interfaces/automotive/vehicle/2.0/types.hal
/**
* 定义了车辆中的各种挡风玻璃/窗户。
*/
enum VehicleAreaWindow : int32_t {
FRONT_WINDSHIELD = 0x00000001, // 前挡风玻璃,1
REAR_WINDSHIELD = 0x00000002, // 后挡风玻璃,2
ROW_1_LEFT = 0x00000010, // 第一排左侧窗户,16
ROW_1_RIGHT = 0x00000040, // 第一排右侧窗户,64
ROW_2_LEFT = 0x00000100, // 第二排左侧窗户,256
ROW_2_RIGHT = 0x00000400, // 第二排右侧窗户,1024
ROW_3_LEFT = 0x00001000, // 第三排左侧窗户,4096
ROW_3_RIGHT = 0x00004000, // 第三排右侧窗户,16384
ROOF_TOP_1 = 0x00010000, // 顶部1号窗户,65536
ROOF_TOP_2 = 0x00020000, // 顶部2号窗户,131072
};
VehiclePropertyAccess¶
车辆属性访问权限
hardware/interfaces/automotive/vehicle/2.0/types.hal
/**
* Property config 定义了它的功能。API的用户必须首先获取 property config,
* 以了解 get() 命令的输出,并确保 set() 或 events 命令与预期输出同步。
*/
enum VehiclePropertyAccess : int32_t {
NONE = 0x00, // 没有访问权限,0
READ = 0x01, // 只读权限,1
WRITE = 0x02, // 只写权限,2
READ_WRITE = 0x03, // 读写权限,3
};
VehiclePropertyChangeMode¶
车辆属性变化模式
hardware/interfaces/automotive/vehicle/2.0/types.hal
/**
* 描述属性值如何变化的枚举类型
*/
enum VehiclePropertyChangeMode : int32_t {
/**
* 此类型的属性不能被更改。不支持对这些属性进行 subscribe 订阅。只能 IVehicle.get() 获取
*/
STATIC = 0x00,
/**
* ON_CHANGE 这个类型的属性当变化时必须上报
* 此类型的属性在发生变化时必须报告。 IVehicle.get() 调用必须返回当前值。
* 对于此属性的设置操作被假定为异步的。当在 IVehicle.set() 之后读取属性(使用 IVehicle.get() )时,
* 它可能仍然返回旧值,直到支持此属性的底层硬件实际上改变了状态。一旦状态改变,属性必须作为事件分发已更改的值。
*/
ON_CHANGE = 0x01,
/**
* 此类型的属性连续变化,并且需要固定的采样率来检索数据。实现者可以选择在重要的值变化时发送额外的通知。
*/
CONTINUOUS = 0x02,
};
SubscribeOptions¶
车辆属性事件订阅信息
hardware/interfaces/automotive/vehicle/2.0/types.hal
/**
* 封装了有关订阅车辆属性事件的信息。
*/
struct SubscribeOptions {
/** 要订阅的属性 */
int32_t propId;
/**
* 采样率,以赫兹(Hz)为单位。
*
* 对于具有 VehiclePropertyChangeMode::CONTINUOUS 的属性,必须提供。
* 该值必须在给定属性的 VehiclePropConfig#minSamplingRate .. VehiclePropConfig#maxSamplingRate 范围内。
* 此值表示客户端希望每秒接收多少次更新。
*/
float sampleRate;
/** 指示要监听哪些事件源的标志。 */
SubscribeFlags flags;
};
enum SubscribeFlags : int32_t {
UNDEFINED = 0x0,
/**
* 订阅来自车辆HAL的事件
* (很可能是车辆本身产生的事件)。
*/
EVENTS_FROM_CAR = 0x1,
/**
* 使用此标志订阅当车辆HAL的客户端(例如Car Service)调用 IVehicle.set(...) 时的事件。
*/
EVENTS_FROM_ANDROID = 0x2,
};
VehicleAreaSeat¶
车辆座椅属性
hardware/interfaces/automotive/vehicle/2.0/types.hal
/**
* 不同的车辆座位。
*/
enum VehicleAreaSeat : int32_t {
ROW_1_LEFT = 0x0001, // 第一排左侧座位, 1
ROW_1_CENTER = 0x0002, // 第一排中间座位, 2
ROW_1_RIGHT = 0x0004, // 第一排右侧座位, 4
ROW_2_LEFT = 0x0010, // 第二排左侧座位, 16
ROW_2_CENTER = 0x0020, // 第二排中间座位, 32
ROW_2_RIGHT = 0x0040, // 第二排右侧座位, 64
ROW_3_LEFT = 0x0100, // 第三排左侧座位, 256
ROW_3_CENTER = 0x0200, // 第三排中间座位, 512
ROW_3_RIGHT = 0x0400 // 第三排右侧座位, 1024
};
StatusCode¶
接口调用状态值
hardware/interfaces/automotive/vehicle/2.0/types.hal
/**
* 车辆HAL接口中使用的错误代码。
*/
enum StatusCode : int32_t {
OK = 0,
// 再试一次
TRY_AGAIN = 1,
// 提供的参数无效
INVALID_ARG = 2,
// 当与车辆属性关联的设备不可用时,必须返回此代码。例如,当客户端尝试在整个HVAC单元关闭时设置HVAC温度。
NOT_AVAILABLE = 3,
// 访问被拒绝
ACCESS_DENIED = 4,
// 在车辆HAL中发生了意外情况
INTERNAL_ERROR = 5,
};
IVehicle.hal¶
hardware/interfaces/automotive/vehicle/2.0/IVehicle.hal
interface IVehicle {
/**
* 返回此车辆HAL支持的所有属性配置的列表。
*/
getAllPropConfigs() generates (vec<VehiclePropConfig> propConfigs);
/**
* 返回给定属性的属性配置列表。
*
* 如果未找到请求的 VehicleProperty ,则必须返回 StatusCode::INVALID_ARG,
* 否则返回带有 StatusCode::OK 的车辆属性配置列表。
*/
getPropConfigs(vec<int32_t> props)
generates (StatusCode status, vec<VehiclePropConfig> propConfigs);
/**
* 获取车辆属性值。
*
* 对于 VehiclePropertyChangeMode::STATIC 属性,此方法必须始终返回相同的值。
* 对于 VehiclePropertyChangeMode::ON_CHANGE 属性,它必须返回最新可用的值。
*
* 一些属性(如 RADIO_PRESET )需要在GET请求中传递 VehiclePropValue 对象中的附加数据。
*
* 如果尚无可用数据,即在初始阶段可能发生的情况下,此调用必须立即返回 StatusCode::TRY_AGAIN 的错误代码。
*/
get(VehiclePropValue requestedPropValue)
generates (StatusCode status, VehiclePropValue propValue);
/**
* 设置车辆属性值。
*
* 忽略数据的时间戳。
*
* 设置某些属性需要有初始状态可用。如果初始数据尚不可用,则此调用必须返回 StatusCode::TRY_AGAIN。
* 对于具有单独电源控制的属性,如果未启动属性,则此调用必须返回 StatusCode::NOT_AVAILABLE错误。
*/
set(VehiclePropValue propValue) generates (StatusCode status);
/**
* 订阅属性事件。
*
* 客户端必须能够根据选项参数中提供的数据订阅多个属性。
*
* @param listener 此客户端必须在适当的事件上被调用。
* @param options 订阅的选项列表。SubscribeOption包含诸如属性Id、区域Id、采样率等信息。
*/
subscribe(IVehicleCallback callback, vec<SubscribeOptions> options)
generates (StatusCode status);
/**
* 取消订阅属性事件。
*
* 如果此客户端未订阅给定属性,则此方法必须返回StatusCode::INVALID_ARG。
*/
unsubscribe(IVehicleCallback callback, int32_t propId)
generates (StatusCode status);
/**
* 打印车辆HAL的调试状态。
*/
debugDump() generates (string s);
};
IVehicleCallback.hal¶
hardware/interfaces/automotive/vehicle/2.0/IVehicleCallback.hal
interface IVehicleCallback {
/**
* 当API用户订阅的变量需要报告时,会触发此事件回调。这可能是基于阈值和频率(常规订阅,参见subscribe调用的参数),
* 或者当调用 IVehicle.set() 方法并且需要报告实际更改时。
*
* 这些回调是分块的。
*
* @param values 更新的值。
*/
oneway onPropertyEvent(vec<VehiclePropValue> propValues);
/**
* 如果客户端使用 SubscribeFlags::EVENTS_FROM_ANDROID 标志订阅了属性,并且调用了 IVehicle.set(...) 方法,
* 则会调用此方法。
*
* 这些事件必须立即传递给订阅者,不进行任何批处理。
*
* @param value 客户端设置的值。
*/
oneway onPropertySet(VehiclePropValue propValue);
/**
* 设置属性值通常是异步操作。因此,即使客户端从IVehicle::set(...)收到StatusCode::OK,
* 这也不能保证该值已成功传播到车辆网络。如果发生这种罕见的事件,必须调用此方法。
*
* @param errorCode - StatusCode枚举中的任何值。
* @param property - 发生错误的属性。
* @param areaId - 指定发生问题的区域的位掩码,对于全局属性必须为0。
*/
oneway onPropertySetError(StatusCode errorCode,
int32_t propId,
int32_t areaId);
};
VehicleHal 获取(设置)属性¶
subscribe订阅属性¶
CarService.onCreate()¶
CarService 在 onCreate() 中创建 ICarImpl
packages/services/Car/service/src/com/android/car/CarService.java
@Override
public void onCreate() {
...
mVehicle = getVehicle();
mICarImpl = new ICarImpl(this,
mVehicle,
SystemInterface.Builder.defaultSystemInterface(this).build(),
mVehicleInterfaceName);
mICarImpl.init();
...
}
创建 ICarImpl 的时候传了 mVehicle 进去,也就是 IVehicle 。
packages/services/Car/service/src/com/android/car/CarService.java
@Nullable
private static IVehicle getVehicle() {
final String instanceName = SystemProperties.get("ro.vehicle.hal", "default");
try {
return android.hardware.automotive.vehicle.V2_0.IVehicle.getService(instanceName);
} catch (RemoteException e) {
Slog.e(CarLog.TAG_SERVICE, "Failed to get IVehicle/" + instanceName + " service", e);
} catch (NoSuchElementException e) {
Slog.e(CarLog.TAG_SERVICE, "IVehicle/" + instanceName + " service not registered yet");
}
return null;
}
好家伙,就是 VehicleHAl 服务。
ICarImpl构造函数¶
构造函数中 new VehicleHal 对象,然后又在 CarImpl 的 init() 函数中调用 VehicleHal 对象的 init() 函数
packages/services/Car/service/src/com/android/car/ICarImpl.java
public ICarImpl(Context serviceContext, IVehicle vehicle, SystemInterface systemInterface,
String vehicleInterfaceName) {
this(serviceContext, vehicle, systemInterface, vehicleInterfaceName,
/* carUserService= */ null, /* carWatchdogService= */ null,
/* powerPolicyDaemon= */ null);
}
@VisibleForTesting
ICarImpl(Context serviceContext, IVehicle vehicle, SystemInterface systemInterface,
String vehicleInterfaceName,
@Nullable CarUserService carUserService,
@Nullable CarWatchdogService carWatchdogService,
@Nullable ICarPowerPolicySystemNotification powerPolicyDaemon) {
...
mHal = constructWithTrace(t, VehicleHal.class,
() -> new VehicleHal(serviceContext, vehicle));
...
}
@MainThread
void init() {
...
mHal.init();
...
}
VehicleHal¶
构造函数new各个HalService(继承于 HalServiceBase ),并且 new HalClient 客户端对象。
packages/services/Car/service/src/com/android/car/hal/VehicleHal.java
public VehicleHal(Context context, IVehicle vehicle) {
mHandlerThread = CarServiceUtils.getHandlerThread(
VehicleHal.class.getSimpleName());
mHandler = new Handler(mHandlerThread.getLooper());
mPowerHal = new PowerHalService(this);
mPropertyHal = new PropertyHalService(this);
mInputHal = new InputHalService(this);
mVmsHal = new VmsHalService(context, this);
mUserHal = new UserHalService(this);
mDiagnosticHal = new DiagnosticHalService(this);
mClusterHalService = new ClusterHalService(this);
mEvsHal = new EvsHalService(this);
mTimeHalService = new TimeHalService(context, this);
//TODO(b/202396546): Dedupe this assignment with the other one in constructor below
mAllServices.addAll(Arrays.asList(mPowerHal,
mInputHal,
mDiagnosticHal,
mVmsHal,
mUserHal,
mClusterHalService,
mEvsHal,
mTimeHalService,
mPropertyHal)); // mPropertyHal should be the last.
mHalClient = new HalClient(vehicle, mHandlerThread.getLooper(),
/* callback= */ this);
}
getAllPropConfigs()¶
mHalClient.getAllPropConfigs() 从 Vehicle HAL(IVehicle.hal) 获取所有的属性。 调用到VehicleHalManager.cpp 的 getAllPropConfigs() 函数。
packages/services/Car/service/src/com/android/car/hal/VehicleHal.java
public void init() {
fetchAllPropConfigs();
...
}
private void fetchAllPropConfigs() {
synchronized (mLock) {
if (!mAllProperties.isEmpty()) { // already set
Slog.i(CarLog.TAG_HAL, "fetchAllPropConfigs already fetched");
return;
}
}
ArrayList<VehiclePropConfig> configs;
try {
configs = mHalClient.getAllPropConfigs();
if (configs == null || configs.size() == 0) {
Slog.e(CarLog.TAG_HAL, "getAllPropConfigs returned empty configs");
return;
}
} catch (RemoteException e) {
throw new RuntimeException("Unable to retrieve vehicle property configuration", e);
}
synchronized (mLock) {
// Create map of all properties
for (VehiclePropConfig p : configs) {
if (DBG) {
Slog.i(CarLog.TAG_HAL, "Add config for prop:" + Integer.toHexString(p.prop)
+ " config:" + p);
}
mAllProperties.put(p.prop, p);
}
}
}
VehicleHal.init()¶
在 init() 中调用 fetchAllPropConfigs() 获取到所有的属性,并保存在 mAllProperties 变量中。 接着还有一件很重要的事情是,给每个服务更新对应的属性。
packages/services/Car/service/src/com/android/car/hal/VehicleHal.java
public void init() {
fetchAllPropConfigs();
// PropertyHalService will take most properties, so make it big enough.
ArrayList<VehiclePropConfig> configsForService = new ArrayList<>(mAllServices.size());
for (int i = 0; i < mAllServices.size(); i++) {
HalServiceBase service = mAllServices.get(i);
int[] supportedProps = service.getAllSupportedProperties();
configsForService.clear();
synchronized (mLock) {
if (supportedProps.length == 0) {
for (Integer propId : mAllProperties.keySet()) {
if (service.isSupportedProperty(propId)) {
VehiclePropConfig config = mAllProperties.get(propId);
mPropertyHandlers.append(propId, service);
configsForService.add(config);
}
}
} else {
for (int prop : supportedProps) {
VehiclePropConfig config = mAllProperties.get(prop);
if (config == null) {
continue;
}
mPropertyHandlers.append(prop, service);
configsForService.add(config);
}
}
}
service.takeProperties(configsForService);
service.init();
}
}
根据签名的构造函数,我们知道 mAllServices 就是各个 HalService,这里我们拿 PowerHalService 举例。
PowerHalService.getAllSupportedProperties()¶
PowerHalService支持的所有属性是: - AP_POWER_STATE_REQ - AP_POWER_STATE_REPORT - DISPLAY_BRIGHTNESS
packages/services/Car/service/src/com/android/car/hal/PowerHalService.java
public class PowerHalService extends HalServiceBase {
private static final int[] SUPPORTED_PROPERTIES = new int[]{
AP_POWER_STATE_REQ,
AP_POWER_STATE_REPORT,
DISPLAY_BRIGHTNESS
};
@Override
public int[] getAllSupportedProperties() {
return SUPPORTED_PROPERTIES;
}
}
在回到前面的 init() 函数,从 PowerHalService.getAllSupportedProperties() 是有获取到支持属性的;所以接着从 mAllProperties 去寻找是否有配置,最后调用 PowerHalService.takeProperties(configsForService) 更新
packages/services/Car/service/src/com/android/car/hal/VehicleHal.java
public void init() {
...
// PropertyHalService will take most properties, so make it big enough.
ArrayList<VehiclePropConfig> configsForService = new ArrayList<>(mAllServices.size());
for (int i = 0; i < mAllServices.size(); i++) {
HalServiceBase service = mAllServices.get(i);
int[] supportedProps = service.getAllSupportedProperties();//有属性
configsForService.clear();
synchronized (mLock) {
if (supportedProps.length == 0) {//所以不进这里
for (Integer propId : mAllProperties.keySet()) {
if (service.isSupportedProperty(propId)) {
VehiclePropConfig config = mAllProperties.get(propId);
mPropertyHandlers.append(propId, service);
configsForService.add(config);
}
}
} else {
for (int prop : supportedProps) {
//从 hal 里查到是否有匹配的
VehiclePropConfig config = mAllProperties.get(prop);
if (config == null) {
continue;
}
// 有则添加到 configsForService
mPropertyHandlers.append(prop, service);
configsForService.add(config);
}
}
}
service.takeProperties(configsForService);
service.init();
}
}
PowerHalService.takeProperties()¶
packages/services/Car/service/src/com/android/car/hal/PowerHalService.java
public class PowerHalService extends HalServiceBase {
@GuardedBy("mLock")
private final HashMap<Integer, VehiclePropConfig> mProperties = new HashMap<>();
@Override
public void takeProperties(Collection<VehiclePropConfig> properties) {
if (properties.isEmpty()) {
return;
}
synchronized (mLock) {
for (VehiclePropConfig config : properties) {
mProperties.put(config.prop, config);
}
}
}
}
PowerHalService.init()¶
调用 mHal.subscribeProperty(this, config.prop); 订阅属性。
packages/services/Car/service/src/com/android/car/hal/PowerHalService.java
public class PowerHalService extends HalServiceBase {
@Override
public void init() {
synchronized (mLock) {
for (VehiclePropConfig config : mProperties.values()) {
if (VehicleHal.isPropertySubscribable(config)) {
mHal.subscribeProperty(this, config.prop);
}
}
VehiclePropConfig brightnessProperty = mProperties.get(DISPLAY_BRIGHTNESS);
if (brightnessProperty != null) {
mMaxDisplayBrightness = brightnessProperty.areaConfigs.size() > 0
? brightnessProperty.areaConfigs.get(0).maxInt32Value : 0;
if (mMaxDisplayBrightness <= 0) {
Slog.w(CarLog.TAG_POWER, "Max display brightness from vehicle HAL is invalid:"
+ mMaxDisplayBrightness);
mMaxDisplayBrightness = 1;
}
}
}
}
}
VehicleHal.subscribeProperty()¶
packages/services/Car/service/src/com/android/car/hal/VehicleHal.java
/**
* Subscribes given properties with sampling rate defaults to 0 and no special flags provided.
*
* @see #subscribeProperty(HalServiceBase, int, float, int)
*/
public void subscribeProperty(HalServiceBase service, int property)
throws IllegalArgumentException {
subscribeProperty(service, property, /* samplingRateHz= */ 0f,
SubscribeFlags.EVENTS_FROM_CAR);
}
public void subscribeProperty(HalServiceBase service, int property,
float samplingRateHz, int flags) throws IllegalArgumentException {
if (DBG) {
Slog.i(CarLog.TAG_HAL, "subscribeProperty, service:" + service
+ ", " + toCarPropertyLog(property));
}
VehiclePropConfig config;
synchronized (mLock) {
config = mAllProperties.get(property);
}
if (config == null) {
throw new IllegalArgumentException("subscribe error: config is null for property 0x"
+ toHexString(property));
} else if (isPropertySubscribable(config)) {
SubscribeOptions opts = new SubscribeOptions();
opts.propId = property;
opts.sampleRate = samplingRateHz;
opts.flags = flags;
synchronized (mLock) {
assertServiceOwnerLocked(service, property);
mSubscribedProperties.put(property, opts);
}
try {
mHalClient.subscribe(opts);
} catch (RemoteException e) {
Slog.e(CarLog.TAG_HAL, "Failed to subscribe to " + toCarPropertyLog(property),
e);
}
} else {
Slog.e(CarLog.TAG_HAL, "Cannot subscribe to " + toCarPropertyLog(property));
}
}
HalClient.subscribe()¶
packages/services/Car/service/src/com/android/car/hal/HalClient.java
public void subscribe(SubscribeOptions... options) throws RemoteException {
mVehicle.subscribe(mInternalCallback, new ArrayList<>(Arrays.asList(options)));
}
最终会调用到 IVehicle.hal 的 subscribe(),也就是 VehicleHalManager.cpp 的 subscribe()
VehicleHalManager.subscribe()¶
hardware/interfaces/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
Return<StatusCode> VehicleHalManager::subscribe(const sp<IVehicleCallback> &callback,
const hidl_vec<SubscribeOptions> &options) {
hidl_vec<SubscribeOptions> verifiedOptions(options); // 创建一个与options相同的verifiedOptions向量
for (size_t i = 0; i < verifiedOptions.size(); i++) { // 遍历verifiedOptions向量
SubscribeOptions& ops = verifiedOptions[i]; // 获取当前遍历到的元素
auto prop = ops.propId; // 获取ops的propId属性
const auto* config = getPropConfigOrNull(prop); // 根据propId获取属性配置信息
if (config == nullptr) {
ALOGE("Failed to subscribe: config not found, property: 0x%x", prop);
return StatusCode::INVALID_ARG; // 返回无效参数错误码
}
if (ops.flags == SubscribeFlags::UNDEFINED) { // 如果ops的flags属性为未定义
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); // 检查并更新ops的sampleRate属性
}
std::list<SubscribeOptions> updatedOptions; // 创建一个空的updatedOptions列表
auto res = mSubscriptionManager.addOrUpdateSubscription(getClientId(callback),
callback, verifiedOptions,
&updatedOptions); // 添加或更新订阅信息,并将更新后的选项存储在updatedOptions列表中
if (StatusCode::OK != res) {
ALOGW("%s failed to subscribe, error code: %d", __func__, res);
return res; // 返回错误码
}
for (auto opt : updatedOptions) { // 遍历updatedOptions列表
mHal->subscribe(opt.propId, opt.sampleRate); // 调用mHal的subscribe方法订阅属性
}
return StatusCode::OK; // 返回成功状态码
}
先检查这属性的配置是否存在,如果不存在则返回错误。接着 SubscriptionManager.addOrUpdateSubscription() 添加或更新订阅信息。
根据前面的分析,mHal 就是 EmulatedVehicleHal , 所以 mHal->subscribe(opt.propId, opt.sampleRate) 就是 EmulatedVehicleHal.subscribe()
EmulatedVehicleHal.subscribe()¶
hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
StatusCode EmulatedVehicleHal::subscribe(int32_t property, float sampleRate) {
ALOGI("%s propId: 0x%x, sampleRate: %f", __func__, property, sampleRate);
if (isContinuousProperty(property)) {
mRecurrentTimer.registerRecurrentEvent(hertzToNanoseconds(sampleRate), property);
}
return StatusCode::OK;
}
isContinuousProperty() 改变 VehiclePropConfig 的 changemode 为 CONTINUOUS(即不断的周期性的发送变化)
以上我们只是拿 PowerHalService ,在 VehicleHal.init() 中会遍历所以的 HalService 去做同样的事情,所以 所有属性都subscribe,CarService就可以所有接收到Vehicle HAL发上来的所有属性变化
同理,unsubscribe注销订阅。
set 设置属性¶
我们还是以 PowerHalService 为例,如下:
packages/services/Car/service/src/com/android/car/hal/PowerHalService.java
private void setPowerState(int state, int additionalParam) {
if (isPowerStateSupported()) {
int[] values = { state, additionalParam };
try {
mHal.set(VehicleProperty.AP_POWER_STATE_REPORT, 0).to(values);
Slog.i(CarLog.TAG_POWER, "setPowerState=" + powerStateReportName(state)
+ " param=" + additionalParam
+ " VehicleProperty.AP_POWER_STATE_REPORT=" + VehicleProperty.AP_POWER_STATE_REPORT);
} catch (ServiceSpecificException e) {
Slog.e(CarLog.TAG_POWER, "cannot set to AP_POWER_STATE_REPORT", e);
}
}
}
mHal 是 VehicleHal,所以会调到 VehicleHal.set() 。看到调到的 VehicleHal.set() 之后,我突然觉得用这个例子来举例不太好。 这里我就用一个简单的代码流程来举例非 car-service 进程怎么设置属性的。
- CarHvacManager.setBooleanProperty()
packages/services/Car/car-lib/src/android/car/hardware/hvac/CarHvacManager.java
public void setBooleanProperty(@PropertyId int propertyId, int area, boolean val) {
if (mHvacPropertyIds.contains(propertyId)) {
mCarPropertyMgr.setBooleanProperty(propertyId, area, val);
}
}
- CarPropertyManager.setProperty()
packages/services/Car/car-lib/src/android/car/hardware/property/CarPropertyManager.java
public void setBooleanProperty(int prop, int areaId, boolean val) {
setProperty(Boolean.class, prop, areaId, val);
}
public <E> void setProperty(@NonNull Class<E> clazz, int propId, int areaId, @NonNull E val) {
...
try {
mService.setProperty(new CarPropertyValue<>(propId, areaId, val),
mCarPropertyEventToService);
...
}
- CarPropertyService.setProperty()
packages/services/Car/service/src/com/android/car/CarPropertyService.java
@Override
public void setProperty(CarPropertyValue prop, ICarPropertyEventListener listener) {
...
mHal.setProperty(prop);
...
}
这里的 mHal 是 PropertyHalService
- PropertyHalService.set()
packages/services/Car/service/src/com/android/car/hal/PropertyHalService.java
public void setProperty(CarPropertyValue prop) {
...
mVehicleHal.set(halProp);
}
- VehicleHal.setValue()
packages/services/Car/service/src/com/android/car/hal/VehicleHal.java
protected void set(VehiclePropValue propValue) {
mHalClient.setValue(propValue);
}
- HalClient.set()
packages/services/Car/service/src/com/android/car/hal/HalClient.java
public void setValue(VehiclePropValue propValue) {
return mVehicle.set(propValue);
}
好,走到这里已经很清晰了。我们还是回到刚才的例子当中。
VehicleHal.set()¶
packages/services/Car/service/src/com/android/car/hal/VehicleHal.java
@CheckResult
VehiclePropValueSetter set(int propId, int areaId) {
return new VehiclePropValueSetter(mHalClient, propId, areaId);
}
packages/services/Car/service/src/com/android/car/hal/VehicleHal.java
final class VehiclePropValueSetter {
final WeakReference<HalClient> mClient;
final VehiclePropValue mPropValue;
private VehiclePropValueSetter(HalClient client, int propId, int areaId) {
mClient = new WeakReference<>(client);
mPropValue = new VehiclePropValue();
mPropValue.prop = propId;
mPropValue.areaId = areaId;
}
void to(boolean value) {
to(value ? 1 : 0);
}
void to(int value) {
mPropValue.value.int32Values.add(value);
submit();
}
void to(int[] values) {
for (int value : values) {
mPropValue.value.int32Values.add(value);
}
submit();
}
void to(Collection<Integer> values) {
mPropValue.value.int32Values.addAll(values);
submit();
}
void submit() {
HalClient client = mClient.get();
if (client != null) {
if (DBG) {
Slog.i(CarLog.TAG_HAL, "set, " + toCarPropertyLog(mPropValue.prop)
+ toCarAreaLog(mPropValue.areaId));
}
client.setValue(mPropValue);
}
}
}
VehicleHal 里有几个 set() 函数,不管是那个 set() 函数,最终都是调 mHalClient.setValue(propValue) 设置属性。
HalClient.setValue()¶
还记得之前在 VehicleHal 构造函数里的 vehicle 是从哪里来的吗? 其实 CarService.getVehicle() 获取到并通过构造 ICarImpl 一步一步传进来的。
packages/services/Car/service/src/com/android/car/hal/VehicleHal.java
public VehicleHal(Context context, IVehicle vehicle) {
...
mHalClient = new HalClient(vehicle, mHandlerThread.getLooper(),
/* callback= */ this);
}
所以 mVehicle 就是 VehicleHal 。也就是 IVehicle.hal 的 set() 接口。 最终是调到 VehicleHalManager.cpp 的 set() 接口。
packages/services/Car/service/src/com/android/car/hal/HalClient.java
public void setValue(VehiclePropValue propValue) {
...
return mVehicle.set(propValue);
...
}
VehicleHalManager.set()¶
hardware/interfaces/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
/**
* @brief 设置车辆属性值
* @param value 要设置的属性值
* @return 返回设置结果的状态码
*/
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); // 调用mHal的set方法设置属性值
return Return<StatusCode>(status); // 返回设置结果的状态码
}
其中这里的 handlePropertySetEvent() 函数非常重要,主要是用来调用 SubscriptionManager 把事件回调到客户端的;关于这一点,我们后面会分析。
现在先看 mHal->set(value) ,还是根据前面的分析,mHal 就是 EmulatedVehicleHal。
EmulatedVehicleHal.set()¶
hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) {
...
// 将值发送给车辆服务器,服务器将与(真实或模拟的)汽车通信
auto setValueStatus = mVehicleClient->setProperty(propValue, updateStatus);
if (setValueStatus != StatusCode::OK) {
return setValueStatus;
}
return StatusCode::OK;
}
通过 VehicleHal 初始化的流程其实可以知道,mVehicleClient 就是 VehicleHalClient 。但这里显然是预留的厂商实现的。 我们通过厂商的代码可以知道 mVehicleClient 是 VehicleClientImpl 。
StatusCode VehicleClientImpl::setProperty(const VehiclePropValue& value, bool updateStatus) {
return mVehicleServer->onSetProperty(value);
}
这里就涉及到厂商自己的业务逻辑了,而从这里我们也知道了,aosp 里 VehicleService 初始化时,并没有创建 VehicleHalClient、VehicleHalServer;而是需要厂商自己的创建。
1. class VehicleHalServer : public property::IPropertyTransfer
2. 在 VehicleHalServer::initAllProperties() 里,会调用 prop->init(this),
3. void Property::init(IPropertyTransfer* transfer) {
mProperty->registerWritePropValueListener(
[transfer](const VehiclePropValue& value, CommitMode mode, bool updateStatus) {
transfer->onPropertyValue(value, mode, updateStatus);
});
}
4. mReportQueue.push(propValue);
5. PropValueStore::PropValueStore() : mReportQueue(true) {
mBatchTaskConsumer.run(&mReportQueue, std::bind(&PropValueStore::onVehiclePropertyValueFromStore,this,std::placeholders::_1), "ReportConsumer");
}
VehicleHalServer::onSetProperty() ->
IProperty::onSetPropertyValue() ->
Area::onSetPropertyAreaValue ->
IProperty::writeToStore() ->
(由1,2,3可知)
VehicleHalServer::onPropertyValue() ->
PropValueStore::writeValue() ->
(由4,5可知)
PropValueStore::onVehiclePropertyValueFromStore() ->
VehicleHalClient::onPropertyValue()
DHUVehicleHal::onPropertyValue()
最终会调到 VehiclePropertyStore 去写属性。
VehiclePropertyStore.writeValue()¶
hardware/interfaces/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
bool VehiclePropertyStore::writeValue(const VehiclePropValue& propValue,
bool updateStatus) {
MuxGuard g(mLock);
// 属性id是否已经注册,如果当前属性id没有注册,则返回false,写入失败。
if (!mConfigs.count(propValue.prop)) return false;
RecordId recId = getRecordIdLocked(propValue); // 获取记录ID
VehiclePropValue* valueToUpdate = const_cast<VehiclePropValue*>(getValueOrNullLocked(recId)); // 获取要更新的值
// 如果当前没有保存该属性,则加入一条新的记录
if (valueToUpdate == nullptr) {
mPropertyValues.insert({ recId, propValue });
return true;
}
// 如果要更新的值的时间戳大于propValue的时间戳,则返回false
if (valueToUpdate->timestamp > propValue.timestamp) {
return false;
}
// 更新valueToUpdate的时间戳和值
// propertyStore中的时间戳应该只由服务器端更新,它表示服务器生成事件的时间
valueToUpdate->timestamp = propValue.timestamp;
valueToUpdate->value = propValue.value;
// 如果需要更新状态,则更新valueToUpdate的状态
if (updateStatus) {
valueToUpdate->status = propValue.status;
}
return true;
}
- 如果要写的属性id 还没有注册,则不写入值,返回失败
- 如果要写的属性id 还没有保存过,这保存在 mPropertyValues 中
- 如果要更新的值的时间戳小于 propValue 的时间戳,则更新
这里有个疑问,更新的值并没有更新到 mPropertyValues,那下次通过 get() 获取不就有问题么?
VehicleHalManager.handlePropertySetEvent()¶
hardware/interfaces/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
void VehicleHalManager::handlePropertySetEvent(const VehiclePropValue& value) {
auto clients =
mSubscriptionManager.getSubscribedClients(value.prop, SubscribeFlags::EVENTS_FROM_ANDROID);
for (const auto& client : clients) {
client->getCallback()->onPropertySet(value);
}
}
hardware/interfaces/automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp
std::list<sp<HalClient>> SubscriptionManager::getSubscribedClients(int32_t propId,
SubscribeFlags flags) const {
MuxGuard g(mLock);
return getSubscribedClientsLocked(propId, flags);
}
std::list<sp<HalClient>> SubscriptionManager::getSubscribedClientsLocked(
int32_t propId, SubscribeFlags flags) const {
std::list<sp<HalClient>> subscribedClients;
sp<HalClientVector> propClients = getClientsForPropertyLocked(propId);
if (propClients.get() != nullptr) {
for (size_t i = 0; i < propClients->size(); i++) {
const auto& client = propClients->itemAt(i);
if (client->isSubscribed(propId, flags)) {
subscribedClients.push_back(client);
}
}
}
return subscribedClients;
}
handlePropertySetEvent 调用 SubscriptionManager.getSubscribedClients() 返回订阅的HalClient对象list列表;然后会遍历 HalClient 调用其 onPropertySet(value) 回调接口。
VehicleCallback¶
packages/services/Car/service/src/com/android/car/hal/HalClient.java
final class HalClient {
private final IVehicleCallback mInternalCallback;
HalClient(IVehicle vehicle, Looper looper, IVehicleCallback callback,
int waitCapMs, int sleepMs) {
mInternalCallback = new VehicleCallback(handler);
}
private static final class VehicleCallback extends IVehicleCallback.Stub {
private final Handler mHandler;
VehicleCallback(Handler handler) {
mHandler = handler;
}
@Override
public void onPropertyEvent(ArrayList<VehiclePropValue> propValues) {
mHandler.sendMessage(Message.obtain(
mHandler, CallbackHandler.MSG_ON_PROPERTY_EVENT, propValues));
}
@Override
public void onPropertySet(VehiclePropValue propValue) {
mHandler.sendMessage(Message.obtain(
mHandler, CallbackHandler.MSG_ON_PROPERTY_SET, propValue));
}
@Override
public void onPropertySetError(int errorCode, int propId, int areaId) {
mHandler.sendMessage(Message.obtain(
mHandler, CallbackHandler.MSG_ON_SET_ERROR,
new PropertySetError(errorCode, propId, areaId)));
}
}
}
回调 onPropertySet() 被触发后,通过sendMessage(),然后 handlemessage() 处理消息。 最后调回到 VehicleHal.onPropertySet() 。
packages/services/Car/service/src/com/android/car/hal/VehicleHal.java
@Override
public void onPropertySet(VehiclePropValue value) {
// No need to handle on-property-set events in HAL service yet.
}
get 获取属性¶
我们还是以 PowerHalService 为例,如下:
packages/services/Car/service/src/com/android/car/hal/PowerHalService.java
@Nullable
public PowerState getCurrentPowerState() {
int[] state;
try {
state = mHal.get(int[].class, VehicleProperty.AP_POWER_STATE_REQ);
} catch (ServiceSpecificException e) {
Slog.e(CarLog.TAG_POWER, "Cannot get AP_POWER_STATE_REQ", e);
return null;
}
return new PowerState(state[VehicleApPowerStateReqIndex.STATE],
state[VehicleApPowerStateReqIndex.ADDITIONAL]);
}
mHal 是 VehicleHal,所以会调到 VehicleHal.get() 。
这里我们还是用一个简单的代码流程来举例非 car-service 进程怎么获取属性的。
- CarHvacManager.getIntProperty()
packages/services/Car/car-lib/src/android/car/hardware/hvac/CarHvacManager.java
public int getIntProperty(@PropertyId int propertyId, int area) {
return mCarPropertyMgr.getIntProperty(propertyId, area);
}
- CarPropertyManager.getProperty()
packages/services/Car/car-lib/src/android/car/hardware/property/CarPropertyManager.java
public int getIntProperty(int prop, int area) {
checkSupportedProperty(prop);
CarPropertyValue<Integer> carProp = getProperty(Integer.class, prop, area);
return handleNullAndPropertyStatus(carProp, area, 0);
}
@Nullable
public <E> CarPropertyValue<E> getProperty(@NonNull Class<E> clazz, int propId, int areaId) {
...
try {
CarPropertyValue<E> propVal = mService.getProperty(propId, areaId);
...
return propVal;
...
}
- CarPropertyService.getProperty()
packages/services/Car/service/src/com/android/car/CarPropertyService.java
@Override
public CarPropertyValue getProperty(int prop, int zone) {
...
return mHal.getProperty(prop, zone);
}
这里的 mHal 是 PropertyHalService
- PropertyHalService.get()
packages/services/Car/service/src/com/android/car/hal/PropertyHalService.java
@Nullable
public CarPropertyValue getProperty(int mgrPropId, int areaId) throws ServiceSpecificException {
...
VehiclePropValue value = mVehicleHal.get(halPropId, areaId);
...
}
- VehicleHal.get()
packages/services/Car/service/src/com/android/car/hal/VehicleHal.java
public VehiclePropValue get(int propertyId, int areaId) {
...
return mHalClient.getValue(createPropValue(propertyId, areaId));
}
- HalClient.getValue()
packages/services/Car/service/src/com/android/car/hal/HalClient.java
VehiclePropValue getValue(VehiclePropValue requestedPropValue) {
...
ValueResult res = internalGet(requestedPropValue);
...
}
private ValueResult internalGet(VehiclePropValue requestedPropValue) {
...
try {
mVehicle.get(requestedPropValue,
(status, propValue) -> {
result.status = status;
result.propValue = propValue;
});
}
...
}
好,走到这里已经很清晰了。我们还是回到刚才的例子当中。
VehicleHal.get()¶
packages/services/Car/service/src/com/android/car/hal/VehicleHal.java
public <T> T get(Class clazz, VehiclePropValue requestedPropValue) {
VehiclePropValue propValue;
propValue = mHalClient.getValue(requestedPropValue);
if (clazz == Long.class || clazz == long.class) {
return (T) propValue.value.int64Values.get(0);
} else if (clazz == Integer.class || clazz == int.class) {
return (T) propValue.value.int32Values.get(0);
} else if (clazz == Boolean.class || clazz == boolean.class) {
return (T) Boolean.valueOf(propValue.value.int32Values.get(0) == 1);
} else if (clazz == Float.class || clazz == float.class) {
return (T) propValue.value.floatValues.get(0);
} else if (clazz == Long[].class) {
Long[] longArray = new Long[propValue.value.int64Values.size()];
return (T) propValue.value.int32Values.toArray(longArray);
} else if (clazz == Integer[].class) {
Integer[] intArray = new Integer[propValue.value.int32Values.size()];
return (T) propValue.value.int32Values.toArray(intArray);
} else if (clazz == Float[].class) {
Float[] floatArray = new Float[propValue.value.floatValues.size()];
return (T) propValue.value.floatValues.toArray(floatArray);
} else if (clazz == long[].class) {
return (T) toLongArray(propValue.value.int64Values);
} else if (clazz == int[].class) {
return (T) toIntArray(propValue.value.int32Values);
} else if (clazz == float[].class) {
return (T) toFloatArray(propValue.value.floatValues);
} else if (clazz == byte[].class) {
return (T) toByteArray(propValue.value.bytes);
} else if (clazz == String.class) {
return (T) propValue.value.stringValue;
} else {
throw new IllegalArgumentException("Unexpected type: " + clazz);
}
}
VehicleHal 里有几个 get() 函数,不管是那个 get() 函数,最终都是调 mHalClient.getValue() 获取属性。
HalClient.getValue()¶
packages/services/Car/service/src/com/android/car/hal/HalClient.java
VehiclePropValue getValue(VehiclePropValue requestedPropValue) {
final ObjectWrapper<VehiclePropValue> valueWrapper = new ObjectWrapper<>();
int status = invokeRetriable(() -> {
ValueResult res = internalGet(requestedPropValue);
valueWrapper.object = res.propValue;
return res.status;
}, mWaitCapMs, mSleepMs);
...
}
private ValueResult internalGet(VehiclePropValue requestedPropValue) {
final ValueResult result = new ValueResult();
try {
mVehicle.get(requestedPropValue,
(status, propValue) -> {
result.status = status;
result.propValue = propValue;
});
} catch (RemoteException e) {
Slogf.e(TAG, getValueErrorMessage("get", requestedPropValue), e);
result.status = StatusCode.TRY_AGAIN;
}
return result;
}
根据前面的分析 mVehicle 是 VehicleHal 。也就是 IVehicle.hal 的 get() 接口。 最终是调到 VehicleHalManager.cpp 的 get() 接口。
VehicleHalManager.get()¶
hardware/interfaces/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
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); // 回调ACCESS_DENIED错误码和空值
return Void(); // 返回空值
}
StatusCode status;
auto value = mHal->get(requestedPropValue, &status); // 调用mHal的get方法获取属性值
_hidl_cb(status, value.get() ? *value : kEmptyValue); // 回调获取的状态码和属性值(如果有)
return Void(); // 返回空值
}
还是根据前面的分析,mHal 就是 EmulatedVehicleHal。
EmulatedVehicleHal.get()¶
hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get(
const VehiclePropValue& requestedPropValue, StatusCode* outStatus) {
auto propId = requestedPropValue.prop;
ALOGV("get(%d)", propId);
auto& pool = *getValuePool();
VehiclePropValuePtr v = nullptr; // 定义一个指向VehiclePropValue的智能指针v,并初始化为nullptr
// 根据propId来获取值
// OBD2_FREEZE_FRAME 是 0BD 检测到故障信息
// 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:
// 如果 EmulatedUserHal 支持这个属性,则调用 EmulatedUserHal.onGetProperty() 函数获取属性值
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;
}
// 空调电源属性
if (mHvacPowerProps.count(propId)) {
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) {
*outStatus = StatusCode::NOT_AVAILABLE; // 将状态码设置为NOT_AVAILABLE
break;
}
}
// mPropStore 就是 VehiclePropertyStore ,也就是从 VehiclePropertyStore 获取属性
auto internalPropValue = mPropStore->readValueOrNull(requestedPropValue);
if (internalPropValue != nullptr) {
v = getValuePool()->obtain(*internalPropValue);
}
if (!v) {
*outStatus = StatusCode::INVALID_ARG;
} else if (v->status == VehiclePropertyStatus::AVAILABLE) {
*outStatus = StatusCode::OK;
} else {
*outStatus = StatusCode::TRY_AGAIN;
}
break;
}
if (v.get()) {
v->timestamp = elapsedRealtimeNano();
}
return v;
}
这里其实很简单: - 故障 相关的属性,则相关函数单独出来,但最终都还是调用到 VehiclePropertyStore 里获取的。 - EmulatedUserHal 支持这个属性,则从 EmulatedUserHal 获取 - 空调电源属性,单独处理 - 如果以上情况都不满足,则正常从 VehiclePropertyStore 获取属性。
VehiclePropertyStore¶
hardware/interfaces/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
std::unique_ptr<VehiclePropValue> VehiclePropertyStore::readValueOrNull(
const VehiclePropValue& request) const {
MuxGuard g(mLock);
RecordId recId = getRecordIdLocked(request);
const VehiclePropValue* internalValue = getValueOrNullLocked(recId);
return internalValue ? std::make_unique<VehiclePropValue>(*internalValue) : nullptr;
}
std::unique_ptr<VehiclePropValue> VehiclePropertyStore::readValueOrNull(
int32_t prop, int32_t area, int64_t token) const {
RecordId recId = {prop, isGlobalProp(prop) ? 0 : area, token };
MuxGuard g(mLock);
const VehiclePropValue* internalValue = getValueOrNullLocked(recId);
return internalValue ? std::make_unique<VehiclePropValue>(*internalValue) : nullptr;
}
const VehiclePropValue* VehiclePropertyStore::getValueOrNullLocked(
const VehiclePropertyStore::RecordId& recId) const {
auto it = mPropertyValues.find(recId);
return it == mPropertyValues.end() ? nullptr : &it->second;
}
从这里可以看出来,VehicleHal 配置的这些车辆相关的属性,其实并没有通过数据库或者文件进程存储。而是通过 VehiclePropertyStore 存储在内存中。
其实前面我们提到 VehiclePropertyStore 的类,其中有一个 registerProperty() 函数,就是每次进程起来的时候把所有的属性都加载到内存中。
//hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h
class EmulatedVehicleHalIface : public VehicleHal{.....}
//hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
class EmulatedVehicleHal : public EmulatedVehicleHalIface{....}
//hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get(
const VehiclePropValue& requestedPropValue, StatusCode* outStatus) {
auto propId = requestedPropValue.prop;
auto& pool = *getValuePool();
VehiclePropValuePtr v = nullptr;
switch (propId) {
case OBD2_FREEZE_FRAME:
v = pool.obtainComplex();
*outStatus = fillObd2FreezeFrame(requestedPropValue, v.get());
break;
case OBD2_FREEZE_FRAME_INFO:
v = pool.obtainComplex();
*outStatus = fillObd2DtcInfo(v.get());
break;
default:
auto internalPropValue = mPropStore->readValueOrNull(requestedPropValue);
if (internalPropValue != nullptr) {
v = getValuePool()->obtain(*internalPropValue);
}
*outStatus = v != nullptr ? StatusCode::OK : StatusCode::INVALID_ARG;
break;
}
return v;
}
-
VehiclePropertyStore.cpp - readValueOrNull
-
getRecordIdLocked 根据入参VehiclePropValue获取RecordId,关于VehiclePropValue对象可查看上层VehicleHal.java的get函数的流程
-
调用getValueOrNullLocked,根据RecordId从VehiclePropertyStore中读取
//VehiclePropertyStore.cpp
VehiclePropertyStore::RecordId VehiclePropertyStore::getRecordIdLocked(
const VehiclePropValue& valuePrototype) const {
RecordId recId = {
.prop = valuePrototype.prop,
.area = isGlobalProp(valuePrototype.prop) ? 0 : valuePrototype.areaId,
.token = 0
};
auto it = mConfigs.find(recId.prop);
if (it == mConfigs.end()) return {};
if (it->second.tokenFunction != nullptr) {
recId.token = it->second.tokenFunction(valuePrototype);
}
return recId;
}
const VehiclePropValue* VehiclePropertyStore::getValueOrNullLocked(
const VehiclePropertyStore::RecordId& recId) const {
auto it = mPropertyValues.find(recId);
return it == mPropertyValues.end() ? nullptr : &it->second;
}
//VehiclePropertyStore.h
class VehiclePropertyStore {
...
struct RecordId {
int32_t prop;
int32_t area;
int64_t token;
bool operator==(const RecordId& other) const;
bool operator<(const RecordId& other) const;
};
using PropertyMap = std::map<RecordId, VehiclePropValue>;
.....
PropertyMap mPropertyValues;
}
附录¶
文中提到的一个接口文件会在编译的时候自动生成,主要目录是在:
out/soong/.intermediates/hardware/interfaces/automotive/vehicle/2.0
android.hardware.automotive.vehicle@2.0_genc++
android.hardware.automotive.vehicle@2.0_genc++_headers
android.hardware.automotive.vehicle-V2.0-java_gen_java