2. 实现车辆属性读写接口
任务说明
本案例需要在Android Car服务中实现自定义车辆属性的读写能力。核心目标包括:定义自定义属性ID、在CarService中实现该属性的get/set逻辑、并通过CarPropertyManager完成客户端读写验证。案例基于API 29+的CarPropertyManager机制,不涉及VHAL层真实硬件属性,使用PropertyId为0x1140_0001的自定义只读/可写属性演示完整链路。
实现步骤
- 定义自定义属性ID常量(与VHAL属性ID格式一致,高16位为厂商自定义区域)
- 在CarService的PropertyHalService中注册该属性的get/set回调
- 通过CarPropertyManager调用
getProperty/setProperty完成读写
关键完整代码
// 1. 自定义属性ID定义(CarPropertyManager中使用的属性ID)
public final class CustomPropertyId {
// 厂商自定义区域:0x1140开头,低16位自定义
public static final int VENDOR_CUSTOM_PROPERTY = 0x11400001;
// 属性类型:整数类型
public static final int PROPERTY_TYPE_INT = 4; // 对应CarPropertyManager.PROPERTY_TYPE_INT32
}
// 2. CarService侧实现(位于packages/services/Car/service/src/.../car/)
// 在PropertyHalService中注册自定义属性处理
public class CustomPropertyService extends ICarPropertyImpl {
private static final String TAG = "CustomPropertyService";
private final Map<Integer, CarPropertyValue> mPropertyStore = new HashMap<>();
public CustomPropertyService() {
// 初始化自定义属性默认值
CarPropertyValue<Integer> defaultValue = new CarPropertyValue<>(
CustomPropertyId.VENDOR_CUSTOM_PROPERTY, 0, 100);
mPropertyStore.put(CustomPropertyId.VENDOR_CUSTOM_PROPERTY, defaultValue);
}
@Override
public synchronized CarPropertyValue getProperty(int propertyId, int areaId) {
if (propertyId != CustomPropertyId.VENDOR_CUSTOM_PROPERTY) {
throw new IllegalArgumentException("Unsupported property: " + propertyId);
}
CarPropertyValue value = mPropertyStore.get(propertyId);
if (value == null) {
throw new IllegalArgumentException("Property not initialized: " + propertyId);
}
return value;
}
@Override
public synchronized void setProperty(CarPropertyValue val) {
int propertyId = val.getPropertyId();
if (propertyId != CustomPropertyId.VENDOR_CUSTOM_PROPERTY) {
throw new IllegalArgumentException("Unsupported property: " + propertyId);
}
// 校验值范围(示例:仅允许0-200)
int newValue = (int) val.getValue();
if (newValue < 0 || newValue > 200) {
throw new IllegalArgumentException("Value out of range [0,200]: " + newValue);
}
mPropertyStore.put(propertyId, val);
}
@Override
public int[] getPropertyList() {
return new int[]{CustomPropertyId.VENDOR_CUSTOM_PROPERTY};
}
}
// 3. 客户端调用示例(App侧)
public class CarPropertyClient {
private CarPropertyManager mCarPropertyManager;
public void init(Context context) {
Car car = Car.createCar(context);
car.connect(() -> {
mCarPropertyManager = (CarPropertyManager) car.getCarManager(Car.PROPERTY_SERVICE);
// 读取属性
CarPropertyValue<Integer> value = mCarPropertyManager.getProperty(
CustomPropertyId.VENDOR_CUSTOM_PROPERTY, 0);
int currentValue = value.getValue();
Log.d("CarPropertyClient", "Current value: " + currentValue);
// 写入属性
CarPropertyValue<Integer> newValue = new CarPropertyValue<>(
CustomPropertyId.VENDOR_CUSTOM_PROPERTY, 0, 150);
mCarPropertyManager.setProperty(newValue);
// 再次读取验证
CarPropertyValue<Integer> updatedValue = mCarPropertyManager.getProperty(
CustomPropertyId.VENDOR_CUSTOM_PROPERTY, 0);
Log.d("CarPropertyClient", "Updated value: " + updatedValue.getValue());
});
}
}
运行与验证
环境要求:Android 10+模拟器或真机,需系统签名(CarService运行在system_server进程)。
- 将
CustomPropertyService注册到CarService:在SystemCarService.java的onCreate()中添加serviceRegistry.addService(Car.PROPERTY_SERVICE, new CustomPropertyService()),替换默认的PropertyHalService(或通过AIDL接口扩展)。 - 编译并刷入系统镜像:
make -j8,然后fastboot flashall。 - 客户端App需声明权限:
<uses-permission android:name="android.car.permission.CAR_PROPERTY_CUSTOMIZE"/>,并确保App具有系统权限。 - 运行App,观察Logcat输出:
// 预期输出(与代码逻辑严格一致)
D/CarPropertyClient: Current value: 100
D/CarPropertyClient: Updated value: 150
通过条件:日志中依次出现初始值100和更新后的值150,且无SecurityException或IllegalArgumentException异常。若修改值为300(超出范围),应抛出IllegalArgumentException,验证范围校验逻辑生效。
常见问题
- 权限不足:客户端必须持有
CAR_PROPERTY_CUSTOMIZE权限,否则会抛出SecurityException。 - 属性未注册:若
getProperty返回null或抛出IllegalArgumentException,检查CustomPropertyService是否已正确注册到CarService。 - 类型不匹配:确保
CarPropertyValue的泛型类型与属性实际类型一致,否则在客户端反序列化时会报错。