上一篇对Automotive模块的Vhal作了总结,本篇文章主要从上层CarService的实现来构析Automotive所提供的功能。 这里主要从以下几点进行源码解读。

CarService功能解析

  • 权限定义与检查
  • CarService与Vhal通信
  • 模拟器的创建与使用
  • 附录:权限定义表

CarService是一个拥有最高优先级的应用服务,它的的源码在 packages/services/Car 目录下面,这个目录下存在许多的工程,这里我们只关心service这个文件夹,service下包含了CarService的服务实现。

权限定义与检查

CarService针对一些特殊的属性读写,定义了对属性值的访问权限,定义方式在service目录中的AndroidManifest.xml中,具体权限定义的字段以及其意义可以参考本文末尾附录表,CarService在PropertyHalServiceIds.java这个类中将属性字段与权限对应起来,属性的权限组,通过SparseArray容器保存,key为属性字段,value为一个Pair类型的变量,first值为读所需权限,second值为写所需权限,并提供了权限获取接口,定义的伪代码如下:

    // Index (key is propertyId, and the value is readPermission, writePermissionprivate final SparseArray<Pair<String, String>> mProps;mProps = new SparseArray<>();// Add propertyId and read/write permissions// Cabin PropertiesmProps.put(VehicleProperty.DOOR_POS, new Pair<>(Car.PERMISSION_CONTROL_CAR_DOORS,Car.PERMISSION_CONTROL_CAR_DOORS));mProps.put(VehicleProperty.DOOR_MOVE, new Pair<>(Car.PERMISSION_CONTROL_CAR_DOORS,Car.PERMISSION_CONTROL_CAR_DOORS));......

一些比较危险的属性,其属性值读写需要调用方应用具有指定的权限才可以操作。那在服务中到底是如何check权限的呢? 让我们来一起先捡个软柿子捏捏。看一下空调温度模块,设置驾驶位空调温度的流程。
从流程图可以看到,check Permission权限检查的操作在CarPropertyService(CPS)中进行,只有在权限通过后,才能将输入下发到VHAL中。 CPS中中通过调用ICarImpl中的静态方法来确定调用方有权限执行此功能。

 @Overridepublic void setProperty(CarPropertyValue prop) {int propId = prop.getPropertyId();if (mConfigs.get(propId) == null) {// Do not attempt to register an invalid propIdLog.e(TAG, "setProperty:  propId is not in config list:0x" + toHexString(propId));return;}//从根据属性ID从权限组中获取写入权限,然后再调用安卓原生判断权限的方式进行判断,如果没有权限,则报RuntimeException异常,中断调用方的应用进程ICarImpl.assertPermission(mContext, mHal.getWritePermission(propId));//如果有权限,则将属性下发mHal.setProperty(prop);}

CarService与Vhal通信

上面一节介绍了CarService通信的权限检查模块,之所以要单独提取出来讲一下流程,是因为本人在调试过程中被权限这块绕了一点时间. 然后接着分析上面提到的vhal模块与Service之间的通信,之前的文章也讲过vhal使用了hidl接口,最终会编译出一个jar包,具体查阅此篇Android 9.0 AutotoMotive模块之Vehicle, 生成的 android.hardware.automotive.vehicle-V2.0-java.jar被service编译的时候依赖了,其中自动生成的IVehicle接口中就实现了Service与Vhal进行binder通信的逻辑,所以这部分我们不要太关心,只需要知道拿到IVehicle接口实例就能通信就OK了, 那怎么拿到该实例呢,IVehicle中有一个这样的方法

android.hardware.automotive.vehicle.V2_0.IVehicle.getService()

这是一个静态方法,CarService也正是通过该方法拿到IVehicle的实例

    @Nullableprivate static IVehicle getVehicle() {try {return android.hardware.automotive.vehicle.V2_0.IVehicle.getService();} catch (RemoteException e) {Log.e(CarLog.TAG_SERVICE, "Failed to get IVehicle service", e);} catch (NoSuchElementException e) {Log.e(CarLog.TAG_SERVICE, "IVehicle service not registered yet");}return null;}

具体的流程如下

 public void onCreate() {Log.i(CarLog.TAG_SERVICE, "Service onCreate");mCanBusErrorNotifier = new CanBusErrorNotifier(this /* context */);//获取IVehicle对象mVehicle = getVehicle();//VHal服务未运行(远端Binder没有找到对应的服务),直接报错if (mVehicle == null) {throw new IllegalStateException("Vehicle HAL service is not available.");}try {//获取vehicle接口名称mVehicleInterfaceName = mVehicle.interfaceDescriptor();} catch (RemoteException e) {throw new IllegalStateException("Unable to get Vehicle HAL interface descriptor", e);}Log.i(CarLog.TAG_SERVICE, "Connected to " + mVehicleInterfaceName);//初始化ICarImpl对象,CarService中的功能实现与Manager的管理定义在该类中。mICarImpl = new ICarImpl(this,mVehicle,SystemInterface.Builder.defaultSystemInterface(this).build(),mCanBusErrorNotifier,mVehicleInterfaceName);mICarImpl.init();//通知bootstat模块car service启动成功SystemProperties.set("boot.car_service_created", "1");//注册服务死亡通知linkToDeath(mVehicle, mVehicleDeathRecipient);//将该服务作为远程服务注册到ServiceManagerServiceManager.addService("car_service", mICarImpl);super.onCreate();}

ICarImpl这里就不深入分析了,简单介绍一下,主要是将车上的各个模块拆解成一个个子模块去管理,比如空调, 车身信息这类属性模块对应的管理模块就是CarPropertyService。 音频管理,则是CarAudioService等等。我们主要介绍一下服务数据是如何下发的,也就是CarPropertyService中setProperty的后续处理逻辑。

还是用权限的那个例子,空调温度设置到CPS中的setProperty之后,会调用PropertyHalService中的setProperty方法,源码如下:

    public void setProperty(CarPropertyValue prop) {//查找该属性是否未有效的属性int halPropId = managerToHalPropId(prop.getPropertyId());Log.d(TAG, "PropertyHalService setProperty halPropId = " + halPropId);if (halPropId == NOT_SUPPORTED_PROPERTY) {throw new IllegalArgumentException("Invalid property Id : 0x"+ toHexString(prop.getPropertyId()));}//将CarPropertyValue转换为VehiclePropValue对象,注意这个VehiclePropValue是hidl自动生成的,包含在jar包中,下发该对象后,vhal模块能够直接取值。VehiclePropValue halProp = toVehiclePropValue(prop, halPropId);try {mVehicleHal.set(halProp);} catch (PropertyTimeoutException e) {Log.e(CarLog.TAG_PROPERTY, "set, property not ready 0x" + toHexString(halPropId), e);throw new RuntimeException(e);}}

最后一路set到IVehicle中,将数据发送给vhal

 public void setValue(VehiclePropValue propValue) throws PropertyTimeoutException {int status = invokeRetriable(() -> {try {//此处将VehiclePropValue下发到VHAL模块return mVehicle.set(propValue);} catch (RemoteException e) {Log.e(CarLog.TAG_HAL, "Failed to set value", e);return StatusCode.TRY_AGAIN;}}, WAIT_CAP_FOR_RETRIABLE_RESULT_MS, SLEEP_BETWEEN_RETRIABLE_INVOKES_MS);//vhal上报,该参数无效if (StatusCode.INVALID_ARG == status) {throw new IllegalArgumentException(String.format("Failed to set value for: 0x%x, areaId: 0x%x",propValue.prop, propValue.areaId));}//错误码:设置失败,请重试if (StatusCode.TRY_AGAIN == status) {throw new PropertyTimeoutException(propValue.prop);}if (StatusCode.OK != status) {throw new IllegalStateException(String.format("Failed to set property: 0x%x, areaId: 0x%x, "+ "code: %d", propValue.prop, propValue.areaId, status));}}

至此,service的set结束,read流程与set差不多,此处不再赘述。

模拟器的创建与使用

Android Studio中使用模拟器,流程如下,打开AVD manager -> create Virture Device -> AutoMotive -> x86镜像,下载镜像完成后,打开即可

模拟器启动后,点击右边工具栏的三个点

在如下界面中就可以模拟车身数据进行通信调试了。

附录:权限定义表

权限定义 权限说明 权限等级
android.car.permission.ADJUST_CAR_CABIN 操作轿厢信息的权限 系统权限
android.car.permission.CAR_ENERGY 访问车辆引擎类型的权限 危险权限
android.car.permission.CAR_IDENTIFICATION 汽车VIN码的访问权限 系统权限
android.car.permission.CONTROL_CAR_CLIMATE 操作空调的权限 系统权限
android.car.permission.CONTROL_CAR_DOORS 操作车门信息的权限 系统权限
android.car.permission.CONTROL_CAR_WINDOWS 操作车窗信息的权限 系统权限
android.car.permission.CONTROL_CAR_MIRRORS 操作车辆后视镜信息的权限 系统权限
android.car.permission.CONTROL_CAR_SEATS 操作车辆座椅信息的权限 系统权限
android.car.permission.CAR_MILEAGE 行驶里程访问权限 系统权限
android.car.permission.CAR_TIRES 轮胎相关属性的读写 系统权限
android.car.permission.CAR_SPEED 车速属性读取 危险权限
android.car.permission.CAR_ENERGY_PORTS 油箱口或者充电口信息的访问权限 普通权限
android.car.permission.CAR_ENGINE_DETAILED 访问发动机详细信息的权限 系统权限
android.car.permission.CAR_DYNAMICS_STATE 动态值访问权限 系统权限
android.car.permission.CAR_VENDOR_EXTENSION 访问特殊的通信信道 系统权限
android.car.permission.CAR_PROJECTION 允许访问car projection相关api的权限 系统权限
android.car.permission.CAR_MOCK_VEHICLE_HAL 允许模拟车身数据 系统权限
android.car.permission.CAR_INFO 允许调用CarInfoManager API的权限 普通权限
android.car.permission.CAR_EXTERIOR_ENVIRONMENT 读取车外温度的权限 普通权限
android.car.permission.CAR_EXTERIOR_LIGHTS" 读取外车灯信息的权限 系统权限
android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS" 控制外车灯信息的权限 系统权限
android.car.permission.CAR_POWERTRAIN 读取动力传输系统信息的权限 普通权限
android.car.permission.CAR_NAVIGATION_MANAGER 使用CarNavigationStatusManager API的权限 系统权限
android.car.permission.CAR_DIAGNOSTICS 读取车辆诊断内容(包括客制化字段)权限 系统权限
android.car.permission.CLEAR_CAR_DIAGNOSTICS 清理车辆诊断信息的权限 系统权限
android.car.permission.VMS_PUBLISHER 访问VMS publisher API的权限 系统权限
android.car.permission.VMS_SUBSCRIBER 访问VMS subscriber API的权限 系统权限
android.car.permission.CAR_DRIVING_STATE 访问CarDrivingStateService去获取驾驶状态的权限 系统权限
android.car.permission.CAR_DRIVING_STATE 访问CarDrivingStateService去获取驾驶状态的权限 系统权限
android.car.permission.CONTROL_APP_BLOCKING 未知权限 系统权限
android.car.permission.CAR_CONTROL_AUDIO_VOLUME 控制音量 系统权限
android.car.permission.CAR_CONTROL_AUDIO_SETTINGS 音量设置 系统权限
android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE 系统签名
android.car.permission.BIND_CAR_INPUT_SERVICE 系统签名
android.car.permission.CAR_DISPLAY_IN_CLUSTER 应用程序必须有此签名才能在仪表盘上显示 系统权限
android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL 应用程序调用CarInstrumentClusterManager在仪表盘中启动Activity时需要此权限 系统权限
android.car.permission.STORAGE_MONITORING 系统权限

Android 9.0 AutoMotive模块之CarService相关推荐

  1. Android服务模块作用,Android 9.0 AutotoMotive模块之CarService

    Android 9.0 AutotoMotive模块之CarService Android 9.0 AutotoMotive模块之CarService 上一篇对Automotive模块的Vhal作了总 ...

  2. Android 5.0 Phone 模块介绍

    ndroid 5.0 Phone 模块代码结构较上个版本发生了很大变化,这样做的好处是代码易于管理和阅读,脱藕,InCallUI可实现客制化. 本篇主要介绍的内容有以下部分: 1:Android 5. ...

  3. android 打开免打扰模式,Android 6.0设置模块免打扰功能浅析

    免打扰功能的入口在NotificationSettings中, 点击列表项跳转到ZenModeSettings.java android:title="@string/zen_mode_se ...

  4. Android 7.0 GMS测试 Camera模块CTS fail项分析

    在上一篇博客中我们提到Camera模块fail项,本篇博客我们单独讲解Camera模块的. GMS中涉及Camera的有: 1.CTS部分的CtsCameraTestCases模块 2.CTS VER ...

  5. Android 8.0学习(32)---Android 8.0源码目录结构详解

    Android 8.0源码目录结构详解 android的移植按如下流程:     (1)android linux 内核的普通驱动移植,让内核可以在目标平台上运行起来.     (2)正确挂载文件系统 ...

  6. Android 10.0 PackageManagerService(二)权限扫描-[Android取经之路]

    摘要:PackageManagerService在systemReady()后,进行了/system/etc/permissions中的各种xml进行扫描,进行相应的权限存储,供以后使用 阅读本文大约 ...

  7. Android 10.0系统启动之init进程-[Android取经之路]

    摘要:init进程是linux系统中用户空间的第一个进程,进程号为1.当bootloader启动后,启动kernel,kernel启动完后,在用户空间启动init进程,再通过init进程,来读取ini ...

  8. 如何在Cordova Android 7.0.0 以下版本集成最新插件 极光插件为例

    前提 Cordova Android 7.0.0开始改变了项目安卓平台的架构.新建一个空项目分别添加Android 6.4.0 和 Android 7.0.0平台: cordova platform ...

  9. android 7 蓝牙版本,[Android]Android什么版本开始支持蓝牙4.2?答案:Android 7.0

    根据Android 7.0的兼容性文档(https://source.android.com/compatibility/7.0/android-7.0-cdd.pdf) 里面7.3.4 Blueto ...

最新文章

  1. 心得丨机器学习自学指南(覆盖各个阶段的心得体会哦)
  2. 从零学React Native之13 持久化存储
  3. pythontuple数据类型_Python基础教程2d–数据类型-tuple(元组)
  4. tar:file-changed-as-we-read-it报错处理
  5. javaweb异常笔记
  6. java 金字塔样式输出_Java打印金字塔(正实心、正空心,倒实心、倒空心),菱形...
  7. python 约束与异常处理
  8. 利用Attribute扩展MVC的Title和Sitemap
  9. web_find()函数检查中文字符串失败的处理方法
  10. 【原】浅谈KL散度(相对熵)在用户画像中的应用
  11. PHP array_diff_assoc
  12. 5G云游戏革命风云已起,各方势力谁执牛耳
  13. 1厘米等于多少个像素
  14. 转载:技术大停滞——范式春梦中的地球工业文明5:台阶前的坑:人类社会的宿命
  15. PyQt5试验:基于QTableWidget的应用
  16. 一个十人开发团队的人员安排
  17. 如何实现一个转动的太极图
  18. win32编程,将rgb图像绘制到窗口句柄
  19. 双亲表示法、孩子表示法、孩子兄弟表示法(二叉树表示法),森林和二叉树的转换
  20. Android圆形按钮示例

热门文章

  1. ElasticSearch搭建集群详解
  2. 小戴媒体播放器 2.0.2
  3. dspace搭建过程
  4. LeCun力挺!马毅教授五年集大成之作:数学可解释的白盒Transformer,性能不输ViT...
  5. 一篇文章带你入门zabbix监控系统
  6. 如何规划好自己在大学的学习路线(大数据专业)
  7. arcgis做水文分析(河流提取、流域提取)
  8. intellij IDE 快捷键(windows)
  9. 运动打卡软件app开发功能
  10. SAP的服务收费怎么算的