VHAL 接口

AIDL VHAL 在 android.hardware.automotive.vehicle namespace 中定义。 VHAL 接口在 IVehicle.aidl 中定义。 除非另有说明,否则必须实现所有方法。

方法
VehiclePropConfigs getAllPropConfigs()
返回此车载 HAL 支持的所有属性配置列表。
VehiclePropConfigs getPropConfigs(in int[] props)
返回指定属性 ID 的属性配置列表。
void getValues(IVehicleCallback callback, in GetValueRequests requests)
异步获取车辆属性值。异步处理一批 GetValueRequest。结果通过回调的 onGetValues 方法传递。
void setValues(IVehicleCallback callback, in SetValueRequests requests)
异步设置车辆属性值。异步处理一批 SetValueRequest。结果通过回调的 onSetValues 方法传递。
void subscribe(in IVehicleCallback callback, in SubscribeOptions[] options, int maxSharedMemoryFileCount)
使用指定选项订阅属性事件。订阅选项包括属性 ID、属性区域 ID 以及以 Hz 为单位的采样率(对于连续属性)。 未使用 maxSharedMemoryFileCount
void unsubscribe(in IVehicleCallback callback, in int[] propIds)
取消订阅指定属性之前订阅的属性事件。
returnSharedMemory(in IVehicleCallback callback, long sharedMemoryId)
不使用,可以作为空操作实现。

回调在 IVehicleCallback.aidl 中定义,并包含这些方法。

方法
oneway void onGetValues(in GetValueResults responses)
用于传递获取值结果的 getValues 函数的回调。在要提取的某些值准备就绪时调用。
oneway void onSetValues(in SetValueResults responses)
用于传递设定值结果的 setValues 函数的回调。在 VHAL 处理完某些属性设置请求时调用。
oneway void onPropertyEvent(in VehiclePropValues propValues, int sharedMemoryFileCount)
用于报告属性更新事件的回调。
CONTINUOUS 属性,系统会根据订阅采样率(以 Hz 为单位)或车载总线消息频率发生属性事件。如果属性的状态发生变化,也有可能发生属性事件。例如,从不可用变成可用。
对于 ON_CHANGE 属性,当属性值或属性的状态发生更改时,就会发生属性事件。
SharedMemoryFileCount 始终为 0
oneway void onPropertySetError(in VehiclePropErrors errors)
用于报告异步属性 set 错误(没有对应的 set 请求)的回调。如果我们知道错误是针对哪个 set 请求,则必须使用带有错误结果的 onSetValues,而不是此方法。

如需了解详情,请参阅 IVehicle.aidlIVehicleCallback.aidl

VHAL 实现由 VtsHalAutomotiveVehicle_TargetTest.cpp 中的 VHAL VTS 进行验证。此测试可验证基本方法是否已正确实现,以及支持的属性配置是否正确。

车辆属性值

请使用 VehiclePropValue 结构描述每个属性的值,其中包含以下字段:

字段 说明
timestamp 表示事件发生时间的时间戳,与 SystemClock.elapsedRealtimeNano() 时钟同步。
prop 此值的属性 ID。
areaid 此值的区域 ID。该区域必须是区域 ID 配置中列出的某个受支持区域;对于全局属性,该区域必须是 0
value 包含实际属性值的数据结构。根据属性类型,此字段中的一个或多个字段将用于存储实际值。例如,value.int32Values 中的第一个元素用于 Int32 类型属性。如需了解详情,请参阅属性配置

异步 getValues 和 setValues

getValuessetValues 操作是异步执行的,这意味着函数可能会在实际的 get 或 set 操作完成之前返回结果。操作结果(例如,getValues 的属性值和 setValues 的成功或错误状态)通过作为参数传递的回调传递。

实现不得对处理请求的 binder 线程中的结果进行阻塞。相反,我们建议您将请求存储在请求队列中,并使用单独的处理程序线程异步处理请求。如需了解详情,请参阅参考实现

图 1. 异步进程。

大型 Parcelable

所有名为 XXXs 的结构(例如 VehiclePropConfigsSetValueRequestsVehiclePropValues)都称为 LargeParcelable(或 StableLargeParcelable)。每个结构代表一个值列表,用于跨 binder 边界传递可能超出 binder 限制(在 LargeParcelable 库实现中为 4KB)的大型数据。每个结构都具有类似的结构定义,其中包含以下字段。

指南 说明
payloads 当值大小符合 binder 内存限制时的值列表或空列表。
sharedMemoryFd 指向一个共享内存文件的可为 null 性文件描述符,该文件在值列表过大时存储序列化载荷。

例如,VehiclePropConfigs 的定义如下:

parcelable VehiclePropConfigs {
    // The list of vehicle property configs if they fit the binder memory
    // limitation.
    VehiclePropConfig[] payloads;
    // Shared memory file to store configs if they exceed binder memory
    // limitation. Created by VHAL, readable only at client. Client could keep
    // the fd opened or keep the FD mapped to access configs.
    @nullable ParcelFileDescriptor sharedMemoryFd;
}

VehiclePropConfigs 包含非空载荷或非 null sharedMemoryFd

  • 如果 payloads 不为空,它会存储实际数据的列表,即属性配置。
  • 如果 sharedMemoryFd 不为 null,它会包含一个共享内存文件,其中存储了 VehiclePropConfigs 的序列化结构。该结构使用 writeToParcel 函数来序列化 Parcel。

作为 VHAL 的 Java 客户端,汽车服务会处理 LargeParcelable 的序列化和反序列化。对于 VHAL 实现和原生客户端,应使用 LargeParcelable 库或该库在 ParcelableUtils.h 中的实用封装容器类对 LargeParcelable 进行序列化和反序列化。

例如,原生客户端解析从 binder 接收的 getValues 的请求如下所示:

// 'requests' are from the binder.
GetValueRequests requests;
expected, ScopedAStatus> deserializedResults = fromStableLargeParcelable(requests);
if (deserializedResults.ok()) {
    const std::vector& getValueRequests = deserializedResults.value().getObject()->payloads;
    // Use the getValueRequests.
  } else {
    // handle error.
}

下面是一个通过 binder 发送 getValues 结果的 VHAL 实现示例:

std::vector results = getResults();
GetValueResults parcelableResults;
ScopedAStatus status = vectorToStableLargeParcelable(std::move(results), &parcelableResults);
if (status.isOk()) {
    // Send parcelableResults through callback.
} else {
    // Handle error.
}