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

Android 9.0 AutotoMotive模块之CarService

Android 9.0 AutotoMotive模块之CarService

上一篇对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, writePermission

private final SparseArray> mProps;

mProps = new SparseArray<>();

// Add propertyId and read/write permissions

// Cabin Properties

mProps.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权限的呢? 让我们来一起先捡个软柿子捏捏。看一下空调温度模块,设置驾驶位空调温度的流程。

9ae73d18020c36af2dbd7a83623b6c4a.png从流程图可以看到,check Permission权限检查的操作在CarPropertyService(CPS)中进行,只有在权限通过后,才能将输入下发到VHAL中。 CPS中中通过调用ICarImpl中的静态方法来确定调用方有权限执行此功能。

@Override

public void setProperty(CarPropertyValue prop) {

int propId = prop.getPropertyId();

if (mConfigs.get(propId) == null) {

// Do not attempt to register an invalid propId

Log.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的实例

@Nullable

private 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);

//将该服务作为远程服务注册到ServiceManager

ServiceManager.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镜像,下载镜像完成后,打开即可

e1e17cd4a184ddad350ffe4c85443fd0.png

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

f1c872582b29299ede018edfa1496894.png

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

2ea1fc8699f526a0423d1d994052ac05.png

附录:权限定义表

权限定义

权限说明

权限等级

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 AutotoMotive模块之CarService相关教程

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值