封面座舱配图 – 上汽飞凡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的架构如下:

【Android R】车载 Android 核心服务 - 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中CarInfoManagerCarCabinManagerCarHvacManagerCarSensorManagerCarVendorExtensionManager均现已过时,在我个人实践阅历的车载项目中,担任开发CarService的搭档,也会挑选将以上Manager移除运用CarPropertyManager代替。

尽管将轿车的Property特点分散到独立的Manager中能够让Car API的易用性、可读性更强,可是跟着轿车特点的不断增加,API的保护也会变得更加复杂,而CarPropertyManager从完结上就让保护作业变得简单,Google或许也是依据以上的考虑挑选不再保护独立的Manager。

所以本文不再介绍CarInfoManagerCarCabinManagerCarHvacManagerCarSensorManagerCarVendorExtensionManager的完结,有需求的同学请参阅源码中是怎么完结的。

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的流程并不复杂,这儿就不再粘贴源码了逐个讲解了,贴上一份设定的时序图。

【Android R】车载 Android 核心服务 - CarPropertyService

权限操控

上面在分析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中。

【Android R】车载 Android 核心服务 - CarPropertyService

那么接下来咱们以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接口交互逻辑两部分组成,如下所示

【Android R】车载 Android 核心服务 - CarPropertyService

  • IVehicle.hal

界说VehicleHAL对外暴露的办法。

  • IVehicleCallback.hal

界说特点改变时的回调接口

  • types.hal

界说在IVehicle.halIVehicleCallback.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

如下图所示:

【Android R】车载 Android 核心服务 - CarPropertyService

因为博主并没有实践从事过HAL层的开发,有关VehicleHAL就只介绍到这儿,实践作业中一般会有独自担任HAL层的搭档编写这儿的代码。

更多内容请参阅官方的文档:source.android.google.cn/docs/device…

总结

本篇介绍了CarPropertyService的完结原理,可是仅经过阅览这篇文章其实并不能完全掌握整个CarPropertyService,这是任何技能性文章都做不到的通病,实践项目依然需求咱们仔细阅览源码,分析办法的意义,本篇文章的实践意图是让你弄清楚要害节点的完结办法和运转原理。

我个人也担任过CarPropertyService的开发作业,其时因为对CarPropertyService的运转机制并不了解,挑选整个重写CarPropertyService,现在想想着实走了不少弯路。

好了,感谢你的阅览,希望能帮助到你。