封面座舱配图 – 上汽飞凡R7
前语
比照开发车载Android和手机Android运用,最大的差异应该便是许多车载运用需求考虑轿车全体的运转状况,例如,操控车载空调或车速到达必定的阈值时,出于安全的考虑多媒体运用要主动保持静音;轿车处于行进状况下,OTA运用要保持静默等等。APP怎么从Framework层获取车辆状况的数据,而Framework层又是从哪里获取到数据,它们的运转机制是怎样的,便是本篇要解说的问题了。
本文是车载Android核心服务系列文章的第二篇,系列目录如下:
1.【Android R】车载 Android 核心服务 – CarService 解析
2.【Android R】车载 Android 核心服务 – CarPropertyService 解析
这个系列文章的首要意图在于收拾原生车载Android体系中,一些核心Service的运转原理与源码完结,所以会有大段的源码解读,内容会比较枯燥。假如阅览本文时还没有车载或车载相关的经验并不丰厚,主张先阅览从运用工程师的视点再谈车载 Android 体系,了解车载Android体系的根底结构。
本系列涉及的运用层API以及Framework层的完结办法,依据原生车载Android R体系,因为实践项目中各个主机厂商会对CarService
做种种修正,本系列内容仅供车载开发者参阅。
CarPropertyService 简介
经过上一篇的介绍,咱们了解了狭义上的CarService
其实只是一系列Binder目标的容器,自身并没有多少特殊功能,有过车载经验的同学或许会有疑问,因为这或许和你正在阅历的项目有出入,这是因为部分量产型的车载项目为了保证要害服务的稳定性,CarService
中不少功能都被独立出去了,导致CarService
实践上只能供给了查询、设置车辆特点的功能,而这部分功能便是本篇的主角 – CarPropertyService
完结的。
从完结上来说CarPropertyService
的架构如下:
咱们从下往上顺次来介绍:
- VehicleHAL
用于接收MCU数据的HAL层程序。VehicleHAL
与MCU之间是怎么进行通讯的,每个车载项目技能选型不同,完结上也千差万别,无法详细介绍。我个人阅历过得的某个车载项目是运用DBUS。
- HalClient
HIDL在Client端的HwBinder目标,完结最基本的HIDL通讯功能。
- VehicleHal
用于与HAL层的Vehicle HAL程序的通讯接口。它需求对接收到的数据进行基本解析(类型查看),然后将每个事件发送到相应的HalServiceBase完结类里。
因为Framework层的VehicleHal与HAL层的VehicleHAL存在重名,后面为了区分会用VehicleHal(FWK) 表明Framework层的VehicleHal,用VehicleHAL(HAL) 表明HAL层的VehicleHAL。
- PropertyHalService
担任进一步处理来自VehicleHal(FWK)
数据的接口。是HalServiceBase的完结类。
- CarPropertyService
是ICarProperty.aidl
的完结类。是运用层与HAL层的通讯中继。
- CarPropertyManager
CarPropertyService
在Client端的代理。车载体系中的运用需求经过CarPropertyManager
来获取或设置车辆的特点。
先来看 CarPropertyManager
供给的API。
车辆特点 API
在Android R中CarInfoManager
、CarCabinManager
、CarHvacManager
、CarSensorManager
、CarVendorExtensionManager
均现已过时,在我个人实践阅历的车载项目中,担任开发CarService
的搭档,也会挑选将以上Manager移除运用CarPropertyManager
代替。
尽管将轿车的Property特点分散到独立的Manager中能够让Car API的易用性、可读性更强,可是跟着轿车特点的不断增加,API的保护也会变得更加复杂,而CarPropertyManager
从完结上就让保护作业变得简单,Google或许也是依据以上的考虑挑选不再保护独立的Manager。
所以本文不再介绍CarInfoManager
、CarCabinManager
、CarHvacManager
、CarSensorManager
、CarVendorExtensionManager
的完结,有需求的同学请参阅源码中是怎么完结的。
CarPropertyManager API 介绍
CarPropertyManager
中界说的常量
类型 | 常量名 |
---|---|
int | CAR_SET_PROPERTY_ERROR_CODE_ACCESS_DENIED 表明设置操作失利的状况,轿车拒绝拜访。 |
int | CAR_SET_PROPERTY_ERROR_CODE_INVALID_ARG 表明设置操作失利的状况,参数无效。 |
int | CAR_SET_PROPERTY_ERROR_CODE_PROPERTY_NOT_AVAILABLE 表明设置操作失利的状况,特点不可用。 |
int | CAR_SET_PROPERTY_ERROR_CODE_TRY_AGAIN 表明设置操作失利的状况,从头测验。 |
int | CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN 表明设置操作失利的状况,不知道错误。 |
float | SENSOR_RATE_FAST 以10Hz的速率读取传感器。 |
float | SENSOR_RATE_FASTEST 以100Hz的速率读取传感器。 |
float | SENSOR_RATE_NORMAL 以1Hz的速率读取传感器。 |
float | SENSOR_RATE_ONCHANGE 读取ON_CHANGE传感器 |
float | SENSOR_RATE_UI 以5Hz的速率读取传感器。 |
CarPropertyManager
中界说的办法。
回来值类型 | 办法名 |
---|---|
int | getAreaId(int propId, int area) 回来包含车辆特点选定区域的areaId。 |
boolean | getBooleanProperty(int prop, int area) 回来bool类型的车辆特点,此办法或许需求几秒钟才干完结,因而需求从非主线程调用它。 |
CarPropertyConfig<?> | getCarPropertyConfig(int propId) 按特点Id获取CarPropertyConfig。 |
float | getFloatProperty(int prop, int area) 回来float类型的车辆特点,此办法或许需求几秒钟才干完结,因而需求从非主线程调用它。 |
int[] | getIntArrayProperty(int prop, int area) 回来int数组类型的车辆特点,此办法或许需求几秒钟才干完结,因而需求从非主线程调用它。 |
int | getIntProperty(int prop, int area) 回来int类型的车辆特点,此办法或许需求几秒钟才干完结,因而需求从非主线程调用它。 |
CarPropertyValue | getProperty(Class clazz, int propId, int areaId) 回来CarPropertyValue类型的车辆特点,此办法或许需求几秒钟才干完结,因而需求从非主线程调用它。 |
CarPropertyValue | getProperty(int propId, int areaId) |
List | getPropertyList(ArraySet propertyIds) |
List | getPropertyList() |
boolean | isPropertyAvailable(int propId, int area) 依据轿车的当前状况,查看给定特点是否可用或禁用。 |
boolean | registerCallback(CarPropertyManager.CarPropertyEventCallback callback, int propertyId, float rate) 注册CarPropertyEventCallback以获取车辆特点更新。 |
void | setBooleanProperty(int prop, int areaId, boolean val) 修正特点。 |
void | setFloatProperty(int prop, int areaId, float val) 设置float类型的车辆特点,此办法或许需求几秒钟才干完结,因而需求从非主线程调用它。 |
void | setIntProperty(int prop, int areaId, int val) 设置int类型的车辆特点,此办法或许需求几秒钟才干完结,因而需求从非主线程调用它。 |
void | setProperty(Class clazz, int propId, int areaId, E val) 按areaId设置车辆特点的值。 |
void | unregisterCallback(CarPropertyManager.CarPropertyEventCallback callback) 中止监听车辆特点的更新回调 |
void | unregisterCallback(CarPropertyManager.CarPropertyEventCallback callback, int propertyId) 中止监听车辆特点的更新回调 |
setXXXProperty/getXXXProperty默许只完结了对float、int、boolean、intArray类型的拓展,如需求运用更多的类型,能够运用setProperty/getProperty(Class class)传入需求拓展的类型即可。
CarPropertyManager 的完结原理并不复杂,能够直接参阅源码:/packages/services/Car/car-lib/src/android/car/hardware/property/CarPropertyManager.java。
CarPropertyConfig API 介绍
CarPropertyConfig表明有关轿车特点的一般信息,例如轿车区域的数据类型和最小/最大范围(假如适用)。也是实践开发中非常常用的类。
CarPropertyConfig 中界说的常量。
类型 | 常量名 |
---|---|
int | VEHICLE_PROPERTY_ACCESS_NONE 特点拜访权限不知道 |
int | VEHICLE_PROPERTY_ACCESS_READ 该特点是可读的 |
int | VEHICLE_PROPERTY_ACCESS_READ_WRITE 该特点是可读、可写的 |
int | VEHICLE_PROPERTY_ACCESS_WRITE 该特点是可写的 |
int | VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS 这种特点值会以必定的频率不断上报 |
int | VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE 该特点的值会在发生改变时上报 |
int | VEHICLE_PROPERTY_CHANGE_MODE_STATIC 该特点的值一直不会改变 |
CarPropertyConfig 中界说的办法
回来值类型 | 办法名 |
---|---|
int | getAccess() 回来轿车特点的拜访类型。详细类型便是上面界说的前4个常量 |
int[] | getAreaIds() 回来轿车的区域id数组 |
int | getAreaType() 回来轿车特点的区域类型。 |
int | getChangeMode() 回来轿车特点的更改形式。详细形式便是上面界说的后3个常量 |
List | getConfigArray() 回来额定的装备特点 |
float | getMaxSampleRate() 回来最大频率。仅支撑继续上报的特点 |
float | getMinSampleRate() 回来最小频率。仅支撑继续上报的特点 |
T | getMaxValue(int areaId) |
T | getMaxValue() |
T | getMinValue() |
T | getMinValue(int areaId) |
int | getPropertyId() 回来特点ID |
Class | getPropertyType() 回来车辆特点的类型 |
boolean | isGlobalProperty() 回来 是否是全局特点 |
CarPropertyManager 运用示例
运用CarPropertyManager
能够分为以下几个过程:
1)运用Car衔接到 CarService
,并获取到 CarPropertyManager
。
Car car = Car.createCar(this, workThreadHandler, 2000, new Car.CarServiceLifecycleListener() {
@Override
public void onLifecycleChanged(@NonNull Car car, boolean ready) {
// ready 在Service断开衔接时会变为false
if (ready) {
CarPropertyManager propertyMgr = (CarPropertyManager) car.getCarManager(Car.PROPERTY_SERVICE);
} else {
// CarService 发生反常或衔接被断开了,需求client端处理。
}
}
});
2)给一切的property特点注册监听事件
// 空调的property id list,需求看hal层是怎么界说的
private final ArraySet<Integer> mHvacPropertyIds = new ArraySet<>(Arrays.asList(new Integer [] {
...
}));
CarPropertyManager propertyMgr = (CarPropertyManager) car.getCarManager(Car.PROPERTY_SERVICE);
List<CarPropertyConfig> propertyList = propertyMgr.getPropertyList(mHvacPropertyIds);
for (CarPropertyConfig config : propertyList) {
// 给每个独自的propertyId注册监听回调。
propertyMgr.registerCallback(callback,config.getPropertyId(), SENSOR_RATE_ONCHANGE);
}
3)获取单个Property的值
public boolean getBooleanProperty(@PropertyId int propertyId, int area) {
return propertyMgr.getBooleanProperty(propertyId, area);
}
尽管运用getBooleanProperty、getIntProperty、getFloatProperty、getIntArrayProperty代码上更简练一些,可是更主张运用getProperty()
。getProperty()
的回来值是CarPropertyValue
,这其间包含了Property的状况信息,能够让运用方掩盖更多的反常场景。
当特点不可用时,getXXXProperty()会回来默许的值,造成运用方读取数据不准确。
public CarPropertyValue<Boolean> getBooleanProperty(int propertyId, int area) {
return propertyMgr.getProperty(Boolean.class, propertyId, area);
}
CarPropertyValue<Boolean> value = getBooleanProperty(CarHvacManager.ID_ZONED_AC_ON, 0);
if (value == null && value.getStatus() != CarPropertyValue.STATUS_AVAILABLE) {
// ac 不可用
} else if (value.getValue()) {
// ac 开
} else {
// ac 关
}
4)设定单个Property的值
public void setBooleanProperty(@PropertyId int propertyId, int area, boolean val) {
if (mHvacPropertyIds.contains(propertyId)) {
propertyMgr.setBooleanProperty(propertyId, area, val);
}
}
设定的值终究会经过aidl接口,将数据传输到CarPropertyService
中,接下来咱们继续看数据在CarPropertyService
中是怎么传递的。
CarPropertyService 完结原理
CarPropertyService 初始化流程
CarPropertyService
是在CarService中完结创立的,CarService
的初始化流程在之前的文章【Android R】车载 Android 核心服务 – CarService 解析中现已有过介绍,不再赘述。CarPropertyService
的初始流程分为以下4步:
1)首先,在ICarImpl中创立VehicleHal(FWK);
@VisibleForTesting
ICarImpl(Context serviceContext, IVehicle vehicle, SystemInterface systemInterface,
CanBusErrorNotifier errorNotifier, String vehicleInterfaceName,
@Nullable CarUserService carUserService,
@Nullable CarWatchdogService carWatchdogService) {
...
mHal = new VehicleHal(serviceContext, vehicle);
// 在任何其他服务组件之前履行此操作,以允许进行功能查看。即使没有初始化,它也应该作业。
// 为此,vhal-get会被重试,因为它或许太早了。
VehiclePropValue disabledOptionalFeatureValue = mHal.getIfAvailableOrFailForEarlyStage(
VehicleProperty.DISABLED_OPTIONAL_FEATURES, INITIAL_VHAL_GET_RETRY);
String[] disabledFeaturesFromVhal = null;
if (disabledOptionalFeatureValue != null) {
String disabledFeatures = disabledOptionalFeatureValue.value.stringValue;
if (disabledFeatures != null && !disabledFeatures.isEmpty()) {
disabledFeaturesFromVhal = disabledFeatures.split(",");
}
}
if (disabledFeaturesFromVhal == null) {
disabledFeaturesFromVhal = new String[0];
}
...
}
2)在 VehicleHal(FWK)
创立过程中,同时创立出 PropertyHalService 和 HalClient;
public VehicleHal(Context context, IVehicle vehicle) {
...
mPropertyHal = new PropertyHalService(this);
...
mHalClient = new HalClient(vehicle, mHandlerThread.getLooper(), this /*IVehicleCallback*/ );
}
3)然后,在ICarImpl中创立 CarPropertyService;
ICarImpl(Context serviceContext, IVehicle vehicle, SystemInterface systemInterface,
CanBusErrorNotifier errorNotifier, String vehicleInterfaceName,
@Nullable CarUserService carUserService,
@Nullable CarWatchdogService carWatchdogService) {
...
mCarPropertyService = new CarPropertyService(serviceContext, mHal.getPropertyHal());
...
}
4)终究,在 ICarImpl
中调用 VehicleHal.init()
、 CarPropertyService.init()
完结初始化。
@MainThread
void init() {
mHal.init();
for (CarServiceBase service : mAllServices) {
service.init();
}
}
接下来,咱们顺次把这些模块是怎么完结数据上报的流程梳理一下,先来看处于Framework最底层的 HalClient。
HalClient
车辆HAL客户端。直接与车辆HAL的HIDL接口IVehicle交互。包含一些可检索特点的逻辑,将车辆告诉重定向到给定的looper线程中。
HalClient(IVehicle vehicle, Looper looper, IVehicleCallback callback,
int waitCapMs, int sleepMs) {
mVehicle = vehicle;
Handler handler = new CallbackHandler(looper, callback);
mInternalCallback = new VehicleCallback(handler);
mWaitCapMs = waitCapMs;
mSleepMs = sleepMs;
}
VehicleCallback 是HIDL接口IVehicleCallback.Stub
的完结类,担任监听HAL层上报的数据,然后将其发送到CallbackHandler
中进行处理。
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)));
}
}
CallbackHandler
是一个自界说的Handler,会将VehicleHal(HAL)上报的数据分类经过callback回调给VehicleHal(FWK)。
private static final class CallbackHandler extends Handler {
private static final int MSG_ON_PROPERTY_SET = 1;
private static final int MSG_ON_PROPERTY_EVENT = 2;
private static final int MSG_ON_SET_ERROR = 3;
...
@Override
public void handleMessage(Message msg) {
IVehicleCallback callback = mCallback.get();
...
try {
switch (msg.what) {
case MSG_ON_PROPERTY_EVENT:
callback.onPropertyEvent((ArrayList<VehiclePropValue>) msg.obj);
break;
case MSG_ON_PROPERTY_SET:
callback.onPropertySet((VehiclePropValue) msg.obj);
break;
case MSG_ON_SET_ERROR:
PropertySetError obj = (PropertySetError) msg.obj;
callback.onPropertySetError(obj.errorCode, obj.propId, obj.areaId);
break;
default:
Log.e(TAG, "Unexpected message: " + msg.what);
}
} catch (RemoteException e) {
Log.e(TAG, "Message failed: " + msg.what);
}
}
}
考虑一个问题,为什么HAL上报的数据信息要先经过Handler再处理呢?
这既有线程切换的考虑,还有便是VehicleHAL(HAL)上报的数据有时会非常频频,将数据放到Looper的MessageQueue中能够便于咱们依照上报的顺序,有序地处理数据。
VehicleHal
用于与HAL层的Vehicle HAL程序的通讯接口。将HalClient回调过来的数据,进行初步的处理。咱们以onPropertyEvent为例,看一下VehicleHAl(FWK)是怎么处理HalClient回调过来的数据的。
VehicleHAl(FWK)的处理办法分为两步
1)第一步,依据上报数据找到对应的HalServiceBase(HalServiceBase是PropertyHalService
的父类),将VehiclePropValue添加到PropertyHalService
的list中。
@Override
public void onPropertyEvent(ArrayList<VehiclePropValue> propValues) {
synchronized (mLock) {
for (VehiclePropValue v : propValues) {
HalServiceBase service = mPropertyHandlers.get(v.prop);
if(service == null) {
Log.e(CarLog.TAG_HAL, "HalService not found for prop: 0x"
+ toHexString(v.prop));
continue;
}
service.getDispatchList().add(v);
mServicesToDispatch.add(service);
...
}
}
...
}
2)第二步,主动触发PropertyHalService.onHalEvents()
将VehiclePropValue发送到PropertyHalService中,紧接着清理掉缓存数据。
@Override
public void onPropertyEvent(ArrayList<VehiclePropValue> propValues) {
...
for (HalServiceBase s : mServicesToDispatch) {
s.onHalEvents(s.getDispatchList());
s.getDispatchList().clear();
}
mServicesToDispatch.clear();
}
PropertyHalService
在PropertyHalService.onHalEvents
中处理接收到的value list。将数据转化为CarPropertyValue
后,经过PropertyHalListener
将处理好的数据回调给CarPropertyService
,而终究会由CarPropertyService
将数据回调会运用层的接口。
@Override
public void onHalEvents(List<VehiclePropValue> values) {
PropertyHalListener listener;
...
if (listener != null) {
for (VehiclePropValue v : values) {
if (v == null) {
continue;
}
...
int mgrPropId = halToManagerPropId(v.prop);
CarPropertyValue<?> propVal;
if (isMixedTypeProperty(v.prop)) {
// parse mixed type property value.
VehiclePropConfig propConfig;
synchronized (mLock) {
propConfig = mHalPropIdToVehiclePropConfig.get(v.prop);
}
boolean containBooleanType = propConfig.configArray.get(1) == 1;
propVal = toMixedCarPropertyValue(v, mgrPropId, containBooleanType);
} else {
propVal = toCarPropertyValue(v, mgrPropId);
}
// 封装到 CarPropertyEvent
CarPropertyEvent event = new CarPropertyEvent(
CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, propVal);
mEventsToDispatch.add(event);
}
listener.onPropertyChange(mEventsToDispatch);
mEventsToDispatch.clear();
}
}
注意两个办法,toMixedCarPropertyValue()
和 toCarPropertyValue()
假如数据类型是Integer、Float、Long、Float[]、Long[]、Integer[]、byte[]、String则由 toCarPropertyValue()
担任数据转化。除此以外的类型由toMixedCarPropertyValue()
担任数据转化。它们都是将VehiclePropValue
转化为CarPropertyValue
。
设定/获取 Property
设定和与获取Property的流程并不复杂,这儿就不再粘贴源码了逐个讲解了,贴上一份设定的时序图。
权限操控
上面在分析CarPropertyService监听特点改变的详细完结时,咱们提到了运用Car API的接口需求注册对应的权限,那么这些权限是怎么管理的呢?
在PropertyHalService的结构办法中,创立了一个PropertyHalServiceIds的目标,而这个目标便是用来存储每个特点所需求的权限的。
PropertyHalServiceIds源码位置:/packages/services/Car/service/src/com/android/car/hal/PropertyHalServiceIds.java
public PropertyHalService(VehicleHal vehicleHal) {
mPropIds = new PropertyHalServiceIds();
mSubscribedHalPropIds = new HashSet<Integer>();
mVehicleHal = vehicleHal;
}
在PropertyHalServiceIds的结构办法中,将每个特点对应需求的权限进行了逐个关联,保存在一个SparseArray中。
那么接下来咱们以getProperty()办法为例,看一下是怎么限制无权限运用的调用的。
@Override
public CarPropertyValue getProperty(int prop, int zone) {
...
ICarImpl.assertPermission(mContext, mHal.getReadPermission(prop));
return mHal.getProperty(prop, zone);
}
@Nullable
public String getReadPermission(int mgrPropId) {
int halPropId = managerToHalPropId(mgrPropId);
return mPropIds.getReadPermission(halPropId);
}
@Nullable
public String getReadPermission(int propId) {
Pair<String, String> p = mProps.get(propId);
if (p != null) {
// 特点ID存在。回来 权限。
if (p.first == null) {
Log.e(TAG, "propId is not available for reading : 0x" + toHexString(propId));
}
return p.first;
} else if (isVendorProperty(propId)) {
// 假如特点是供应商特点,并且没有特定权限。
return Car.PERMISSION_VENDOR_EXTENSION;
} else {
return null;
}
}
getReadPermission的调用链很好懂,首要便是将传入的id与PropertyHalServiceIds中关联好的权限比对,并取出对应的权限字符串。
assertPermission办法会判别调用方是否拥有相应的权限,或本次调用是否是自身建议的,假如不是,则会抛出SecurityException。
#########ICarImpl.java###############
public static void assertPermission(Context context, String permission) {
if (context.checkCallingOrSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("requires " + permission);
}
}
setProperty()办法的权限查看与getProperty()办法类似,不过getProperty()办法是查看ReadPermission,setProperty()办法是查看WritePermission。
车辆特点的读取以及操作需求稳重授权给运用,所以权限操控在车载Android体系中就显得尤为重要。
VehicleHAL
VehicleHAL 是由Android Automotive OS界说的硬件抽象层(hardware abstract layer)。它界说了 OEM 能够完结的特点以及与Framework Service交互的接口。用户对车辆APP产生的一系列操作终究都会来到VehicleHAL,并因为VehicleHAL转宣布Android体系。
源码地址:/hardware/interfaces/automotive/vehicle/2.0/
源码结构
VehicleHAL首要由IPC接口和交互逻辑两部分组成,如下所示
- IVehicle.hal
界说VehicleHAL对外暴露的办法。
- IVehicleCallback.hal
界说特点改变时的回调接口
- types.hal
界说在IVehicle.hal
与IVehicleCallback.hal
中运用的数据结构和特点值。
上述三个hal文件的结构与AIDL的通讯结构非常类似,不过这种通讯办法叫做HIDL(读作:嗨豆)。
有关HIDL的进一步内容,请参阅官方文档:source.android.google.cn/docs/core/a…
- default/ utils/
是Android Automotive OS关于VechicleHAL的参阅完结。可是其间并没有完结与车辆总线进行数据交互这样的事务逻辑,这块的内容需求主机制造商自行完结。
VehicleHAL 接口
VHAL 支撑以下接口:
- getAllPropConfigs() generates (vec propConfigs);
列出 VehicleHAL 所支撑的一切特点的装备。CarService 仅运用支撑的特点。
- 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);
撤销订阅特点事件。
VHAL 支撑以下回调接口:
- oneway onPropertyEvent(vecpropValues);
告诉车辆特点值的改变。应只针对已订阅特点履行。
- oneway onPropertySet(VehiclePropValue propValue);
假如客户端运用SubscribeFlags.EVENTS_FROM_ANDROID标志订阅了特点,并且调用了IVehicle.set()办法,则会调用此办法。
- oneway onPropertySetError(StatusCode errorCode,int32_t propId,int32_tareaId);
回来全局 VHAL 级错误或每个特点的错误。全局错误解导致 HAL 从头启动,这或许会导致包含运用在内的其他组件从头启动。
编译VehicleHAL
HIDL接口界说好之后,与AIDL接口相同需求编译更jar供给给Framework的开发,以下过程是编译原生的VehicleHAL,实践项目中的VehicleHAL一般会放置vendor里面,可是编译办法相同。
cd hardware/interfaces/automotive/vehicle/2.0
mma
编译好的jar包位于
/out/soong/.intermediates/hardware/interfaces/automotive/vehicle/2.0/android.hardware.automotive.vehicle-V2.0-java/android_common/javac
如下图所示:
因为博主并没有实践从事过HAL层的开发,有关VehicleHAL就只介绍到这儿,实践作业中一般会有独自担任HAL层的搭档编写这儿的代码。
更多内容请参阅官方的文档:source.android.google.cn/docs/device…
总结
本篇介绍了CarPropertyService的完结原理,可是仅经过阅览这篇文章其实并不能完全掌握整个CarPropertyService,这是任何技能性文章都做不到的通病,实践项目依然需求咱们仔细阅览源码,分析办法的意义,本篇文章的实践意图是让你弄清楚要害节点的完结办法和运转原理。
我个人也担任过CarPropertyService
的开发作业,其时因为对CarPropertyService
的运转机制并不了解,挑选整个重写CarPropertyService
,现在想想着实走了不少弯路。
好了,感谢你的阅览,希望能帮助到你。