文章目录
-
-
-
- 开发环境如下
- 目录结构
-
- [自定义Aidl VHal Vendor](#自定义Aidl VHal Vendor)
- [源码下 hardware](#源码下 hardware)
- 目前启动的是什么?
- 怎么替换AIDL,原理是什么?
- 编译vhal
- 烧录执行脚本
- CarService测试指令
- CarSignalDemo
- 树外app集成流程
-
-
开发环境如下
- WSl2+ Ubuntu 22.04.5 LTS
- android13-r44
- sdk_car_x86_64-userdebug + emulator
目录结构
自定义Aidl VHal Vendor
- gen_oem_vehicle_property_ids.py+ gen.sh:是解析excl->json脚本
- vehicle_props.json 是vhal初始化所需文件
- vehicle-OemVhalService.rc 启动脚本
- 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 属性。