【Android R】车载 Android 焦点折务 - CarPropertyService

开发者 2024-9-28 04:58:50 65 0 来自 中国
1.png 前言

对比开辟车载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 中界说的常量
范例常量名intCAR_SET_PROPERTY_ERROR_CODE_ACCESS_DENIED 体现设置操纵失败的状态,汽车拒绝访问。intCAR_SET_PROPERTY_ERROR_CODE_INVALID_ARG 体现设置操纵失败的状态,参数无效。intCAR_SET_PROPERTY_ERROR_CODE_PROPERTY_NOT_AVAILABLE 体现设置操纵失败的状态,属性不可用。intCAR_SET_PROPERTY_ERROR_CODE_TRY_AGAIN 体现设置操纵失败的状态,重新实验。intCAR_SET_PROPERTY_ERROR_CODE_UNKNOWN 体现设置操纵失败的状态,未知错误。floatSENSOR_RATE_FAST 以10Hz的速率读取传感器。floatSENSOR_RATE_FASTEST 以100Hz的速率读取传感器。floatSENSOR_RATE_NORMAL 以1Hz的速率读取传感器。floatSENSOR_RATE_ONCHANGE 读取ON_CHANGE传感器floatSENSOR_RATE_UI 以5Hz的速率读取传感器。CarPropertyManager 中界说的方法。
返回值范例方法名intgetAreaId(int propId, int area)  返回包罗车辆属性选定区域的areaId。booleangetBooleanProperty(int prop, int area)  返回bool范例的车辆属性,此方法大概必要几秒钟才气完成,因此必要从非主线程调用它。CarPropertyConfig<?>getCarPropertyConfig(int propId)  按属性Id获取CarPropertyConfig。floatgetFloatProperty(int prop, int area)  返回float范例的车辆属性,此方法大概必要几秒钟才气完成,因此必要从非主线程调用它。int[]getIntArrayProperty(int prop, int area)  返回int数组范例的车辆属性,此方法大概必要几秒钟才气完成,因此必要从非主线程调用它。intgetIntProperty(int prop, int area)  返回int范例的车辆属性,此方法大概必要几秒钟才气完成,因此必要从非主线程调用它。<E> CarPropertyValue<E>getProperty(Class<E> clazz, int propId, int areaId)  返回CarPropertyValue范例的车辆属性,此方法大概必要几秒钟才气完成,因此必要从非主线程调用它。<E> CarPropertyValue<E>getProperty(int propId, int areaId)List<CarPropertyConfig>getPropertyList(ArraySet<Integer> propertyIds)List<CarPropertyConfig>getPropertyList()booleanisPropertyAvailable(int propId, int area)  根据汽车的当前状态,检查给定属性是否可用或禁用。booleanregisterCallback(CarPropertyManager.CarPropertyEventCallback callback, int propertyId, float rate)  注册CarPropertyEventCallback以获取车辆属性更新。voidsetBooleanProperty(int prop, int areaId, boolean val)  修改属性。voidsetFloatProperty(int prop, int areaId, float val)  设置float范例的车辆属性,此方法大概必要几秒钟才气完成,因此必要从非主线程调用它。voidsetIntProperty(int prop, int areaId, int val)  设置int范例的车辆属性,此方法大概必要几秒钟才气完成,因此必要从非主线程调用它。<E> voidsetProperty(Class<E> clazz, int propId, int areaId, E val)  按areaId设置车辆属性的值。voidunregisterCallback(CarPropertyManager.CarPropertyEventCallback callback)  制止监听车辆属性的更新回调voidunregisterCallback(CarPropertyManager.CarPropertyEventCallback callback, int propertyId)  制止监听车辆属性的更新回调setXXXProperty/getXXXProperty默认只实现了对float、int、boolean、intArray范例的拓展,如必要使用更多的范例,可以使用setProperty/getProperty(Class<T> class)传入必要拓展的范例即可。
CarPropertyManager 的实现原理并不复杂,可以直接参考源码:/packages/services/Car/car-lib/src/android/car/hardware/property/CarPropertyManager.java。
CarPropertyConfig API 介绍

CarPropertyConfig体现有关汽车属性的一样寻常信息,例如汽车区域的数据范例和最小/最大范围(如果实用)。也是现实开辟中非常常用的类。
CarPropertyConfig 中界说的常量。
范例常量名intVEHICLE_PROPERTY_ACCESS_NONE 属性访问权限未知intVEHICLE_PROPERTY_ACCESS_READ 该属性是可读的intVEHICLE_PROPERTY_ACCESS_READ_WRITE 该属性是可读、可写的intVEHICLE_PROPERTY_ACCESS_WRITE 该属性是可写的intVEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS 这种属性值会以肯定的频率不绝上报intVEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE 该属性的值会在发生变革时上报intVEHICLE_PROPERTY_CHANGE_MODE_STATIC 该属性的值始终不会改变CarPropertyConfig 中界说的方法
返回值范例方法名intgetAccess() 返回汽车属性的访问范例。具体范例就是上面界说的前4个常量int[]getAreaIds() 返回汽车的区域id数组intgetAreaType() 返回汽车属性的区域范例。intgetChangeMode() 返回汽车属性的更改模式。具体模式就是上面界说的后3个常量List<Integer>getConfigArray() 返回额外的设置属性floatgetMaxSampleRate() 返回最大频率。仅支持一连上报的属性floatgetMinSampleRate() 返回最小频率。仅支持一连上报的属性TgetMaxValue(int areaId)TgetMaxValue()TgetMinValue()TgetMinValue(int areaId)intgetPropertyId() 返回属性IDClass<T>getPropertyType() 返回车辆属性的范例booleanisGlobalProperty() 返回 是否是全局属性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断开毗连时会变为falseif (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);
@VisibleForTestingICarImpl(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() 完成初始化。
@MainThreadvoid 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中。
@Overridepublic 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中,紧接着清算掉缓存数据。
@Overridepublic 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将数据回调会应用层的接口。
@Overridepublic 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);            }            // 封装到 CarPropertyEventCarPropertyEvent 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中。

4.png 那么接下来我们以getProperty()方法为例,看一下是怎样限定无权限应用的调用的。
@Overridepublic CarPropertyValue getProperty(int prop, int zone) {    ...    ICarImpl.assertPermission(mContext, mHal.getReadPermission(prop));    return mHal.getProperty(prop, zone);}@Nullablepublic String getReadPermission(int mgrPropId) {    int halPropId = managerToHalPropId(mgrPropId);    return mPropIds.getReadPermission(halPropId);}@Nullablepublic 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接口交互逻辑两部门组成,如下所示

5.png

  • IVehicle.hal
界说VehicleHAL对外袒露的方法。

  • IVehicleCallback.hal
界说属性变革时的回调接口

  • types.hal
界说在IVehicle.hal与IVehicleCallback.hal中使用的数据结构和属性值。
上述三个hal文件的结构与AIDL的通讯结构非常相似,不外这种通讯方式叫做HIDL(读作:嗨豆)。
有关HIDL的进一步内容,请参考官方文档:https://source.android.google.cn/docs/core/architecture/hidl

  • default/ utils/
是Android Automotive OS对于VechicleHAL的参考实现。但是其中并没有实现与车辆总线举行数据交互如许的业务逻辑,这块的内容必要主机制造商自行实现。
VehicleHAL 接口

VHAL 支持以下接口:

  • getAllPropConfigs() generates (vec<VehiclePropConfig> propConfigs);
列出 VehicleHAL 所支持的全部属性的设置。CarService 仅使用支持的属性。

  • getPropConfigs(vec<int32_t> props) generates (StatusCode status, vec<VehiclePropConfig> propConfigs);
返回所选属性的设置。

  • get(VehiclePropValue requestedPropValue) generates (StatusCode status, VehiclePropValue propValue);
获取车辆属性值。

  • set(VehiclePropValue propValue) generates (StatusCode status);
向属性写入一个值。写入的结果是按属性举行界说的。

  • subscribe(IVehicleCallback callback, vec<SubscribeOptions> options) generates (StatusCode status);
开始监督属性值的变革。

  • unsubscribe(IVehicleCallback callback, int32_t propId) generates (StatusCode status);
取消订阅属性事故。
VHAL 支持以下回调接口:

  • oneway onPropertyEvent(vec<VehiclePropValue>propValues);
通知车辆属性值的变革。应只针对已订阅属性执行。

  • 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.0mma编译好的jar包位于
/out/soong/.intermediates/hardware/interfaces/automotive/vehicle/2.0/android.hardware.automotive.vehicle-V2.0-java/android_common/javac
如下图所示:

由于博主并没有现实从事过HAL层的开辟,有关VehicleHAL就只介绍到这里,现实工作中一样寻常会有单独负责HAL层的同事编写这里的代码。
更多内容请参考官方的文档:https://source.android.google.cn/docs/devices/automotive/vhal
总结

本篇介绍了CarPropertyService的实现原理,但是仅通过阅读这篇文章着实并不能完全把握整个CarPropertyService,这是任何技能性文章都做不到的通病,现实项目依然必要我们仔细阅读源码,分析方法的寄义,本篇文章的现实目标是让你弄清晰关键节点的实现方式和运行原理。
我个人也负责过CarPropertyService的开辟工作,当时由于对CarPropertyService的运行机制并不相识,选择整个重写CarPropertyService,现在想想着实走了不少弯路。
好了,感谢你的阅读,希望能资助到你。
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-11-22 00:03, Processed in 0.206362 second(s), 35 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表