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 核心类说明
| 类名 | 说明 |
|---|---|
MiCar | MiCar 主入口类,负责创建和管理 MiCar 实例 |
MiCarPropertyManager | 属性管理器,提供统一的属性访问接口 |
MiCarPropertyConfig | 属性配置类,描述属性的元数据信息 |
MiCarPropertyValue | 属性值类,封装属性的值和状态 |
MiCarPropertyImpl | MiCar 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):
- 获取
MiCarPropertyManager实例 - 初始化属性订阅
- 开始接收属性变化事件
断开时(ready=false):
- 取消所有属性订阅
- 将
mPropertyManager设置为null - 防止后续操作导致异常
💡 最佳实践:在使用
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_enable | Debug 日志开关 | adb shell settings put global vehicle_debug_enable 1 | adb shell settings put global vehicle_debug_enable 0 |
mi_vehicle_mock_data | Mock 数据开关 | adb shell settings put global mi_vehicle_mock_data 1 | adb 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 18.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 | 检查 FakeVHAL | dumpsys 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 D9. 注意事项
- 权限检查:使用属性前必须确保应用已获得相应权限
- 服务连接:必须等待 MiCar 服务连接成功后才能使用属性管理器
- 线程安全:属性操作应在主线程或指定的 Handler 线程中执行
- 资源释放:使用完毕后应及时取消订阅并断开 MiCar 连接
- 错误处理:所有属性操作都可能抛出异常,务必做好异常处理
- 属性可用性:部分属性可能在特定车型或配置下不可用,使用前应检查
⚠️ 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 版本。