MiCarPropertyService 接入文档

1. 项目概述

MiCarPropertyService 是小米汽车属性服务 SDK,提供统一的车辆属性访问接口。该 SDK 支持两种实现方式:

  • MiCar AIDL 服务:通过 MiCar 服务进行车辆属性访问
  • 原生 Android Car API:通过 Android 原生 CarPropertyManager 进行访问

SDK 会根据系统环境自动选择合适的实现方式,对上层应用提供统一的 API 接口。

核心特性

  • 统一的车辆属性读写接口
  • 支持属性订阅和事件回调
  • 自动适配 MiCar 服务或原生 Android Car API
  • 完善的权限管理和错误处理

2. 架构设计

2.1 整体架构

┌─────────────────────────────────────────────────────────────┐
│                      应用层 (Application)                               │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                   MiCarPropertyManager                                 │
│              (统一属性管理接口 - 核心 API)                                │
└─────────────────────────────────────────────────────────────┘
                                 │
              ┌───────────────┴───────────────┐
              ▼                               ▼
┌──────────────────────────┐    ┌──────────────────────────┐
│    MiCarPropertyImpl          │    │  DefaultCarPropertyImpl      │
│  (MiCar AIDL 服务实现)         │    │  (原生 Android Car 实现)       │
└──────────────────────────┘    └──────────────────────────┘
              │                               │
              ▼                               ▼
┌──────────────────────────┐    ┌──────────────────────────┐
│      MiCar 服务               │    │   Android CarService          │
│  (com.mi.car.service)        │     │   (原生车辆服务)               │
└──────────────────────────┘    └──────────────────────────┘

2.2 核心类说明

类名说明
MiCarMiCar 主入口类,负责创建和管理 MiCar 实例
MiCarPropertyManager属性管理器,提供统一的属性访问接口
MiCarPropertyConfig属性配置类,描述属性的元数据信息
MiCarPropertyValue属性值类,封装属性的值和状态
MiCarPropertyImplMiCar AIDL 服务实现
DefaultCarPropertyImpl原生 Android Car API 实现

2.3 服务选择机制

SDK 在初始化时会自动检测系统环境:

  • 如果系统支持 MiCar 服务(通过 getPackageManager().getPackageInfo("com.mi.car.property") 检测),则使用 MiCarImpl
  • 否则回退到原生 Android Car API,使用 DefaultNativeCarImpl

判断底层服务类型

通过:MiCar.isMiCarServiceSupported() 方法进行判断是否支持底层服务。

可以通过 MiCar.getServiceType() 方法判断当前底层链接的是原生的 CarService 还是独立的 CarPropertyService:

// 获取服务类型
MiCar.ServiceType serviceType = miCar.getServiceType();
 
if (serviceType == MiCar.ServiceType.NOT_INITIALIZED) {
    // 服务尚未初始化
    Log.w(TAG, "Car service not yet initialized");
} else if (serviceType == MiCar.ServiceType.MICAR_SERVICE) {
    // 使用 MiCar AIDL 服务(独立 CarPropertyService)
    Log.i(TAG, "Using MiCar AIDL service (independent CarPropertyService)");
} else if (serviceType == MiCar.ServiceType.NATIVE_CAR_SERVICE) {
    // 使用原生 Android CarService
    Log.i(TAG, "Using native Android CarService");
}

ServiceType 枚举值说明:

  • NOT_INITIALIZED: 服务尚未初始化(mCarImpl 为空)
  • MICAR_SERVICE: 使用 MiCar AIDL 服务(独立 CarPropertyService)
  • NATIVE_CAR_SERVICE: 使用原生 Android CarService

3. 快速开始

3.1 添加依赖

build.gradle 中添加依赖:

dependencies {
    implementation 'com.mi.car:MiCarPropertySDK:1.*.*'
}

最新版本在:https://pkgs.d.xiaomi.net/ui/native/releases/com/mi/car/MiCarPropertySDK

在 android bp 中添加依赖:

static_libs: [
    "mi-car-property-sdk",
],

3.2 权限配置

AndroidManifest.xml 中添加所需权限:

<!-- 基础车辆权限 -->
<uses-permission android:name="android.car.permission.CAR_INFO" />
<uses-permission android:name="android.car.permission.CAR_SPEED" />
<uses-permission android:name="android.car.permission.CAR_ENERGY" />
 
<!-- 根据需要添加其他权限 -->
<uses-permission android:name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME" />
<uses-permission android:name="android.car.permission.CAR_CONTROL_INTERIOR_LIGHTS" />

3.3 初始化 MiCar 实例

🎁 重要提示:初始化 MiCar 实例时,必须正确处理服务连接和断开的生命周期,确保资源的正确管理。

import mi.car.property.MiCar;
import mi.car.property.MiCarPropertyManager;
import mi.car.property.hardware.MiCarPropertyValue;
 
public class CarPropertyManager {
    private static final String TAG = "CarPropertyManager";
 
    private MiCar mMiCar;
    private MiCarPropertyManager mPropertyManager;
    private final Context mContext;
    private final Handler mHandler;
 
    // 订阅的属性回调
    private final MiCarPropertyManager.MiCarPropertyEventCallback mPropertyCallback =
        new MiCarPropertyManager.MiCarPropertyEventCallback() {
            @Override
            public void onChangeEvent(MiCarPropertyValue value) {
                Log.i(TAG, "Property changed: " + value.getPropertyId() +
                      " = " + value.getValue());
            }
 
            @Override
            public void onErrorEvent(int propertyId, int areaId) {
                Log.e(TAG, "Property error: propertyId=" + propertyId +
                      ", areaId=" + areaId);
            }
        };
 
    public CarPropertyManager(Context context, Handler handler) {
        mContext = context;
        mHandler = handler;
    }
 
    /**
     * 初始化 MiCar 实例
     */
    public void initialize() {
        // 创建 MiCar 实例
        mMiCar = MiCar.createCar(mContext, mHandler,
                  MiCar.CAR_WAIT_TIMEOUT_DO_NOT_WAIT,
            new MiCar.MiCarServiceLifecycleListener() {
                @Override
                public void onLifecycleChanged(@NonNull MiCar car, boolean ready) {
                    if (ready) {
                        // MiCar 服务已连接,进行服务初始化
                        mPropertyManager = (MiCarPropertyManager)
                        car.getCarManager(MiCar.PROPERTY_SERVICE);
                        //
                        mPropertyManager.registerCallback(....);
                    } else {
                        // MiCar 服务已断开,清理资源
                        mPropertyManager.unregisterCallback(....);
                        mPropertyManager = null;
                    }
                }
            });
    }
 
    /**
     * 获取属性管理器(需要检查是否可用)
     */
    @Nullable
    public MiCarPropertyManager getPropertyManager() {
        return mPropertyManager;
    }
 
    /**
     * 检查服务是否已就绪
     */
    public boolean isServiceReady() {
        return mMiCar != null && mMiCar.isConnected() && mPropertyManager != null;
    }
 
    /**
     * 释放资源
     */
    public void release() {
        // 1. 取消所有属性订阅
        if (mPropertyManager != null) {
            try {
                mPropertyManager.unregisterCallback(mPropertyCallback);
            } catch (Exception e) {
                Log.e(TAG, "Failed to unregister callbacks during release", e);
            }
        }
 
        // 2. 设置为 null
        mPropertyManager = null;
 
        // 3. 断开 MiCar 连接
        if (mMiCar != null) {
            try {
                mMiCar.release();
            } catch (Exception e) {
                Log.e(TAG, "Failed to disconnect MiCar", e);
            }
            mMiCar = null;
        }
 
        Log.i(TAG, "CarPropertyManager released");
    }
}

初始化流程说明

连接成功时(ready=true):

  1. 获取 MiCarPropertyManager 实例
  2. 初始化属性订阅
  3. 开始接收属性变化事件

断开时(ready=false):

  1. 取消所有属性订阅
  2. mPropertyManager 设置为 null
  3. 防止后续操作导致异常

💡 最佳实践:在使用 mPropertyManager 前,务必检查其是否为 null,避免服务断开后继续操作导致崩溃。

// 正确的使用方式
if (mPropertyManager != null) {
    try {
        int value = mPropertyManager.getIntProperty(propertyId, areaId);
        // 处理值...
    } catch (Exception e) {
        Log.e(TAG, "Failed to get property", e);
    }
}
 
// 或者使用 isServiceReady() 方法
if (isServiceReady()) {
    // 安全地使用 propertyManager
}

4. 核心 API 使用

4.1 获取属性列表

// 获取所有可用属性
List<MiCarPropertyConfig> propertyList = propertyManager.getPropertyList();
 
// 获取指定属性的配置
MiCarPropertyConfig<?> config = propertyManager.getCarPropertyConfig(propertyId);

4.2 读取属性值

// 读取布尔类型属性
boolean boolValue = propertyManager.getBooleanProperty(propertyId, areaId);
 
// 读取浮点类型属性
float floatValue = propertyManager.getFloatProperty(propertyId, areaId);
 
// 读取整型属性
int intValue = propertyManager.getIntProperty(propertyId, areaId);
 
// 读取整型数组属性
int[] intArrayValue = propertyManager.getIntArrayProperty(propertyId, areaId);
 
// 通用读取方法
MiCarPropertyValue<Integer> value = propertyManager.getProperty(Integer.class, propertyId, areaId);

4.3 设置属性值

// 设置布尔类型属性
propertyManager.setBooleanProperty(propertyId, areaId, true);
 
// 设置浮点类型属性
propertyManager.setFloatProperty(propertyId, areaId, 25.5f);
 
// 设置整型属性
propertyManager.setIntProperty(propertyId, areaId, 100);
 
// 通用设置方法
propertyManager.setProperty(Integer.class, propertyId, areaId, 100);

4.4 属性订阅与回调

// 定义回调接口
MiCarPropertyManager.MiCarPropertyEventCallback callback =
    new MiCarPropertyManager.MiCarPropertyEventCallback() {
        @Override
        public void onChangeEvent(MiCarPropertyValue value) {
            // 属性值变化回调
            Log.i(TAG, "Property changed: " + value.getPropertyId() +
                  " = " + value.getValue());
        }
 
        @Override
        public void onErrorEvent(int propertyId, int areaId) {
            // 属性访问错误回调
            Log.e(TAG, "Property error: " + propertyId + ", area: " + areaId);
        }
    };
 
// 注册回调,订阅属性变化
boolean registered = propertyManager.registerCallback(
    callback,
    propertyId,
    MiCarPropertyManager.SENSOR_RATE_ONCHANGE  // 更新频率
);
 
// 取消单个属性订阅
propertyManager.unregisterCallback(callback, propertyId);
 
// 取消所有订阅
propertyManager.unregisterCallback(callback);

4.5 新增接口说明

//
release()

4.6 异步属性操作

// 异步获取属性
List<MiCarPropertyManager.GetPropertyRequest> requests = new ArrayList<>();
requests.add(MiCarPropertyManager.GetPropertyRequest.generateGetPropertyRequest(
    requestId, propertyId, areaId));
 
propertyManager.getPropertiesAsync(
    requests,
    MiCarPropertyManager.ASYNC_GET_DEFAULT_TIMEOUT_MS,
    null,  // cancellationSignal
    executor,
    new MiCarPropertyManager.GetPropertyCallback() {
        @Override
        public void onSuccess(@NonNull MiCarPropertyManager.GetPropertyResult<?> result) {
            Log.i(TAG, "Async get success: " + result.getValue());
        }
 
        @Override
        public void onFailure(@NonNull MiCarPropertyManager.PropertyAsyncError error) {
            Log.e(TAG, "Async get failed: " + error.getErrorCode());
        }
    }
);
 
// 异步设置属性
List<MiCarPropertyManager.SetPropertyRequest<?>> setRequests = new ArrayList<>();
setRequests.add(MiCarPropertyManager.SetPropertyRequest.generateSetPropertyRequest(
    requestId, propertyId, areaId, value));
 
propertyManager.setPropertiesAsync(
    setRequests,
    MiCarPropertyManager.ASYNC_GET_DEFAULT_TIMEOUT_MS,
    null,  // cancellationSignal
    executor,
    new MiCarPropertyManager.SetPropertyCallback() {
        @Override
        public void onSuccess(@NonNull MiCarPropertyManager.SetPropertyResult result) {
            Log.i(TAG, "Async set success");
        }
 
        @Override
        public void onFailure(@NonNull MiCarPropertyManager.PropertyAsyncError error) {
            Log.e(TAG, "Async set failed: " + error.getErrorCode());
        }
    }
);

5. 属性配置详解

5.1 MiCarPropertyConfig 结构

public class MiCarPropertyConfig<T> {
    // 属性访问类型
    public static final int VEHICLE_PROPERTY_ACCESS_NONE = 0;      // 无访问权限
    public static final int VEHICLE_PROPERTY_ACCESS_READ = 1;      // 只读
    public static final int VEHICLE_PROPERTY_ACCESS_WRITE = 2;     // 只写
    public static final int VEHICLE_PROPERTY_ACCESS_READ_WRITE = 3; // 读写
 
    // 属性变化模式
    public static final int VEHICLE_PROPERTY_CHANGE_MODE_STATIC = 0;     // 静态,不变化
    public static final int VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE = 1;   // 变化时通知
    public static final int VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS = 2; // 连续变化
 
    // 区域类型
    public static final int VEHICLE_AREA_TYPE_GLOBAL = 0;  // 全局属性
    public static final int VEHICLE_AREA_TYPE_WINDOW = 2;  // 窗户
    public static final int VEHICLE_AREA_TYPE_SEAT = 3;    // 座椅
    public static final int VEHICLE_AREA_TYPE_DOOR = 4;    // 车门
    public static final int VEHICLE_AREA_TYPE_MIRROR = 5;  // 后视镜
    public static final int VEHICLE_AREA_TYPE_WHEEL = 6;   // 车轮
    public static final int VEHICLE_AREA_TYPE_VENDOR = 7;  // 厂商自定义
}

5.2 属性值状态

public class MiCarPropertyValue<T> {
    // 属性状态
    public static final int STATUS_AVAILABLE = 0;    // 可用
    public static final int STATUS_UNAVAILABLE = 1;  // 不可用
    public static final int STATUS_ERROR = 2;        // 错误
}

6. 错误处理

6.1 常见异常

异常类型说明处理建议
MiPropertyAccessDeniedSecurityException权限不足检查应用权限配置
MiPropertyNotAvailableException属性不可用检查属性是否支持
IllegalArgumentException参数错误检查参数合法性
IllegalStateException服务未连接确保 MiCar 已连接
RemoteException远程服务异常重试或检查服务状态

6.2 错误码定义

// 设置属性错误码
public static final int CAR_SET_PROPERTY_ERROR_CODE_TRY_AGAIN = 1;
public static final int CAR_SET_PROPERTY_ERROR_CODE_INVALID_ARG = 2;
public static final int CAR_SET_PROPERTY_ERROR_CODE_PROPERTY_NOT_AVAILABLE = 3;
public static final int CAR_SET_PROPERTY_ERROR_CODE_ACCESS_DENIED = 4;
public static final int CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN = 5;
 
// 异步操作错误码
public static final int STATUS_OK = 0;
public static final int STATUS_ERROR_INTERNAL_ERROR = 1;
public static final int STATUS_ERROR_NOT_AVAILABLE = 2;
public static final int STATUS_ERROR_TIMEOUT = 3;

7. 完整使用示例

以下是一个完整的使用示例,展示了从初始化到释放资源的完整生命周期:

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
 
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
 
import mi.car.property.MiCar;
import mi.car.property.MiCarPropertyManager;
import mi.car.property.hardware.MiCarPropertyConfig;
import mi.car.property.hardware.MiCarPropertyValue;
 
import java.util.List;
 
public class CarPropertyExample {
    private static final String TAG = "CarPropertyExample";
 
    private MiCar mMiCar;
    private MiCarPropertyManager mPropertyManager;
    private boolean mIsInitialized = false;
 
    private final Context mContext;
    private final Handler mMainHandler;
 
    // 属性变化回调
    private final MiCarPropertyManager.MiCarPropertyEventCallback mPropertyCallback =
        new MiCarPropertyManager.MiCarPropertyEventCallback() {
            @Override
            public void onChangeEvent(MiCarPropertyValue value) {
                Log.i(TAG, "Property [0x" + Integer.toHexString(value.getPropertyId()) +
                      "] = " + value.getValue());
                handlePropertyChange(value);
            }
 
            @Override
            public void onErrorEvent(int propertyId, int areaId) {
                Log.e(TAG, "Property error: propertyId=0x" +
                      Integer.toHexString(propertyId) + ", areaId=" + areaId);
            }
        };
 
    public CarPropertyExample(Context context) {
        mContext = context.getApplicationContext();
        mMainHandler = new Handler(Looper.getMainLooper());
    }
 
    /**
     * 初始化
     */
    public void initialize() {
        Log.i(TAG, "Initializing CarPropertyExample...");
 
        mMiCar = MiCar.createCar(mContext, mMainHandler,
                 MiCar.CAR_WAIT_TIMEOUT_DO_NOT_WAIT,
            new MiCar.MiCarServiceLifecycleListener() {
                @Override
                public void onLifecycleChanged(@NonNull MiCar car, boolean ready) {
                    mMiCar = car;
                    if (ready) {
                        onCarServiceConnected();
                    } else {
                        onCarServiceDisconnected();
                    }
                }
            });
    }
 
    /**
     * 服务连接成功
     */
    private void onCarServiceConnected() {
        Log.i(TAG, "MiCar service connected");
 
        try {
            // 获取属性管理器
            mPropertyManager = (MiCarPropertyManager)
                mMiCar.getCarManager(MiCar.PROPERTY_SERVICE);
 
            if (mPropertyManager == null) {
                Log.e(TAG, "Failed to get property manager");
                return;
            }
 
            // 初始化完成
            mIsInitialized = true;
 
            // 获取属性列表
            listAvailableProperties();
 
            // 订阅属性变化
            subscribeToProperties();
 
            // 读取示例属性
            readSampleProperties();
 
        } catch (Exception e) {
            Log.e(TAG, "Initialization failed", e);
        }
    }
 
    /**
     * 服务断开连接
     */
    private void onCarServiceDisconnected() {
        Log.w(TAG, "MiCar service disconnected");
 
        mIsInitialized = false;
 
        // 取消所有属性订阅
        if (mPropertyManager != null) {
            try {
                mPropertyManager.unregisterCallback(mPropertyCallback);
                Log.i(TAG, "Unregistered all callbacks");
            } catch (Exception e) {
                Log.e(TAG, "Failed to unregister callbacks", e);
            }
        }
 
        // 设置为 null
        mPropertyManager = null;
 
        Log.i(TAG, "Cleanup completed");
    }
 
    /**
     * 列出可用属性
     */
    private void listAvailableProperties() {
        if (mPropertyManager == null) return;
 
        try {
            List<MiCarPropertyConfig> configs = mPropertyManager.getPropertyList();
            Log.i(TAG, "Available properties: " + configs.size());
 
            for (MiCarPropertyConfig config : configs) {
                Log.d(TAG, "  - Property 0x" + Integer.toHexString(config.getPropertyId()) +
                      " (access=" + config.getAccess() +
                      ", changeMode=" + config.getChangeMode() + ")");
            }
        } catch (Exception e) {
            Log.e(TAG, "Failed to list properties", e);
        }
    }
 
    /**
     * 订阅属性变化
     */
    private void subscribeToProperties() {
        if (mPropertyManager == null) return;
 
        // 订阅车辆速度
        int vehicleSpeed = 0x11400200;
        subscribeProperty(vehicleSpeed);
 
        // 订阅电池电量
        int batteryLevel = 0x11400201;
        subscribeProperty(batteryLevel);
    }
 
    /**
     * 订阅单个属性
     */
    private void subscribeProperty(int propertyId) {
        if (mPropertyManager == null) return;
 
        try {
            boolean registered = mPropertyManager.registerCallback(
                mPropertyCallback,
                propertyId,
                MiCarPropertyManager.SENSOR_RATE_ONCHANGE
            );
            Log.i(TAG, "Subscribe to 0x" + Integer.toHexString(propertyId) +
                  ": " + (registered ? "success" : "failed"));
        } catch (Exception e) {
            Log.e(TAG, "Failed to subscribe to 0x" + Integer.toHexString(propertyId), e);
        }
    }
 
    /**
     * 读取示例属性
     */
    private void readSampleProperties() {
        if (mPropertyManager == null) return;
 
        // 读取整型属性
        try {
            int vehicleSpeed = 0x11400200;
            MiCarPropertyValue<Integer> speedValue =
                mPropertyManager.getProperty(Integer.class, vehicleSpeed, 0);
            Log.i(TAG, "Vehicle speed: " + speedValue.getValue());
        } catch (Exception e) {
            Log.e(TAG, "Failed to read vehicle speed", e);
        }
 
        // 读取浮点属性
        try {
            int batteryLevel = 0x11400201;
            float level = mPropertyManager.getFloatProperty(batteryLevel, 0);
            Log.i(TAG, "Battery level: " + level);
        } catch (Exception e) {
            Log.e(TAG, "Failed to read battery level", e);
        }
    }
 
    /**
     * 处理属性变化
     */
    private void handlePropertyChange(MiCarPropertyValue value) {
        // 根据属性 ID 处理不同的变化
        int propertyId = value.getPropertyId();
 
        switch (propertyId) {
            case 0x11400200:
                Log.i(TAG, "Speed changed: " + value.getValue());
                break;
            case 0x11400201:
                Log.i(TAG, "Battery level changed: " + value.getValue());
                break;
            default:
                Log.d(TAG, "Other property changed: 0x" +
                      Integer.toHexString(propertyId));
        }
    }
 
    /**
     * 设置属性示例
     */
    public void setPropertyExample() {
        if (mPropertyManager == null) {
            Log.w(TAG, "Property manager not available");
            return;
        }
 
        try {
            // 设置整型属性
            int propertyId = 0x11500200; // 示例属性
            mPropertyManager.setIntProperty(propertyId, 0, 100);
            Log.i(TAG, "Property set successfully");
        } catch (Exception e) {
            Log.e(TAG, "Failed to set property", e);
        }
    }
 
    /**
     * 检查服务是否就绪
     */
    public boolean isServiceReady() {
        return mIsInitialized && mPropertyManager != null;
    }
 
    /**
     * 释放资源
     */
    public void release() {
        Log.i(TAG, "Releasing CarPropertyExample...");
 
        mIsInitialized = false;
 
        // 1. 取消所有订阅
        if (mPropertyManager != null) {
            try {
                mPropertyManager.unregisterCallback(mPropertyCallback);
            } catch (Exception e) {
                Log.e(TAG, "Failed to unregister callbacks", e);
            }
        }
 
        // 2. 设置为 null
        mPropertyManager = null;
 
        // 3. 断开 MiCar
        if (mMiCar != null) {
            try {
                mMiCar.release();
            } catch (Exception e) {
                Log.e(TAG, "Failed to disconnect MiCar", e);
            }
            mMiCar = null;
        }
 
        Log.i(TAG, "CarPropertyExample released");
    }
}

在 Activity 中使用

public class MainActivity extends AppCompatActivity {
    private CarPropertyExample mCarPropertyExample;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        // 初始化
        mCarPropertyExample = new CarPropertyExample(this);
        mCarPropertyExample.initialize();
    }
 
    @Override
    protected void onDestroy() {
        super.onDestroy();
 
        // 释放资源
        if (mCarPropertyExample != null) {
            mCarPropertyExample.release();
            mCarPropertyExample = null;
        }
    }
}

在 Service 中使用

public class CarPropertyService extends Service {
    private CarPropertyExample mCarPropertyExample;
 
    @Override
    public void onCreate() {
        super.onCreate();
 
        // 初始化
        mCarPropertyExample = new CarPropertyExample(this);
        mCarPropertyExample.initialize();
    }
 
    @Override
    public void onDestroy() {
        super.onDestroy();
 
        // 释放资源
        if (mCarPropertyExample != null) {
            mCarPropertyExample.release();
            mCarPropertyExample = null;
        }
    }
 
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

8. 调试与 Mock 命令

8.1 核心调试开关

Settings.Global 开关

设置项作用启用命令禁用命令
vehicle_debug_enableDebug 日志开关adb shell settings put global vehicle_debug_enable 1adb shell settings put global vehicle_debug_enable 0
mi_vehicle_mock_dataMock 数据开关adb shell settings put global mi_vehicle_mock_data 1adb shell settings put global mi_vehicle_mock_data 0

生效机制:通过 ContentObserver 监听,修改后立即生效,无需重启服务。

开启调试模式

adb shell settings put global mi_vehicle_debug_enable 1
adb shell settings put global mi_vehicle_mock_data 1

8.2 Shell 调试命令

MiCarPropertyService 服务名为 micar_property,通过 dumpsys 接口暴露调试命令。

# 命令格式
adb shell dumpsys micar_property <command> [arguments...]

可用命令

命令用途示例
inject-vhal-event注入单个属性事件dumpsys micar_property inject-vhal-event 0x11400200 50
inject-error-event注入错误事件dumpsys micar_property inject-error-event 0x11400200 0 1
inject-continuous-events注入连续事件dumpsys micar_property inject-continuous-events 0x11400200 50 -s 10 -d 60
get-property-value获取属性值dumpsys micar_property get-property-value 0x11400200
set-property-value设置属性值dumpsys micar_property set-property-value 0x11400200 0 50
get-carpropertyconfig获取属性配置dumpsys micar_property get-carpropertyconfig
list-vhal-props列出所有属性dumpsys micar_property list-vhal-props
check-fake-vhal检查 FakeVHALdumpsys micar_property check-fake-vhal
get-vhal-backend获取 VHAL 类型dumpsys micar_property get-vhal-backend

8.3 信号 Mock

通过 VHAL Mock

adb shell dumpsys android.hardware.automotive.vehicle.IVehicle/micar \
  --mock_from_car <property_id> -i <value> -a <area_id> --stat <status>
 
# 示例:Mock 车速
adb shell dumpsys android.hardware.automotive.vehicle.IVehicle/micar \
  --mock_from_car 289408000 -i 60 -a 0 --stat 0

详细参考:libvhalclient(IVehicle)使用文档

8.4 日志系统

日志 Tag 前缀

  • 服务端:PropServer-<ClassName>
  • SDK 端:PropSDK-<ClassName>

全局日志控制

# 开启所有 DEBUG 日志
adb shell setprop persist.log.tag D

9. 注意事项

  1. 权限检查:使用属性前必须确保应用已获得相应权限
  2. 服务连接:必须等待 MiCar 服务连接成功后才能使用属性管理器
  3. 线程安全:属性操作应在主线程或指定的 Handler 线程中执行
  4. 资源释放:使用完毕后应及时取消订阅并断开 MiCar 连接
  5. 错误处理:所有属性操作都可能抛出异常,务必做好异常处理
  6. 属性可用性:部分属性可能在特定车型或配置下不可用,使用前应检查

⚠️ native 侧的 libvhalclient 不受影响

10. 常见问题

Q: 如何判断 MiCar 服务是否可用?

A: 使用 MiCar.isMiCarServiceSupported() 方法检测。

Q: 属性读取失败怎么办?

A: 检查权限配置、属性 ID 是否正确、属性是否在当前车型上可用。

Q: 如何提高属性订阅的性能?

A: 使用批量订阅、合理设置更新频率、及时取消不需要的订阅。

Q: 支持哪些属性类型?

A: 支持 Boolean、Float、Integer、Integer[]、String 等类型,具体取决于属性定义。

Q: 这个 C++ 的库(改用 libvhalclient 前后的两种)有影响吗?

A: 不影响,libvhalclient 是通过 vehicle 去获取,不涉及 carlib 的更改。

Q: A17 是必须迁移的,A14 和 A12 可以不迁移,那后续 A14 和 A12 需要迁移吗?

A: A17 如果用到的是 MiCar 定义的信号,那必须迁移,A14 和 A12 可以不用迁移。

Q: A17 不进行适配的情况下,后续会出现什么问题?

A: A17 后期不适配的话,会出现信号获取不到,订阅不到,get 不到值抛出异常等情况。

Q: 那么你们这个切换,只会上 A17 及之后版本的吧,原来的 Android 版本不会再回落了吧?

A: 只会上 A17 版本以及后续版本,目前没有计划回落到 A14 和 A12 版本。

11. 参考文档