CarPropertyService信号配置和调试

本文主要记录property信号添加的操作流程。

以下操作基于HIDL,安卓13:

信号配置

1.types.hal中更新信号

首先,VHAL需要根据信号矩阵表,更新types.hal中的信号。

文件路径LINUX\android\hardware\interfaces\automotive\vehicle\2.0\types.hal

信号id是8位的16进制数,可分为4个部分,它们通过或运算累加起来。

下面以原生信号为例,进行说明。

    INFO_EV_BATTERY_CAPACITY = (
        0x0106
        | VehiclePropertyGroup:SYSTEM
        | VehiclePropertyType:FLOAT
        | VehicleArea:GLOBAL),

后4位0x0106是信号的id,由信号矩阵表定义,一般是唯一的。

VehiclePropertyGroup是最高位,系统原生的为SYSTEM(0x10000000);一般来说,供应商添加使用VENDOR(0x20000000)。

VehiclePropertyType是第三第四位,定义如下

enum VehiclePropertyType : int32_t {
    STRING          = 0x00100000,
    BOOLEAN         = 0x00200000,
    INT32           = 0x00400000,
    INT32_VEC       = 0x00410000,
    INT64           = 0x00500000,
    INT64_VEC       = 0x00510000,
    FLOAT           = 0x00600000,
    FLOAT_VEC       = 0x00610000,
    BYTES           = 0x00700000,
    MIXED           = 0x00e00000,
    MASK            = 0x00ff0000
};

VehicleArea是第二位,一般大部分信号的area是GLOBAL。

enum VehicleArea : int32_t {
    /**
     * A global property is a property that applies to the entire vehicle and is not associated with
     * a specific area. For example, FUEL_LEVEL, HVAC_STEERING_WHEEL_HEAT are global properties.
     */
    GLOBAL      = 0x01000000,
    /** WINDOW maps to enum VehicleAreaWindow */
    WINDOW      = 0x03000000,
    /** MIRROR maps to enum VehicleAreaMirror */
    MIRROR      = 0x04000000,
    /** SEAT maps to enum VehicleAreaSeat */
    SEAT        = 0x05000000,
    /** DOOR maps to enum VehicleAreaDoor */
    DOOR        = 0x06000000,
    /** WHEEL maps to enum VehicleAreaWheel */
    WHEEL       = 0x07000000,

    MASK        = 0x0f000000,
};

在编译CarService时,会自动先编译VHAL。所以修改types.hal之后,可以不立即编译VHAL。可以等CarService代码完成后,直接编译CarService即可。

2.PropertyHalServiceIds中配置信号的读写权限

PropertyHalServiceIds文件路径LINUX\android\packages\services\Car\service\src\com\android\car\hal\PropertyHalServiceIds.java

参考原生代码添加权限

        mProps.put(VehicleProperty.INFO_EV_BATTERY_CAPACITY, new Pair<>(
                    Car.PERMISSION_CAR_INFO,
                    null));

new Pair<>(,)中,先后添加读权限和写权限。

PropertyHalServiceIds中会使用到types.hal生成的VehicleProperty类,这也是CarService的编译依赖VHAL的原因。

3.VehiclePropertyIds中添加信号id

VehiclePropertyIds在car-lib目录下,是需要打包成jar以后,提供给APP使用的。

VehiclePropertyIds文件路径LINUX\android\packages\services\Car\car-lib\src\android\car\VehiclePropertyIds.java

car-lib目录下的接口文件修改后,要执行make update-api命令。这个命令会更新以下两个current.txt文件:

  • LINUX\android\packages\services\Car\car-lib\api\current.txt
  • LINUX\android\packages\services\Car\car-lib-module\api\current.txt

其实这2个文件的内容是完全一样的,文件内容就是按照字母表顺序,列出了APP可用的公共接口方法和常量。

这2个文件很重要,进行完整编译时,会校验其中的内容。假如VehiclePropertyIds中新增的信号在current.txt中没有,就会报错并终止编译。如果要手动修改current.txt(例如手动同步代码),一定要注意代码写入的位置是否正确,如果没有按照字母表顺序排列,也会报错并导致无法编译image。

4.编译获取产物和使用

添加property的基本步骤就是以上的3个。完成后即可编译。

  1. source build/envsetup.sh
  2. lunch 编译选项
  3. make CarServiceUpdatableNonModule 或者 在Car的对应目录下mm

这里不能make CarService,因为CarService.apk和CarServiceUpdatableNonModule.apk是不同的,具体区别参考这篇博客《CarService的构成和初始化分析》

编译完成后可获取jar包供APP使用。建议APP引用jar包时使用compileOnly,以避免一些库的冲突。对于CarPropertyService来说,APP只要使用接口和常量,所以compileOnly参与编译即可,不需要用implementation参与打包。

提供给APP的jar包路径为/out/soong/.intermediates/packages/services/Car/car-lib/android.car/android_common/javac/android.car.jar

也可以使用/out/target/common/obj/JAVA_LIBRARIES/android.car_intermediates/classes.jar

用MD5计算可得知,上面两个路径的文件,MD5值是完全一样的。

如果是framework使用编译产物进行调试,需要使用到的产物为android.car.jar(包含Car/car-lib目录下的修改)和CarServiceUpdatableNonModule.apk(包含Car/service目录下的修改)

注意这里的 android.car.jar和提供的APP的jar包是不同的东西,其路径为out/target/product/qssi/system/framework/android.car.jar。具体的区别可以参考这篇博客《CarService的构成和初始化分析》

将android.car.jar文件push进system/framework/之后,重启即可生效。

代码提交

综上,更新一个信号需要CarService修改4个文件

  • LINUX\android\packages\services\Car\car-lib\api\current.txt
  • LINUX\android\packages\services\Car\car-lib-module\api\current.txt
  • LINUX\android\packages\services\Car\car-lib\src\android\car\VehiclePropertyIds.java
  • LINUX\android\packages\services\Car\service\src\com\android\car\hal\PropertyHalServiceIds.java

站在CarService提交代码的角度来说,VHAL只需要保证修改types.hal并比CarService先合入即可。DefaultConfig.h是VHAL自己的默认值设置,对于CarService编译无影响。

(非必需)添加枚举值

有些进阶需求还会在car-lib中添加枚举类,来限制信号的具体值。比如,在枚举类中定义常量ON和OFF,这样APP编写代码时使用常量名,至于ON和OFF代表的具体值,APP并不关注。这样当信号值变化时,更新枚举类和生成的jar包即可,APP代码无需变动,对于平台类项目很合适。

添加枚举值时,可以在types.hal中添加enum,参考原生的代码:

enum EvsServiceState : int32_t {
    OFF = 0,
    ON = 1,
};

之后编译VHAL,可得到产物/out/soong/.intermediates/hardware/interfaces/automotive/vehicle/2.0/android.hardware.automotive.vehicle-V2.0-java_gen_java/gen/srcs/android/hardware/automotive/vehicle/V2_0/EvsServiceState.java

可以把这个java枚举类放入car-lib目录下,例如在car-lib/src/android/car中新建一个文件夹专门放置枚举类。然后打包进jar供APP使用。但java文件中的包名需要修改,还需要添加构造方法,否则会编译报错。枚举类较多时,可以用脚本进行批量修改。

注意在car-lib中修改枚举类之后,要更新current.txt文件。

调试

CarService的调试,涉及上层APP和下层VHAL。

APP侧调试

APP侧,可以写一个测试APP引入android.car.jar,调用set/get/register三种接口。APP应当有系统权限,否则无法set。如果一些信号有在PropertyHalServiceIds里设置读写权限,APP也应当加上。

初始化代码

private Car mCarApi;
private CarPropertyManager mCarPropertyManager;

if (mCarApi != null && mCarApi.isConnected()) {
    mCarApi.disconnect();
    mCarApi = null;
}
mCarApi = Car.createCar(context, null, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT, (car, ready) -> {
    if (ready) {
        mCarPropertyManager = (CarPropertyManager) car.getCarManager(Car.PROPERTY_SERVICE);
    } else {
        // CarService发生异常或断开时,需要client端处理
    }
});

注册/注销监听

private final CarPropertyManager.CarPropertyEventCallback mCarPropertyEventListener = new CarPropertyManager.CarPropertyEventCallback() {
    @Override
    public void onChangeEvent(CarPropertyValue carPropertyValue) {
    }

    @Override
    public void onErrorEvent(int var1, int var2) {
    }
};

mCarPropertyManager.registerCallback(mCarPropertyEventListener, propertyId, CarPropertyManager.SENSOR_RATE_ONCHANGE);
mCarPropertyManager.unregisterCallback(mCarPropertyEventListener, propertyId);

set接口。areaId一般使用0(GLOBAL),不是GLOBAL的信号应使用对应的areaId。

    public void setBooleanProperty(int prop, int areaId, boolean val) 
    public void setFloatProperty(int prop, int areaId, float val) 
    public void setIntProperty(int prop, int areaId, int val) 
    public <E> void setProperty(@NonNull Class<E> clazz, int propId, int areaId, @NonNull E val) 

get接口。areaId一般使用0(GLOBAL),不是GLOBAL的信号应使用对应的areaId。

    public boolean getBooleanProperty(int prop, int area) 
    public float getFloatProperty(int prop, int area) 
    public int getIntProperty(int prop, int area) 
    public int[] getIntArrayProperty(int prop, int area) 
    public <E> CarPropertyValue<E> getProperty(@NonNull Class<E> clazz, int propId, int areaId) 

VHAL侧调试

原生提供了命令进行调试。

adb shell lshal debug android.hardware.automotive.vehicle@2.0::IVehicle --set 信号id -i 信号值

信号id可以直接写十进制的id,也可以使用0x的十六进制id。-i表示int型,还可以使用f(float),b(byte数组)

byte数组的格式比较特殊

adb shell lshal debug android.hardware.automotive.vehicle@2.0::IVehicle --set 信号id -b 0x0102

0x之后,每两位占一个字节。

get命令

adb shell lshal debug android.hardware.automotive.vehicle@2.0::IVehicle --get 信号id

CAR.HAL : fetchAllPropConfigs Add config for prop:21401087 config:{.prop = 557846663, .access = READ, .changeMode = ON_CHANGE, .areaConfigs = [], .configArray = [], .configString = , .minSampleRate = 0.0, .maxSampleRate = 0.0} Line 16253: 05-29 13:33:40.350224 2262 2262 D PropertyHalService: takeSupportedProperties: 21401087 Line 21001: 05-29 13:33:44.024170 2677 2677 D CarPropertyManager: getProperty, propId: 0x21401087, areaId: 0x0, class: class java.lang.Integer Line 21015: 05-29 13:33:44.027945 2262 3275 I CAR.HAL : get, property: 0x21401087, areaId: 0x0 Line 21043: 05-29 13:33:44.043146 2642 2642 D CarPropertyManager: getProperty, propId: 0x21401087, areaId: 0x0, class: class java.lang.Integer Line 21048: 05-29 13:33:44.045207 2262 2340 I CAR.HAL : get, property: 0x21401087, areaId: 0x0 Line 21051: 05-29 13:33:44.046275 2262 2340 D PropertyHalService: getProperty value = [CarPropertyValue{mPropertyId=0x21401087, mAreaId=0x0, mStatus=0, mTimestamp=19449340523, mValue=0}]. Line 21052: 05-29 13:33:44.047302 2262 2340 D Property.service: registerListener: propId=0x21401087 rate=0.0 Line 21053: 05-29 13:33:44.047533 2262 3275 D PropertyHalService: getProperty value = [CarPropertyValue{mPropertyId=0x21401087, mAreaId=0x0, mStatus=0, mTimestamp=19432058430, mValue=0}]. Line 21060: 05-29 13:33:44.051705 2262 3275 D Property.service: registerListener: propId=0x21401087 rate=0.0 Line 21085: 05-29 13:33:44.062696 2262 2340 D PropertyHalService: subscribeProperty propId=0x21401087, rate=0.0 Line 21086: 05-29 13:33:44.062784 2262 2340 I CAR.HAL : subscribeProperty, service:com.android.car.hal.PropertyHalService@63f35b, property: 0x21401087 Line 21088: 05-29 13:33:44.063336 1908 1943 I automotive.vehicle@2.0-impl: SubscriptionManager::addOrUpdateSubscription, prop: 0x21401087 Line 21089: 05-29 13:33:44.063361 1908 1943 I automotive.vehicle@2.0-impl: addOrUpdateSubscription opts.propId: 0x21401087 Line 21090: 05-29 13:33:44.063417 1908 1943 I BmiVehicleHal: subscribe propId: 0x21401087, sampleRate: 0.000000 Line 21207: 05-29 13:33:44.098817 2262 2340 D Property.service: registerListener: propId=0x21401087 rate=0.0 Line 23413: 05-29 13:33:46.171879 3395 3395 D CarPropertyManager: getProperty, propId: 0x21401087, areaId: 0x0, class: class java.lang.Integer Line 23420: 05-29 13:33:46.180529 2262 3261 I CAR.HAL : get, property: 0x21401087, areaId: 0x0 Line 23422: 05-29 13:33:46.184444 2262 3261 D PropertyHalService: getProperty value = [CarPropertyValue{mPropertyId=0x21401087, mAreaId=0x0, mStatus=0, mTimestamp=21584668633, mValue=0}]. Line 23430: 05-29 13:33:46.190524 2262 3272 D Property.service: registerListener: propId=0x21401087 rate=0.0 Line 25176: 05-29 13:33:47.525665 2711 2711 D CarPropertyManager: getProperty, propId: 0x21401087, areaId: 0x0, class: class java.lang.Integer Line 25181: 05-29 13:33:47.526435 2262 3261 I CAR.HAL : get, property: 0x21401087, areaId: 0x0 Line 25182: 05-29 13:33:47.527425 2262 3261 D PropertyHalService: getProperty value = [CarPropertyValue{mPropertyId=0x21401087, mAreaId=0x0, mStatus=0, mTimestamp=22930497817, mValue=0}]. Line 25184: 05-29 13:33:47.529974 2262 3261 D Property.service: registerListener: propId=0x21401087 rate=0.0
最新发布
06-21
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值