Vehicle 实战 自定义属性+测试demo

文章目录

开发环境如下
  1. WSl2+ Ubuntu 22.04.5 LTS
  2. android13-r44
  3. sdk_car_x86_64-userdebug + emulator
目录结构
自定义Aidl VHal Vendor
  1. gen_oem_vehicle_property_ids.py+ gen.sh:是解析excl->json脚本
  2. vehicle_props.json 是vhal初始化所需文件
  3. vehicle-OemVhalService.rc 启动脚本
  4. vehicle-OemVhalService.xml 启动说明书
bash 复制代码
maqi@QiMa:~/android13-r44/vendor/oem$ tree
.
└── vehicle
    ├── Android.bp
    ├── gen_oem_vehicle_property_ids.py
    ├── gen.sh
    ├── OEM_VHAL_BUILD_NOTES.md
    ├── vehicle_props.json
    └── vhal
        ├── Android.bp
        ├── android.hardware.automotive.vehicle-OemVhalService.rc
        ├── android.hardware.automotive.vehicle-OemVhalService.xml
        ├── OemVehicleHardware.cpp
        ├── OemVehicleHardware.h
        ├── OemVhalService.cpp
        ├── scripts
        │   ├── excel_to_vhal_json.py
        │   └── sdb_can_signals.csv
        ├── src
        │   └── android
        │       └── oem
        │           └── vehicle
        │               └── property
        │                   └── OemVehiclePropertyId.aidl
        └── vehicle_props.json

8 directories, 15 files

目的就是为了替换 hardware/interfaces/automotive/vehicle/2.0/default

其实路径应该和系统对其的,这边还没改

源码下 hardware
bash 复制代码
maqi@QiMa:~/android13-r44/hardware/interfaces/automotive/vehicle/2.0/default$ tree 
.
├── Android.bp
├── android.hardware.automotive.vehicle@2.0-default-service.rc
├── android.hardware.automotive.vehicle@2.0-default-service.xml
├── common
│   ├── include
│   │   └── vhal_v2_0
│   │       ├── ConcurrentQueue.h
│   │       ├── Obd2SensorStore.h
│   │       ├── ProtoMessageConverter.h
│   │       ├── RecurrentTimer.h
│   │       ├── SubscriptionManager.h
│   │       ├── VehicleClient.h
│   │       ├── VehicleConnector.h
│   │       ├── VehicleHal.h
│   │       ├── VehicleHalManager.h
│   │       ├── VehicleObjectPool.h
│   │       ├── VehiclePropConfigIndex.h
│   │       ├── VehiclePropertyStore.h
│   │       ├── VehicleServer.h
│   │       ├── VehicleUtils.h
│   │       ├── VmsUtils.h
│   │       └── WatchdogClient.h
│   └── src
│       ├── Obd2SensorStore.cpp
│       ├── ProtoMessageConverter.cpp
│       ├── SubscriptionManager.cpp
│       ├── VehicleHalManager.cpp
│       ├── VehicleObjectPool.cpp
│       ├── VehiclePropertyStore.cpp
│       ├── VehicleUtils.cpp
│       ├── VmsUtils.cpp
│       └── WatchdogClient.cpp
├── impl
│   └── vhal_v2_0
│       ├── DefaultConfig.h
│       ├── DefaultVehicleConnector.h
│       ├── DefaultVehicleHal.cpp
│       ├── DefaultVehicleHal.h
│       ├── DefaultVehicleHalServer.cpp
│       ├── DefaultVehicleHalServer.h
│       ├── EmulatedVehicleHal.h
│       ├── FakeObd2Frame.cpp
│       ├── FakeObd2Frame.h
│       ├── FakeValueGenerator.h
│       ├── GeneratorHub.cpp
│       ├── GeneratorHub.h
│       ├── JsonFakeValueGenerator.cpp
│       ├── JsonFakeValueGenerator.h
│       ├── LinearFakeValueGenerator.cpp
│       ├── LinearFakeValueGenerator.h
│       ├── PropertyUtils.h
│       ├── tests
│       │   ├── Android.bp
│       │   ├── DefaultConfigSupportedPropertyIds_test.cpp
│       │   ├── DefaultVhalImpl_test.cpp
│       │   ├── override
│       │   │   ├── gear_selection.json
│       │   │   └── hvac_temperature_set.json
│       │   ├── prop.json
│       │   └── ProtoMessageConverter_test.cpp
│       ├── userhal
│       │   ├── Android.bp
│       │   ├── FakeUserHal.cpp
│       │   └── include
│       │       └── FakeUserHal.h
│       ├── VehicleHalClient.cpp
│       ├── VehicleHalClient.h
│       └── VehicleHalServer.h
├── TEST_MAPPING
├── tests
│   ├── fuzzer
│   │   ├── README.md
│   │   ├── VehicleManager_fuzzer.cpp
│   │   └── VehicleManager_fuzzer.h
│   ├── RecurrentTimer_test.cpp
│   ├── SubscriptionManager_test.cpp
│   ├── VehicleHalManager_test.cpp
│   ├── VehicleHalTestUtils.h
│   ├── VehicleObjectPool_test.cpp
│   ├── VehiclePropConfigIndex_test.cpp
│   └── VmsUtils_test.cpp
└── VehicleService.cpp

12 directories, 70 files
目前启动的是什么?
bash 复制代码
答案:AIDL。这个目录下 HIDL 和 AIDL 两套都有,但 Android 13 (T) 上最终跑的是 AIDL。

目录结构印证:

hardware/interfaces/automotive/vehicle/
2.0/    → HIDL 版  android.hardware.automotive.vehicle@2.0  (遗留/废弃,只是保留)
aidl/   → AIDL 版  android.hardware.automotive.vehicle.IVehicle (当前默认)

三条关键证据:

1. CarService 的选型逻辑(packages/services/Car/service/src/com/android/car/VehicleStub.java,第76行 newVehicleStub()):
先 new AidlVehicleStub() 连 AIDL,isValid() 为真就直接用;连不上才打日志 "No AIDL vehicle HAL found, fall back to HIDL version" 回退到 new HidlVehicleStub()。也就是 AIDL 优先,HIDL 只是兜底。

2. AIDL 默认服务(aidl/impl/vhal/):
- 二进制:android.hardware.automotive.vehicle@V1-default-service
- 服务名:vendor.vehicle-hal-default
- VINTF fqname:IVehicle/default,format="aidl"

3. HIDL 2.0 默认服务(2.0/default/):
- 二进制:android.hardware.automotive.vehicle@2.0-default-service
- 服务名:vendor.vehicle-hal-2.0,transport=hwbinder,instance=default

针对你自己的 sdk_car_x86_64-userdebug 模拟器,跑的是 AIDL 无疑:

device/generic/car/emulator/vhal_aidl/
vhal-emulator-service.rc → service vendor.vehicle-hal-emulator /vendor/bin/hw/android.hardware.automotive.vehicle@V1-emulator-service
Android.bp → 链接 device.generic.car.emulator-aidl-V1-ndk,复用 DefaultVehicleHal + FakeVehicleHardware

"@V1" 就是 AIDL 的 version 1(IVehicle),不是 HIDL。你的自定义 VHAL(vendor/oem/vehicle/vhal,服务名 vendor.oem-vhal)同样走 AIDL。

一句话:2.0/ 目录是历史遗留的 HIDL 实现,aidl/ 才是 T 版本实际生效的路径;模拟器和你的自定义 VHAL 最终都是 AIDL。
怎么替换AIDL,原理是什么?
bash 复制代码
 是的,替换成功 ------ 构建产物层面已经确认,最终镜像里只有你的 OEM VHAL,默认 AIDL VHAL 已被移除。

    核实过程(这是决定性证据,不是推测):

    1. 产品配置做了替换(device/generic/car/common/car.mk 第 18-42 行):

    PRODUCT_PACKAGES -= android.hardware.automotive.vehicle@V1-default-service   # 删默认 AIDL VHAL
    PRODUCT_SOONG_NAMESPACES += vendor/oem/vehicle/vhal
    PRODUCT_PACKAGES += android.hardware.automotive.vehicle-OemVhalService vehicle_props_oem.json


    2. 最终 vendor 分区安装清单(out/target/product/emulator_car_x86_64/installed-files-vendor.txt)里,vehicle/vhal 相关只有这 5 项:

    /vendor/bin/hw/android.hardware.automotive.vehicle-OemVhalService        ← 你的 VHAL
    /vendor/lib64/android.hardware.automotive.vehicle-V1-ndk.so              ← AIDL V1 绑定库(被你的 VHAL 依赖)
    /vendor/etc/automotive/vhal/vehicle_props_oem.json                       ← 你的属性 JSON
    /vendor/etc/init/android.hardware.automotive.vehicle-OemVhalService.rc   ← 你的启动脚本
    /vendor/etc/vintf/manifest/android.hardware.automotive.vehicle-OemVhalService.xml  ← 你的 VINTF

    没有 @V1-default-service、没有 @V1-emulator-service、也没有 HIDL @2.0-default-service。

    3. VINTF 身份完全对上:你的 OemVhalService.xml 声明 android.hardware.automotive.vehicle @ v1, IVehicle/default,和 CarService 的 AidlVehicleStub 连的 android.hardware.automotive.vehicle.IVehicle/default 完全一致。所以 CarService 起来后会直接连到你的 OEM VHAL,不会回退。

    4. SELinux 没问题:你的 rc 用 u:r:hal_vehicle_default:s0,这个域在 system/sepolicy/vendor/hal_vehicle_default.te 里是全局定义的(不是挂在 @V1-default-service 上的私有域),删了默认服务域还在,最终 file_contexts 里也有,能正常启动。

    两点说明:

    - 你替换的是「AIDL 默认 VHAL @V1-default-service」,本质是 AIDL 换 AIDL(用你的 OEM AIDL VHAL 替换 AOSP 默认 AIDL VHAL)。HIDL @2.0 本来就没在跑(Android 13 CarService 优先 AIDL),所以谈不上替换它。

    - 注:out/soong/.intermediates 和 symbols/ 目录里仍能看到 @V1-emulator-service 的编译中间产物,但那只说明它被编译过,installed-files-vendor.txt 里没有它 = 没进最终镜像,不影响结论。

    运行时验证:模拟器当前没开机(adb devices 为空),我没法直接查服务状态。开机后按指令记录.md 第 132-139 行跑即可,关键一条:

    adb shell "service check android.hardware.automotive.vehicle.IVehicle/default"   # 应返回 found
    adb shell "ps -A | grep OemVhalService"                                          # 应看到进程

先上日志vhal的启动和属性监听完整流程,以及手动注入监听回调都体现出来了。

bash 复制代码
maqi@QiMa:~/android13-r44$ adb  logcat -s CarSignalDemo CarSignalManager OemVehicleHardware OemVhalService
--------- beginning of main
10-16 10:43:51.712   245   245 I OemVhalService: OEM VHAL Service starting...
10-16 10:43:51.712   245   245 I OemVehicleHardware: loading properties from /vendor/etc/automotive/vhal/vehicle_props_oem.json
10-16 10:43:51.713   245   245 I OemVehicleHardware: InitProp 0x11400408 type:INT32 (TURN_SIGNAL_STATE) initialValue write res ok? 1
10-16 10:43:51.713   245   245 I OemVehicleHardware: InitProp 0x11400e03 type:INT32 (HAZARD_LIGHTS_STATE) initialValue write res ok? 1
10-16 10:43:51.713   245   245 I OemVehicleHardware: InitProp 0x11400e13 type:INT32 (HAZARD_LIGHTS_SWITCH) initialValue write res ok? 1
10-16 10:43:51.713   245   245 I OemVehicleHardware: InitProp 0x11400207 type:FLOAT (PERF_VEHICLE_SPEED) initialValue write res ok? 1
10-16 10:43:51.713   245   245 I OemVehicleHardware: InitProp 0x11400407 type:INT32 (GEAR_SELECTION) initialValue write res ok? 1
10-16 10:43:51.713   245   245 I OemVehicleHardware: InitProp 0x11400101 type:STRING (INFO_VIN) initialValue write res ok? 1
10-16 10:43:51.713   245   245 I OemVehicleHardware: InitProp 0x21400601 type:INT32 (VENDOR_FRAGRANCE_SWITCH) initialValue write res ok? 1
10-16 10:43:51.713   245   245 I OemVehicleHardware: InitProp 0x21400701 type:INT32 (VENDOR_WINDOW_POS) initialValue write res ok? 1
10-16 10:43:51.713   245   245 I OemVehicleHardware: InitProp 0x21600702 type:FLOAT (VENDOR_TIRE_PRESSURE) initialValue write res ok? 1
10-16 10:43:51.713   245   245 I OemVehicleHardware: InitProp 0x21400703 type:INT32 (VENDOR_RADAR_FRONT) initialValue write res ok? 1
10-16 10:43:51.713   245   245 I OemVehicleHardware: InitProp 0x21400704 type:INT32 (VENDOR_RADAR_REAR) initialValue write res ok? 1
10-16 10:43:51.713   245   245 I OemVehicleHardware: InitProp 0x21400705 type:INT32 (VENDOR_RADAR_LEFT) initialValue write res ok? 1
10-16 10:43:51.713   245   245 I OemVehicleHardware: InitProp 0x21400706 type:INT32 (VENDOR_RADAR_RIGHT) initialValue write res ok? 1
10-16 10:43:51.713   245   245 I OemVehicleHardware: loaded 13 properties
10-16 10:43:51.714   245   245 I OemVhalService: OEM VHAL service registered as android.hardware.automotive.vehicle.IVehicle/default
10-16 10:44:16.450  1656  1656 I CarSignalDemo: speed=0.0 gear=0 turnSignal=0 fragrance=0
10-16 10:44:16.492  1656  1656 I CarSignalDemo: window FL=0 FR=0 RL=0 RR=0
10-16 10:44:16.543  1656  1656 I CarSignalDemo: tire FL=0.0 FR=0.0 RL=0.0 RR=0.0
10-16 10:44:16.546  1656  1656 I CarSignalDemo: radar front=500 rear=500 left=500 right=500
10-16 10:44:16.592   245   252 I OemVehicleHardware: setValues: writeValue for prop 0x11400e13 area 0x0 ok
10-16 10:44:16.593   245   252 I OemVehicleHardware: setValues: writeValue for prop 0x21400601 area 0x1 ok
10-16 10:44:16.593   245   252 I OemVehicleHardware: setValues: writeValue for prop 0x21400701 area 0x1 ok
10-16 10:44:16.656  1656  1656 I CarSignalDemo: 转向灯 -> 0
10-16 10:44:16.656  1656  1656 I CarSignalDemo: 香氛档位 -> 0
10-16 10:44:16.656  1656  1656 I CarSignalDemo: 车窗 area=1 -> 0
10-16 10:44:16.656  1656  1656 I CarSignalDemo: 胎压 area=1 -> 0.0 kPa
10-16 10:44:16.656  1656  1656 I CarSignalDemo: 雷达 position=0 -> 500 cm
10-16 10:44:16.656  1656  1656 I CarSignalDemo: 雷达 position=1 -> 500 cm
10-16 10:44:16.656  1656  1656 I CarSignalDemo: 雷达 position=2 -> 500 cm
10-16 10:44:16.656  1656  1656 I CarSignalDemo: 雷达 position=3 -> 500 cm
10-16 10:47:35.643  1656  1656 I CarSignalDemo: 胎压 area=1 -> 250.5 kPa
10-16 10:47:46.929  1656  1656 I CarSignalDemo: 胎压 area=1 -> 25.0 kPa
10-16 10:49:15.066  1656  1656 I CarSignalDemo: 转向灯 -> 2
编译vhal
bash 复制代码
# VHAL 二进制(改了 C++ 后必编)
source build/envsetup.sh && lunch sdk_car_x86_64-userdebug 

m android.oem.vehicle.property-cpp    → C++ 头(VHAL 用)
m android.oem.vehicle.property-java   → Java 类(App 用)
m android.oem.vehicle.property-ndk	   → NDK 绑定
m android.hardware.automotive.vehicle-OemVhalService  → vhal aidl 进程
烧录执行脚本

一次性烧录hal以及demo程序

bash 复制代码
#!/bin/bash
#
# deploy_carsignal.sh ------ 部署 CarSignalDemo App + OEM VHAL 到 emulator
#
# 用法:
#   ./deploy_carsignal.sh            # 部署到 emulator-5554
#   ./deploy_carsignal.sh <serial>   # 部署到指定设备(如真机 M93664AKHG042700143)
#
# 前置: 先编译好产物(见下方 BUILD)
#
# 本脚本做的事:
#   1. root + remount
#   2. push OEM VHAL 二进制 / JSON / init.rc / vintf.xml 到 /vendor
#   3. 禁用默认 emulator VHAL(防止和 OEM VHAL 抢注册 IVehicle/default)
#   4. push App APK + privapp 权限白名单到 /system
#   5. chmod + restorecon
#   6. reboot
#   7. 验证 VHAL 注册 + 启动 App + 看日志
#
# 说明: adb.exe 是 Windows 程序, 读不了 WSL 的 /home 路径,
#       所以 push 前先 cp 到 /mnt/c/Users/Public/ (即 Windows 的 C:\Users\Public\),
#       再用 Windows 路径 push。
set -euo pipefail

# ================= 配置 =================
ADB="/mnt/d/Android/Sdk/platform-tools/adb.exe"
DEVICE="${1:-emulator-5554}"
OUT="out/target/product/emulator_car_x86_64"
BRIDGE="/mnt/c/Users/Public"        # WSL -> Windows 文件桥接目录

# ================= 编译产物=================
VHAL_BIN="$OUT/vendor/bin/hw/android.hardware.automotive.vehicle-OemVhalService"
VHAL_JSON="$OUT/vendor/etc/automotive/vhal/vehicle_props_oem.json"
VHAL_RC="$OUT/vendor/etc/init/android.hardware.automotive.vehicle-OemVhalService.rc"
VHAL_XML="$OUT/vendor/etc/vintf/manifest/android.hardware.automotive.vehicle-OemVhalService.xml"
APP_APK="$OUT/system/priv-app/CarSignalDemo/CarSignalDemo.apk"
APP_XML="$OUT/system/etc/permissions/com.oem.carsignal.xml"

# ================= 编译 (如产物缺失则提示) =================
echo "==> 检查编译产物..."
for f in "$VHAL_BIN" "$VHAL_JSON" "$VHAL_RC" "$VHAL_XML" "$APP_APK" "$APP_XML"; do
    if [ ! -f "$f" ]; then
        echo "错误: 缺少产物 $f" >&2
        echo "请先编译:" >&2
        echo "  bash -c 'source build/envsetup.sh && lunch sdk_car_x86_64-userdebug && m CarSignalDemo allowed_privapp_com.oem.carsignal android.hardware.automotive.vehicle-OemVhalService vehicle_props_oem.json'" >&2
        exit 1
    fi
done
echo "    产物齐全"

# ================= 设备检查 =================
echo "==> 检查设备 $DEVICE ..."
if ! "$ADB" devices | grep -q "$DEVICE"; then
    echo "错误: 设备 $DEVICE 未连接" >&2
    "$ADB" devices
    exit 1
fi

# ================= 桥接文件 (WSL -> Windows) =================
echo "==> 复制产物到桥接目录 $BRIDGE ..."
cp "$VHAL_BIN"  "$BRIDGE/"
cp "$VHAL_JSON" "$BRIDGE/"
cp "$VHAL_RC"   "$BRIDGE/"
cp "$VHAL_XML"  "$BRIDGE/"
cp "$APP_APK"   "$BRIDGE/"
cp "$APP_XML"   "$BRIDGE/"

BIN_NAME=$(basename "$VHAL_BIN")
JSON_NAME=$(basename "$VHAL_JSON")
RC_NAME=$(basename "$VHAL_RC")
XML_NAME=$(basename "$VHAL_XML")
APK_NAME=$(basename "$APP_APK")
APPXML_NAME=$(basename "$APP_XML")

# ================= root + remount =================
echo "==> root + remount ..."
"$ADB" -s "$DEVICE" root >/dev/null
sleep 2
"$ADB" -s "$DEVICE" wait-for-device
"$ADB" -s "$DEVICE" remount
sleep 2

# ================= push VHAL =================
echo "==> push OEM VHAL 二进制 / JSON / rc / xml ..."
"$ADB" -s "$DEVICE" shell "mkdir -p /vendor/etc/automotive/vhal"
"$ADB" -s "$DEVICE" push "C:/Users/Public/$BIN_NAME"  /vendor/bin/hw/
"$ADB" -s "$DEVICE" push "C:/Users/Public/$JSON_NAME" /vendor/etc/automotive/vhal/
"$ADB" -s "$DEVICE" push "C:/Users/Public/$RC_NAME"   /vendor/etc/init/
"$ADB" -s "$DEVICE" push "C:/Users/Public/$XML_NAME"  /vendor/etc/vintf/manifest/

# ================= 禁用默认 emulator VHAL =================
# 默认 VHAL(android.hardware.automotive.vehicle@V1-emulator-service, 服务名
# vendor.vehicle-hal-emulator)和 OEM VHAL 都注册 IVehicle/default,
# 两者并存会冲突。把它的 rc 改名成 .bak, reboot 后 init 就不会再拉起它。
echo "==> 禁用默认 emulator VHAL ..."
"$ADB" -s "$DEVICE" shell "
    for rc in \$(ls /vendor/etc/init/ 2>/dev/null | tr -d '\r' | grep -iE 'vehicle|vhal' | grep -vi OemVhal); do
        if [ -f /vendor/etc/init/\$rc ]; then
            mv /vendor/etc/init/\$rc /vendor/etc/init/\$rc.bak
            echo \"    disabled: \$rc\"
        fi
    done
"

# ================= push App =================
echo "==> push App APK + 权限白名单 ..."
"$ADB" -s "$DEVICE" shell "mkdir -p /system/priv-app/CarSignalDemo"
"$ADB" -s "$DEVICE" push "C:/Users/Public/$APK_NAME"    /system/priv-app/CarSignalDemo/
"$ADB" -s "$DEVICE" push "C:/Users/Public/$APPXML_NAME" /system/etc/permissions/

# ================= 权限 + SELinux =================
echo "==> chmod + restorecon ..."
"$ADB" -s "$DEVICE" shell "
    chmod 755 /vendor/bin/hw/$BIN_NAME
    chmod 644 /vendor/etc/automotive/vhal/$JSON_NAME
    chmod 644 /vendor/etc/init/$RC_NAME
    chmod 644 /vendor/etc/vintf/manifest/$XML_NAME
    chmod 644 /system/priv-app/CarSignalDemo/$APK_NAME
    chmod 644 /system/etc/permissions/$APPXML_NAME
    restorecon -v /vendor/bin/hw/$BIN_NAME /vendor/etc/automotive/vhal/$JSON_NAME /vendor/etc/init/$RC_NAME /vendor/etc/vintf/manifest/$XML_NAME 2>/dev/null || true
"

# ================= reboot =================
echo "==> reboot ..."
"$ADB" -s "$DEVICE" reboot
"$ADB" -s "$DEVICE" wait-for-device
echo "    等待开机完成..."
"$ADB" -s "$DEVICE" shell 'while [ "$(getprop sys.boot_completed)" != "1" ]; do sleep 2; done'
echo "    开机完成"

# ================= 验证 =================
echo "==> 验证 VHAL 进程 ..."
"$ADB" -s "$DEVICE" shell "ps -A | grep OemVhalService" || echo "    警告: 未找到 OemVhalService 进程"

echo "==> 验证 VHAL 服务注册 ..."
"$ADB" -s "$DEVICE" shell "service check android.hardware.automotive.vehicle.IVehicle/default" || true

echo "==> 启动 App ..."
"$ADB" -s "$DEVICE" shell "am start -n com.oem.carsignal/.MainActivity"

echo ""
echo "==> 完成。查看日志:"
echo "    $ADB -s $DEVICE logcat -s CarSignalDemo CarSignalManager OemVehicleHardware OemVhalService"
echo ""
echo "==> 清理桥接目录 (可选):"
echo "    rm -f $BRIDGE/$BIN_NAME $BRIDGE/$JSON_NAME $BRIDGE/$RC_NAME $BRIDGE/$XML_NAME $BRIDGE/$APK_NAME $BRIDGE/$APPXML_NAME"
CarService测试指令
bash 复制代码
# ❌ 转向灯是 READ 只读,set 会报错:
	adb shell "cmd car_service set-property-value 0x11400408 0 2"
	#   → Cannot set a property: ... (code 4) (code 4)   ← code 4 = ACCESS_DENIED
	# ✅ 转向灯用 inject(模拟上报,触发回调):
	adb shell "cmd car_service inject-vhal-event 0x11400408 0 2"

# 测「写」用 READ_WRITE 属性
	# 香氛 area=1 value=2 (MED)
	adb shell "cmd car_service set-property-value 0x21400601 1 2"
	# 双闪开关 area=0 value=1 (ON)
	adb shell "cmd car_service set-property-value 0x11400e13 0 1"
code 含义
0 OK
1 TRY_AGAIN
2 INVALID_ARG
3 NOT_AVAILABLE
4 ACCESS_DENIED(只读属性被 set,或权限不足)
5 INTERNAL_ERROR

注意 CarSignalDemo 是OEM级别的app

property-java.jar

android13-r44/out/soong/.intermediates/vendor/oem/vehicle/android.oem.vehicle.property-java/android_common/turbine/android.oem.vehicle.property-java.jar

CarSignalDemo
bash 复制代码
maqi@QiMa:~/android13-r44$ tree /home/maqi/android13-r44/packages/apps/Car/CarSignalDemo
/home/maqi/android13-r44/packages/apps/Car/CarSignalDemo
├── Android.bp
├── AndroidManifest.xml
├── com.oem.carsignal.xml
├── res
│   └── values
│       └── strings.xml
└── src
    └── com
        └── oem
            └── carsignal
                ├── CarSignalManager.java
                ├── MainActivity.java
                └── OemVehiclePropertyIds.java

6 directories, 7 files

重点看"android.oem.vehicle.property-java"它是我们自定义的属性

bash 复制代码
    // OEM 私有 vendor 属性 ID:AIDL 生成的枚举 android.oem.vehicle.property.OemVehiclePropertyId。
    // 定义在 vendor/oem/vehicle/Android.bp(归根 namespace,unstable → 模块名无 -V1- 后缀)。
    static_libs: [
        "android.oem.vehicle.property-java",
    ],

编译 APP 和权限

bash 复制代码
bash -c 'source build/envsetup.sh && lunch sdk_car_x86_64-userdebug && m CarSignalDemo allowed_privapp_com.oem.carsignal'

完整推包 上面脚本有介绍

gradle jar包依赖方式

bash 复制代码
cp out/soong/.intermediates/vendor/oem/vehicle/android.oem.vehicle.property-java/android_common/javac/android.oem.vehicle.property-java.jar \
/mnt/c/Users/Public/oem-vehicle-property.jar

第三方工程 Gradle 里

bash 复制代码
第三方开发者在 Gradle 里 compileOnly 引用它编译,运行时仍然是系统提供实现。所以"分发 car-lib"≠"打包 car-lib 进 apk",这两件事别混。
gradle

dependencies { implementation files('libs/oem-vehicle-property.jar') }

然后 android.oem.vehicle.property.OemVehiclePropertyId.VENDOR_FRAGRANCE_SWITCH 直接取 int。
树外app集成流程
bash 复制代码
    树外 Gradle 开发「系统级 settings app」是成立的,而且因为它是系统级(platform 签名 + priv-app + 白名单),能拿到 CAR_VENDOR_EXTENSION,所以能直接读写你的 vendor 属性------不需要代理服务。区别只在于:开发用 Gradle,没法像 AOSP 树内那样写 Soong 的 libs/static_libs,得自己把 jar 喂给 Gradle。

    关键:两个 jar 的引入方式不一样,别搞混。

    一、两个 jar 的性质与引入方式

    jar: android.car.jar(car-lib)
    来源: out 里提取
    Gradle 引入: compileOnly
    为什么: 实现已在系统 car framework,apk 不能重复打包,否则类冲突
    ────────────────────────────────────────
    jar: oem-vehicle-property.jar(vendor 属性 ID)
    来源: out 里提取
    Gradle 引入: implementation
    为什么: 纯常量接口,系统里没有,必须打进 apk

    二、提取 jar 的命令

    bash
    cd /home/maqi/android13-r44
    car-lib:系统级 app 建议用完整实现(含 System API,platform 签名才用得起)
    cp out/soong/.intermediates/packages/services/Car/car-lib/android.car/android_common/javac/android.car.jar \
       /mnt/c/Users/Public/android.car.jar
    若只想用 public API,改用 64K 的 stub(更规范,避免误用隐藏 API):
    cp out/soong/.intermediates/packages/services/Car/car-lib/android.car-stubs/android_common/turbine-combined/android.car-stubs.jar /mnt/c/Users/Public/android.car.jar

    vendor 属性 ID 常量
    cp out/soong/.intermediates/vendor/oem/vehicle/android.oem.vehicle.property-java/android_common/javac/android.oem.vehicle.property-java.jar \
       /mnt/c/Users/Public/oem-vehicle-property.jar


    把两个 jar 拷进 Gradle 工程的 app/libs/。

    三、build.gradle 配置

    gradle
    dependencies {
        // car-lib:编译期可见,不打包(运行期系统提供 android.car 实现)
        compileOnly files('libs/android.car.jar')
        // vendor 属性 ID:打包进 apk
        implementation files('libs/oem-vehicle-property.jar')
    }


    代码里就能像 CarSignalDemo 一样用:
    java
    import android.car.Car;
    import android.car.hardware.property.CarPropertyManager;
    import android.oem.vehicle.property.OemVehiclePropertyId;

    Car car = Car.createCar(context);
    CarPropertyManager mgr = (CarPropertyManager) car.getCarManager(Car.PROPERTY_SERVICE);
    mgr.registerCallback(cb, OemVehiclePropertyId.VENDOR_FRAGRANCE_SWITCH,
            CarPropertyManager.SENSOR_RATE_ONCHANGE);


    四、系统级落地三件套(否则权限还是拿不到)

    1. platform 签名(Gradle signingConfig,把 AOSP 的 platform 密钥转成 keystore):
    bash
    cd /home/maqi/android13-r44
    openssl pkcs8 -in build/make/target/product/security/platform.pk8 -inform DER -nocrypt -out platform.pem
    openssl pkcs12 -export -in build/make/target/product/security/platform.x509.pem \
      -inkey platform.pem -out platform.p12 -password pass:android -name platform
    keytool -importkeystore -destkeystore platform.keystore -srckeystore platform.p12 \
      -srcstoretype PKCS12 -srcstorepass android -deststorepass android -destkeypass android

    build.gradle 里:
    gradle
    signingConfigs {
        platform {
            storeFile file('platform.keystore')
            storePassword 'android'
            keyAlias 'platform'
            keyPassword 'android'
        }
    }
    android { buildTypes { release { signingConfig signingConfigs.platform } } }


    2. 装进 /system/priv-app/(不是 /system/app):
    bash
    adb root && adb remount
    adb shell mkdir -p /system/priv-app/OemSettings
    adb push "C:/Users/Public/OemSettings.apk" /system/priv-app/OemSettings/
    adb reboot


    3. privapp 白名单(声明 CAR_VENDOR_EXTENSION 等 signature|privileged 权限),否则即使签名对了,priv-app 没白名单也会在开机时被拒:
    xml
    <!-- /system/etc/permissions/oem.settings.xml -->
    <permissions>
        <privapp-permissions package="com.oem.settings">
            <permission name="android.car.permission.CAR_VENDOR_EXTENSION"/>
            <permission name="android.car.permission.CAR_EXTERIOR_LIGHTS"/>
            <permission name="android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS"/>
        </privapp-permissions>
    </permissions>

    bash
    adb push "C:/Users/Public/oem.settings.xml" /system/etc/permissions/


    五、一句话总结

    - car-lib → compileOnly,别打包(系统里有实现);vendor 属性 ID jar → implementation,要打包(系统里没有)。
    - Gradle 开发 + platform 签名 + priv-app + 白名单 = 树外的「系统级 settings app」,和树内 CarSignalDemo 拿到的权限完全等价,能读写/监听你的 vendor 属性。
相关推荐
范同学~1 小时前
固定表头+第一列+最后一列
java·服务器·前端
hetao17338371 小时前
2026-10-19 hetao1733837 的刷题记录
c++·算法
夏虫不可与之言冰1 小时前
第三课 点亮 LED 与定时器非阻塞闪烁
c语言·c++·vscode·单片机·嵌入式硬件·物联网
辛苦才能1 小时前
C++ 哈希表深度解析:删除为什么必须打标记,负载因子为什么卡 0.7
开发语言·数据结构·c++·算法
随风爱学习1 小时前
JAVA学习之异常
java
m0_639906941 小时前
HashMap:哈希扰动、扩容源码、红黑树转换、并发问题
java·算法·哈希算法
Roll圈圈2 小时前
长链接太丑影响转化率?这个短链工具让你的推广链接更专业
java
miller-tsunami2 小时前
STL简介&string相关知识点
开发语言·c++·string
神魔皆以血嗜2 小时前
Java 存储金额
java·后端