2. 实现车辆属性读写接口

任务说明

本案例需要在Android Car服务中实现自定义车辆属性的读写能力。核心目标包括:定义自定义属性ID、在CarService中实现该属性的get/set逻辑、并通过CarPropertyManager完成客户端读写验证。案例基于API 29+的CarPropertyManager机制,不涉及VHAL层真实硬件属性,使用PropertyId为0x1140_0001的自定义只读/可写属性演示完整链路。

实现步骤

  1. 定义自定义属性ID常量(与VHAL属性ID格式一致,高16位为厂商自定义区域)
  2. 在CarService的PropertyHalService中注册该属性的get/set回调
  3. 通过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进程)。

  1. 将CustomPropertyService注册到CarService:在SystemCarService.java的onCreate()中添加serviceRegistry.addService(Car.PROPERTY_SERVICE, new CustomPropertyService()),替换默认的PropertyHalService(或通过AIDL接口扩展)。
  2. 编译并刷入系统镜像:make -j8,然后fastboot flashall。
  3. 客户端App需声明权限:<uses-permission android:name="android.car.permission.CAR_PROPERTY_CUSTOMIZE"/>,并确保App具有系统权限。
  4. 运行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的泛型类型与属性实际类型一致,否则在客户端反序列化时会报错。