目录
- 前言
- 一、Vehicle模块
-
- [1.1 简介](#1.1 简介)
- [1.2 Vehicle框架](#1.2 Vehicle框架)
- [1.3 主要功能和特点](#1.3 主要功能和特点)
- [1.4 重要服务CarService](#1.4 重要服务CarService)
-
- [1.4.1 简介](#1.4.1 简介)
- [1.4.2 组成](#1.4.2 组成)
- [1.4.3 启动时序](#1.4.3 启动时序)
- [1.4.4 作用](#1.4.4 作用)
- 二、车辆属性新增demo
-
- [2.1 CarPropertyService](#2.1 CarPropertyService)
-
- [2.1.1 简介](#2.1.1 简介)
- [2.1.2 架构](#2.1.2 架构)
- [2.1.3 车辆属性 API](#2.1.3 车辆属性 API)
- [2.1.4 CarPropertyService 初始化流程](#2.1.4 CarPropertyService 初始化流程)
- [2.2 App demo](#2.2 App demo)
-
- [2.2.1 app主要代码](#2.2.1 app主要代码)
- [2.2.2 新增属性主要代码](#2.2.2 新增属性主要代码)
- [2.2.3 验证结果](#2.2.3 验证结果)
前言
本文通过APP demo来了解Vehicle模块和CarService
一、Vehicle模块
1.1 简介
许多车载应用需要考虑汽车整体的运行状态,例如,控制车载空调或车速达到一定的阈值时,出于安全的考虑多媒体应用要主动保持静音;汽车处于行驶状态下,OTA应用要保持静默等等。APP如何从Framework层获取车辆状态的数据,而Framework层又是从哪里获取到数据,它们的运行机制是怎样的,都是Vehicle的功能作用。
1.2 Vehicle框架
1.3 主要功能和特点
- 车辆数据访问:Vehicle 模块允许应用程序访问车辆的各种数据,例如车速、发动机转速、油耗、车辆位置等。这些数据可以通过车辆的 CAN 总线或其他通信协议获取,并提供给应用程序使用。
- 车辆控制:除了获取车辆数据,Vehicle 模块还支持应用程序向车辆发送控制指令,例如控制车辆的空调系统、音频系统、车窗等。这使得应用程序可以与车辆进行双向通信和控制。
- 标准化接口:Vehicle 模块提供了一套标准化的接口和 API,使开发人员可以轻松地开发与车辆通信和控制相关的应用程序。这些接口包括获取车辆数据、发送控制指令等功能。
- 安全性:由于车辆信息和控制涉及到车辆的安全和稳定性,Vehicle 模块通常会实现一些安全机制,确保数据传输的安全和可靠性。
- 扩展性:Vehicle 模块通常支持扩展,允许厂商或开发人员添加新的车辆数据源或控制功能,以满足不同车辆的需求。
1.4 重要服务CarService
1.4.1 简介
CarService是车载Android系统的核心服务之一,所有应用都需要通过CarService来查询、控制整车的状态,不仅仅是车辆控制,实际上CarService几乎就是整个车载Framework最核心的组件。
1.4.2 组成
作为 Android Automotive 的核心进程,原生的CarService业务量非常庞大,包含了许多与汽车相关的服务,主要有以下:
服务 | 简介 |
---|---|
CarPropertyService | 此类实现ICarProperty的binder接口。有助于更容易地创建处理车辆属性的多个Manager。 |
CarInputService | CarInputService通过车辆HAL监控和处理输入事件 |
CarLocationService | 此服务在车辆停放时存储LocationManager中最后一个已知位置,并在车辆通电时恢复该位置。 |
CarMediaService | 管理汽车应用程序的当前活动媒体源。这与MediaSessionManager的活动会话不同,因为同一时间内车内只能有一个活动源。 |
CarPowerManagementService | 汽车电源管理服务。控制电源状态并与系统的其他部分交互以确保其自身状态。 |
CarProjectionService | 汽车投屏服务。 |
CarAudioService | 负责与汽车音响系统交互的服务。 |
AppFocusService | 应用程序焦点服务确保一次只有一个应用程序类型的实例处于活动状态。 |
GarageModeService | 车库模式。车库模式启用车内空闲时间。 |
InstrumentClusterService | 负责与汽车仪表盘交互的服务。 |
CarPackageManagerService | 汽车包管理服务。 |
CarUserService | 汽车多用户服务。在启动时管理用户。包括:创建用作驱动程序的用户。创建用作乘客的用户。首次运行时创建辅助管理员用户。切换驾驶员。 |
CarStorageMonitoringService | 提供存储监视数据(如I/O统计数据)的服务。为了接收此类数据,用户需要实现IIoStatsListener并根据此服务注册自己。 |
CarBluetoothService | 车载蓝牙服务-维护当前用户的蓝牙设备和配置文件连接。 |
FixedActivityService | 监控显示器顶部的Activity,并确保在固定模式下的Activity在崩溃或因任何原因进入后台时重新启动。此组件还监视目标包的更新,并在更新完成后重新启动它。 |
CarBugreportManagerService | Bug report服务 |
CarConfigurationService | 该服务将查看系统上的默认JSON配置文件并解析其结果。该服务将查找映射到R.raw.car_config的JSON文件。如果此值不存在或格式不正确,则此服务不会失败;相反,它返回各种配置的默认值。 |
CarDiagnosticService | 汽车诊断服务。工程模式会用到此服务。 |
CarDrivingStateService | 推断车辆当前驾驶状态的服务。它通过侦听CarPropertyService的相关属性来计算驾驶状态。 |
CarExperimentalFeatureServiceController | 控制与ExperimentalCarService的绑定以及实验功能的接口。 |
CarFeatureController | 控制汽车特性的部件。 |
CarNightService | 用于处理用于将车辆设置为夜间模式的事件。 |
CarOccupantZoneService | 用于实现CarOccupantZoneManagerAPI的服务。 |
CarTestService | 允许测试/模拟车辆HAL的服务。该服务直接使用车辆HAL API,因为车辆HAL模拟无论如何都需要直接访问该级别。 |
CarUxRestrictionsManagerService | 用户体验限制的服务。根据监听到的车辆当前驾驶状态,限制HMI显示。 |
OccupantAwarenessService | 一种服务,通过HAL边界监听占用者感知检测系统,并通过OccupantAwarenessManager将数据暴露给Android中的系统客户端。 |
SystemActivityMonitoringService | 监控AMS新Activity或Service启动的服务。 |
SystemStateControllerService | 系统状态控制服务。原生系统中是一个空服务,并没有实现。 |
CarMonitoringService | 监视应用程序资源使用情况的服务。 |
CarTrustedDeviceService | 汽车服务中启用受信任设备功能的部分。可信设备是一项功能,其中远程设备注册为可信设备,可以授权Android用户而不是用户输入密码或PIN。 |
CarUserNoticeService | 向用户显示初始通知UI的服务。它仅在启用设置时启动它,并根据用户的请求通知UI自行关闭。 |
VmsBrokerService | VMS客户端实现,使用HAL特定消息编码将VmsPublisher/VmsSubscriber API调用代理到车辆HAL。 |
CarWatchdogService | 实现CarWatchdogManagerAPI的服务。CarWatchdogService作为汽车监控中介运行,它检查客户端的健康状况,并将结果报告给汽车监控服务器。 |
1.4.3 启动时序
CarService的启动时序如下所示:
1.4.4 作用
虽然冠名了xxxService,但这些服务其实并不是四大组件意义上的Service,它们没有继承自android.app.Service,相反它们都继承自ICarxxxx.Stub,本质上属于AIDL接口的实现类。到这一步也可以看出CarService本质上只是作为这些服务的容器而存在的,本身并没有实现业务逻辑上的功能。
二、车辆属性新增demo
App demo 在hal层中添加一些自定义的车辆属性,并最后通过Car.jar包中的CarPropertyService检测新增车辆属性,所以首先了解一下CarPropertyService
2.1 CarPropertyService
2.1.1 简介
CarService其实只是一系列Binder对象的容器,本身并没有多少特殊功能,CarService中不少功能都被独立出去了,导致CarService实际上只能提供了查询、设置车辆属性的功能,而这部分功能就是本篇的主角 - CarPropertyService
实现的。
2.1.2 架构
从下往上依次来介绍:
HAL Service
用于接收MCU数据的HAL层程序。VehicleHAL与MCU之间是如何进行通信的,每个车载项目技术选型不同,实现上也千差万别,无法详细介绍。我个人经历过得的某个车载项目是使用DBUS。HalClient
HIDL在Client端的HwBinder对象,实现最基本的HIDL通信功能。VehicleHal
用于与HAL层的Vehicle HAL程序的通信接口。它需要对接收到的数据进行基本解析(类型检查),然后将每个事件发送到相应的HalServiceBase实现类里。PropertyHalService
负责进一步处理来自VehicleHal(FWK)数据的接口。是HalServiceBase的实现类。CarPropertyService
是ICarProperty.aidl的实现类。是应用层与HAL层的通信中继。CarPropertyManager
CarPropertyService在Client端的代理。车载系统中的应用需要通过CarPropertyManager来获取或设置车辆的属性。
2.1.3 车辆属性 API
在Android R中CarInfoManager、CarCabinManager、CarHvacManager、CarSensorManager、CarVendorExtensionManager均已经过时,将以上Manager移除使用CarPropertyManager替代。
虽然将汽车的Property属性分散到独立的Manager中可以让Car API的易用性、可读性更强,但是随着汽车属性的不断增加,API的维护也会变得愈加复杂,而CarPropertyManager从实现上就让维护工作变得简单,Google可能也是基于以上的考虑选择不再维护独立的Manager。
①CarPropertyManager 中定义的方法。
②CarPropertyConfig API 介绍
CarPropertyConfig表示有关汽车属性的一般信息,例如汽车区域的数据类型和最小/最大范围(如果适用)。也是实际开发中非常常用的类。
2.1.4 CarPropertyService 初始化流程
CarPropertyService是在CarService中完成创建的,这也是为什么要先讲CarService的原因,一旦CarService建立成功,CarPropertyService也就建立完成,只剩下获取的步骤了。
1)首先,在ICarImpl中创建VehicleHal(FWK)。
2)在VehicleHal(FWK) 创建过程中,同时创建出 PropertyHalService 和 HalClient。
3)然后,在ICarImpl中创建 CarPropertyService。
4)最后,在 ICarImpl 中调用 VehicleHal.init() 、 CarPropertyService.init() 完成初始化。
2.2 App demo
基于Vehicle模块有多个属性的情况下,添加新的自定义属性,在上层获取CarPropertyService服务,使用CarPropertyManager订阅维护新添加的属性,通过app按钮修改新添加的属性值,将属性值改变后的内容在app上呈现,并通过打印log方式验证车控消息传递过程。
2.2.1 app主要代码
1)获取Car,使用Car连接到 CarService ,并获取到 CarPropertyManager 。
java
car = Car.createCar(this, null, Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER, (Car car, boolean ready) -> {
if (ready) {
Log.d(TAG, "汽车服务已经连接好");
init(car);
}
});
propertyManager = (CarPropertyManager) car.getCarManager(Car.PROPERTY_SERVICE);
2)给指定的的property属性注册监听事件
可以在重写方法中加入自己的log验证方法是否经过调用。
java
propertyManager.registerCallback(new CarPropertyManager.CarPropertyEventCallback() {
@Override
public void onChangeEvent(CarPropertyValue carPropertyValue) {
}
@Override
public void onErrorEvent(int i, int i1) {
}
},10,11); // 举例 10 属性ID 11 属性区域ID
3)最后通过app上的button按钮改变注册属性的属性值
在按钮的点击事件里选择属性值类型一致的API进行调用。
在按钮
2.2.2 新增属性主要代码
1) 新增属性,定义相关结构。
文件路径
hardware/interfaces/automotive/vehicle/2.0/types.hal
java
/**
* car air purifier MODE
* @change_mode VehiclePropertyChangeMode:ON_CHANGE
* @access VehiclePropertyAccess:READ_WRITE
*/
NEW_PRO = (
0x0BC5
| VehiclePropertyGroup:SYSTEM
| VehiclePropertyType:INT32
| VehicleArea:WINDOW),
名称 NEW_PRO
属性id16进制后四位 0x0BC5
属性组 system
属性类型 INT32
属性作用域 window
变化模式 @change_mode VehiclePropertyChangeMode:ON_CHANGE
读写性质 @access VehiclePropertyAccess:READ_WRITE
关于此处定义属性规则可自行查阅,链接:
Automotive Vehicle Property
2)在数组里定义属性的详细信息及区域ID和默认值。
文件路径
hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
java
{.config =
{.prop = toInt(VehicleProperty::NEW_PRO),
.access =
VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.areaConfigs =
{VehicleAreaConfig{.areaId = WINDOW_1_LEFT, .minInt32Value = 0, .maxInt32Value = 10},
VehicleAreaConfig{.areaId = WINDOW_1_RIGHT, .minInt32Value = 0, .maxInt32Value = 10},
VehicleAreaConfig{.areaId = WINDOW_2_LEFT, .minInt32Value = 0, .maxInt32Value = 10},
VehicleAreaConfig{.areaId = WINDOW_2_RIGHT, .minInt32Value = 0, .maxInt32Value = 10},
}},
.initialValue = {.int32Values = {0}}},
将新属性的四个区域放在窗户位置,最大值10,最小值0,初始化为0。
3) 将新添加的属性id值添加到生成的current.txt文件
如果不添加,会有提示重新编译此处,可自行修改也可报错时按照提示进行make编译
文件路径
packages/services/Car/car-lib/api/current.txt b/packages/services/Car/car-lib/api/current.txt
java
-227,6 +227,7 @@ package android.car {
field public static final int MIRROR_Y_POS = 339741506; // 0x14400b42
field public static final int MIRROR_Z_MOVE = 339741505; // 0x14400b41
field public static final int MIRROR_Z_POS = 339741504; // 0x14400b40
+ field public static final int NEW_PRO = 322964421; // 0x13400bc5
field public static final int NIGHT_MODE = 287310855; // 0x11200407
field public static final int OBD2_FREEZE_FRAME = 299896065; // 0x11e00d01
field public static final int OBD2_FREEZE_FRAME_CLEAR = 299896067; // 0x11e00d03
4)定义属性id值,并将其添加到toString方法中。
文件路径
packages/services/Car/car-lib/src/android/car/VehiclePropertyIds.java
java
public final class VehiclePropertyIds {
+ public static final int NEW_PRO = 322964421;
/**
* Undefined property. */
public static final int INVALID = 0;
@@ -734,6 +735,9 @@ public final class VehiclePropertyIds {
* @return String
*/
public static String toString(int o) {
+ if (o == NEW_PRO) {
+ return "NEW_PRO";
+ }
if (o == INVALID) {
return "INVALID";
}
5)将新增属性与权限关联起来,因为添加时选择了Window,这里选择控制窗户的权限。
文件路径
packages/services/Car/car-lib/src/com/android/car/internal/PropertyPermissionMapping.java
java
public final class PropertyPermissionMapping {
VehiclePropertyIds.SEAT_HEADREST_FORE_AFT_POS,
VehiclePropertyIds.SEAT_HEADREST_FORE_AFT_MOVE);
map(Car.PERMISSION_CONTROL_CAR_WINDOWS,
+ VehiclePropertyIds.NEW_PRO,
VehiclePropertyIds.WINDOW_POS,
VehiclePropertyIds.WINDOW_MOVE,
6)仍然是与权限相关的添加。
文件路径
packages/services/Car/service/src/com/android/car/hal/PropertyHalServiceIds.java
java
// Cabin Properties
+ mProps.put(VehicleProperty.NEW_PRO, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_WINDOWS,
+ Car.PERMISSION_CONTROL_CAR_WINDOWS));
mProps.put(VehicleProperty.DOOR_POS, new Pair<>(
2.2.3 验证结果
可以正常添加属性并在上层获取。
窗户怎么成温度了?这不重要,为了看着高级我自己加的 。