代码位置:
-
Car API:packages/services/Car/car-lib/
-
CarService:packages/services/Car/
-
Vehicle HAL:hardware/interfaces/automotive/vehicle/2.0/
安全性
Vehicle HAL 支持 3 个级别的数据访问安全性:
-
仅限系统(由 vns_policy.xml 控制)
-
允许拥有权限的应用访问(通过汽车服务)
-
无需任何权限即可访问(通过汽车服务)
仅允许部分系统组件直接访问车辆属性,而车辆网络服务是把关程序。大多数应用需通过汽车服务的额外把关(例如,只有系统应用可以控制 HVAC,因为这需要仅授予系统应用的系统权限)。
常用汽车权限(前缀:android.car.permission.):
● [系统权限] ADJUST_CAR_CABIN 操作轿厢信息
● [系统签名] BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE
● [系统签名] BIND_CAR_INPUT_SERVICE
● [危险权限] CAR_ENERGY 访问车辆引擎类型
● [系统权限] CAR_IDENTIFICATION 汽车VIN码的访问
● [系统权限] CAR_MILEAGE 行驶里程访问
● [危险权限] CAR_SPEED 车速属性读取
● [系统权限] CAR_TIRES 轮胎相关属性的读写
● [普通权限] CAR_ENERGY_PORTS 油箱口或者充电口信息的访问
● [系统权限] CAR_ENGINE_DETAILED 访问发动机详细信息
● [系统权限] CAR_DYNAMICS_STATE 动态值访问
● [系统权限] CAR_VENDOR_EXTENSION 访问特殊的通信信道
● [系统权限] CAR_PROJECTION 允许访问car projection相关api
● [系统权限] CAR_MOCK_VEHICLE_HAL 允许模拟车身数据
● [普通权限] CAR_INFO 允许调用CarInfoManager API的权限
● [普通权限] CAR_EXTERIOR_ENVIRONMENT 读取车外温度的权限
● [系统权限] CAR_EXTERIOR_LIGHTS 读取外车灯信息的权限
● [普通权限] CAR_POWERTRAIN 读取动力传输系统信息的权限
● [系统权限] CAR_NAVIGATION_MANAGER 使用CarNavigationStatusManager API
● [系统权限] CAR_CONTROL_AUDIO_VOLUME 控制音量
● [系统权限] CAR_CONTROL_AUDIO_SETTINGS 音量设置
● [系统权限] CAR_DISPLAY_IN_CLUSTER 应用程序必须有此签名才能在仪表盘上显示
● [系统权限] CAR_DIAGNOSTICS 读取车辆诊断内容(包括客制化字段)
● [系统权限] CAR_DRIVING_STATE 访问CarDrivingStateService去获取驾驶状态
● [系统权限] CAR_INSTRUMENT_CLUSTER_CONTROL应用程序调用CarInstrumentClusterManager在仪表盘中启动Activity时需要此权限
● [系统权限] CLEAR_CAR_DIAGNOSTICS 清理车辆诊断信息
● [系统权限] CONTROL_APP_BLOCKING
● [系统权限] CONTROL_CAR_CLIMATE 操作空调
● [系统权限] CONTROL_CAR_DOORS 操作车门信息
● [系统权限] CONTROL_CAR_EXTERIOR_LIGHTS 控制外车灯信息
● [系统权限] CONTROL_CAR_WINDOWS 操作车窗信息
● [系统权限] CONTROL_CAR_MIRRORS 操作车辆后视镜信息
● [系统权限] CONTROL_CAR_SEATS 操作车辆座椅信息
● [系统权限] STORAGE_MONITORING
● [系统权限] VMS_PUBLISHER 访问VMS publisher API
● [系统权限] VMS_SUBSCRIBER 访问VMS subscriber API
调用流程
APP端
1.初始化CarAPI和具体的Manager
Car mCar = Car.createCar(getApplicationContext(), mClientListener);
mCar.connect();
private ServiceConnection mClientListener = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
try {
Log.d(TAG,"MainActivity onServiceConnected…iBinder = "+iBinder);
mCarHvacManager = (CarHvacManager) mCar.getCarManager(Car.HVAC_SERVICE);
mSensorManager =(CarSensorManager) mCar.getCarManager(Car.SENSOR_SERVICE);
mMcuManager = (CarMcuManager) mCar.getCarManager(Car.CAR_MCU_SERVICE);
mCarDYCabinManager = (CarDYCabinManager) mCar.getCarManager(Car.DYCABIN_SERVICE);
mCarCabinManager = (CarCabinManager) mCar.getCarManager(Car.CABIN_SERVICE);
mCarInfoManager = (CarInfoManager) mCar.getCarManager(Car.INFO_SERVICE);
mCarPowerManager = (CarPowerManager) mCar.getCarManager(Car.POWER_SERVICE);
} catch (CarNotConnectedException e) { e.printStackTrace(); }
}
@Override
public void onServiceDisconnected(ComponentName componentName) { }
};
- Manager注册回调,然后通过onChangeEvent获取汽车属性值CarPropertyValue的改变:
mCarHvacManager.registerCallback(mHvacCallback);
private CarHvacEventCallback mHvacCallback = new CarHvacEventCallback() {
@Override
public void onChangeEvent(CarPropertyValue carPropertyValue) {
//Log.d(TAG, "onChangeEvent id = " + toHexString(carPropertyValue.getPropertyId()));
int value = -1;
int areaId;
switch (carPropertyValue.getPropertyId()) {
case ID_HVAC_POWER_ON:
value = (Integer)carPropertyValue.getValue();
areaId = carPropertyValue.getAreaId();
break;
default:
break;
}
}
@Override
public void onErrorEvent(int i, int i1) { }
};
- SET 和 GET,以HVAC空调为例:
mCarHvacManager.setIntProperty(ID_HVAC_LOCK_VENTILATION_ON, VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, HVAC_ON);
float temp = mCarHvacManager.getFloatProperty(ID_HVAC_TEMPERATURE_SET, SEAT_ROW_1_LEFT);
VehicleAreaType分为GLOBAL(全局)、WINDOW(车窗)、MIRROR(镜子)、SEAT(座椅)、DOOR(车门)、WHEEL(车轮)等:
enum VehicleArea : int32_t {
GLOBAL = 0x01000000,
/** WINDOW maps to enum VehicleAreaWindow */
WINDOW = 0x03000000,
/** MIRROR maps to enum VehicleAreaMirror */
MIRROR = 0x04000000,
/** SEAT maps to enum VehicleAreaSeat */
SEAT = 0x05000000,
/** DOOR maps to enum VehicleAreaDoor */
DOOR = 0x06000000,
/** WHEEL maps to enum VehicleAreaWheel */
WHEEL = 0x07000000,
/** IN_OUT_CAR maps to enum VehicleAreaInOutCar,车内外 */
IN_OUT_CAR = 0x08000000,
MASK = 0x0f000000,
};
CarAPI (car-lib:android.car.jar)
1.createCar:
public static Car createCar(Context context, ServiceConnection serviceConnectionListener, @Nullable Handler handler) {
if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
Log.e(CarLibLog.TAG_CAR, “FEATURE_AUTOMOTIVE not declared while android.car is used”);
return null;
}
try {
return new Car(context, serviceConnectionListener, handler);
} catch (IllegalArgumentException e) { // Expected when car service loader is not available.
}
return null;
}
- getCarManager(“serviceName”) -> createCarManager(“serviceName”, IBinder)
public Object getCarManager(String serviceName) throws CarNotConnectedException {
CarManagerBase manager;
ICar service = getICarOrThrow();
synchronized (mCarManagerLock) {
manager = mServiceMap.get(serviceName);
if (manager == null) {
try {
if(TBOX_SERVICE.equals(serviceName)){
manager = createCarManager(serviceName, null);
return manager;
}
IBinder binder = service.getCarService(serviceName);
if (binder == null) {
Log.w(CarLibLog.TAG_CAR, “could not get binder for service:” + serviceName);
return null;
}
manager = createCarManager(serviceName, binder);
if (manager == null) {
Log.w(CarLibLog.TAG_CAR, “could not create manager for service:” + serviceName);
return null;
}
mServiceMap.put(serviceName, manager);
} catch (RemoteException e) {
handleRemoteException(e);
}
}
}
return manager;
}
private CarManagerBase createCarManager(String serviceName, IBinder binder) throws CarNotConnectedException {
CarManagerBase manager = null;
Log.d(“liueg”, "------------------createCarManager()serviceName "+serviceName);
switch (serviceName) {
case AUDIO_SERVICE: manager = new CarAudioManager(binder, mContext, mEventHandler);break;
case SENSOR_SERVICE: manager = new CarSensorManager(binder, mContext, mEventHandler);break;
case DYSENSOR_SERVICE: manager = new CarDYSensorManager(binder, mContext, mEventHandler);break;
case INFO_SERVICE: manager = new CarInfoManager(binder);break;
case APP_FOCUS_SERVICE: manager = new CarAppFocusManager(binder, mEventHandler);break;
case PACKAGE_SERVICE: manager = new CarPackageManager(binder, mContext);break;
case CAR_NAVIGATION_SERVICE: manager = new CarNavigationStatusManager(binder);break;
case CABIN_SERVICE: manager = new CarCabinManager(binder, mContext, mEventHandler);break;
case DIAGNOSTIC_SERVICE: manager = new CarDiagnosticManager(binder, mContext, mEventHandler);break;
case HVAC_SERVICE: manager = new CarHvacManager(binder, mContext, mEventHandler);break;
case DYHVAC_SERVICE: manager = new CarDYHvacManager(binder, mContext, mEventHandler);break;
case POWER_SERVICE: manager = new CarPowerManager(binder, mContext, mEventHandler);break;
case PROJECTION_SERVICE:manager = new CarProjectionManager(binder, mEventHandler);break;
case PROPERTY_SERVICE:
manager = new CarPropertyManager(binder, mEventHandler, false, “CarPropertyManager”);break;
case VENDOR_EXTENSION_SERVICE: manager = new CarVendorExtensionManager(binder, mEventHandler);break;
case CAR_INSTRUMENT_CLUSTER_SERVICE:
manager = new CarInstrumentClusterManager(binder, mEventHandler);break;
case TEST_SERVICE:
/* CarTestManager exist in static library. So instead of constructing it here,
- only pass binder wrapper so that CarTestManager can be constructed outside. */
manager = new CarTestManagerBinderWrapper(binder);break;
case VMS_SUBSCRIBER_SERVICE: manager = new VmsSubscriberManager(binder); break;
case BLUETOOTH_SERVICE: manager = new CarBluetoothManager(binder, mContext);break;
case TBOX_SERVICE: manager = TboxManager.getInstance(); break;
case STORAGE_MONITORING_SERVICE: manager = new CarStorageMonitoringManager(binder, mEventHandler); break;
case CAR_DRIVING_STATE_SERVICE:
manager = new CarDrivingStateManager(binder, mContext, mEventHandler);break;
case CAR_UX_RESTRICTION_SERVICE:
manager = new CarUxRestrictionsManager(binder, mContext, mEventHandler);break;
case CAR_CONFIGURATION_SERVICE: manager = new CarConfigurationManager(binder);break;
case CAR_MCU_SERVICE: manager = new CarMcuManager(binder, mContext, mEventHandler);break;
case DYCABIN_SERVICE: manager = new CarDYCabinManager(binder, mContext, mEventHandler);break;
default:break;
}
return manager;
}
- 具体的Manager -> 注册/反注册回调, set/get 属性CarProperty:
public final class CarHvacManager implements CarManagerBase {
private void handleOnChangeEvent(CarPropertyValue value) {
Collection callbacks;
synchronized (this) { callbacks = new ArraySet<>(mCallbacks); }
if (!callbacks.isEmpty()) {
for (CarHvacEventCallback l: callbacks) {
if (DBG) Log.d(TAG, “onChangeEvent value=” + value.toString());
l.onChangeEvent(value);
}
}
}
private void handleOnErrorEvent(int propertyId, int zone) {
Collection callbacks;
synchronized (this) { callbacks = new ArraySet<>(mCallbacks); }
if (!callbacks.isEmpty()) {
for (CarHvacEventCallback l: callbacks) {
l.onErrorEvent(propertyId, zone);
}
}
}
public CarHvacManager(IBinder service, Context context, Handler handler) {
mCarPropertyMgr = new CarPropertyManager(service, handler, DBG, TAG);
}
public synchronized void registerCallback(CarHvacEventCallback callback)
throws CarNotConnectedException {
if (mCallbacks.isEmpty()) mListenerToBase = new CarPropertyEventListenerToBase(this);
List configs = getPropertyList();
for (CarPropertyConfig c : configs) { // Register each individual propertyId
mCarPropertyMgr.registerListener(mListenerToBase, c.getPropertyId(), 0);
}
mCallbacks.add(callback);
}
public synchronized void unregisterCallback(CarHvacEventCallback callback) {
mCallbacks.remove(callback);
try {
List configs = getPropertyList();
for (CarPropertyConfig c : configs) { // Register each individual propertyId
mCarPropertyMgr.unregisterListener(mListenerToBase, c.getPropertyId());
}
} catch (Exception e) { Log.e(TAG, "getPropertyList exception ", e); }
if (mCallbacks.isEmpty()) {
mCarPropertyMgr.unregisterListener(mListenerToBase);
mListenerToBase = null;
}
}
public List getPropertyList() throws CarNotConnectedException {
return mCarPropertyMgr.getPropertyList(mHvacPropertyIds);
}
public boolean isPropertyAvailable(@PropertyId int propertyId, int area) throws CarNotConnectedException {
return mCarPropertyMgr.isPropertyAvailable(propertyId, area);
}
// GET
// getBooleanProperty -> mCarPropertyMgr.getBooleanProperty(propertyId, area);
// getFloatProperty -> mCarPropertyMgr.getFloatProperty(propertyId, area);
// getIntProperty -> mCarPropertyMgr.getIntProperty(propertyId, area);
public boolean getBooleanProperty(@PropertyId int propertyId, int area)
throws CarNotConnectedException {
return mCarPropertyMgr.getBooleanProperty(propertyId, area);
}
// SET
// setBooleanProperty -> mCarPropertyMgr.setBooleanProperty(propertyId, area, val);
// setFloatProperty -> mCarPropertyMgr.setFloatProperty(propertyId, area, val);
// setIntProperty -> mCarPropertyMgr.setIntProperty(propertyId, area, val);
public void setBooleanProperty(@PropertyId int propertyId, int area, boolean val)
throws CarNotConnectedException {
if (mHvacPropertyIds.contains(propertyId)) {
mCarPropertyMgr.setBooleanProperty(propertyId, area, val);
}
}
}
CarService
- ICarImpl初始化多个Service,可通过getCarService返回对应的Service
public class CarService extends Service {
IVehicle mVehicle = android.hardware.automotive.vehicle.V2_0.IVehicle.getService();
ICarImpl mICarImpl = new ICarImpl(this,
mVehicle,
SystemInterface.Builder.defaultSystemInterface(this).build(),
mCanBusErrorNotifier,
mVehicleInterfaceName);
mICarImpl.init();
}
public class ICarImpl extends ICar.Stub {
public ICarImpl(Context serviceContext, IVehicle vehicle, SystemInterface systemInterface,
CanBusErrorNotifier errorNotifier, String vehicleInterfaceName) {
mContext = serviceContext;
mSystemInterface = systemInterface;
mHal = new VehicleHal(vehicle);
mVehicleInterfaceName = vehicleInterfaceName;
mSystemActivityMonitoringService = new SystemActivityMonitoringService(serviceContext);
mCarPowerManagementService = new CarPowerManagementService(mContext, mHal.getPowerHal(), systemInterface);
mCarPropertyService = new CarPropertyService(serviceContext, mHal.getPropertyHal());
mCarDrivingStateService = new CarDrivingStateService(serviceContext, mCarPropertyService);
mCarUXRestrictionsService = new CarUxRestrictionsManagerService(serviceContext,
mCarDrivingStateService, mCarPropertyService);
mCarPackageManagerService = new CarPackageManagerService(serviceContext,
mCarUXRestrictionsService, mSystemActivityMonitoringService);
mCarInputService = new CarInputService(serviceContext, mHal.getInputHal());
mCarProjectionService = new CarProjectionService(serviceContext, mCarInputService);
mGarageModeService = new GarageModeService(mContext, mCarPowerManagementService);
mAppFocusService = new AppFocusService(serviceContext, mSystemActivityMonitoringSe
rvice);
mCarAudioService = new CarAudioService(serviceContext, mCarPropertyService);
mCarNightService = new CarNightService(serviceContext, mCarPropertyService);
mInstrumentClusterService = new InstrumentClusterService(serviceContext, mAppFocusService, mCarInputService);
mSystemStateControllerService = new SystemStateControllerService(serviceContext,
mCarPowerManagementService, mCarAudioService, this);
mPerUserCarServiceHelper = new PerUserCarServiceHelper(serviceContext);
mCarBluetoothService = new CarBluetoothService(serviceContext, mCarPropertyService,
mPerUserCarServiceHelper, mCarUXRestrictionsService);
mVmsSubscriberService = new VmsSubscriberService(serviceContext, mHal.getVmsHal());
mVmsPublisherService = new VmsPublisherService(serviceContext, mHal.getVmsHal());
mCarDiagnosticService = new CarDiagnosticService(serviceContext, mHal.getDiagnosticHal());
mCarStorageMonitoringService = new CarStorageMonitoringService(serviceContext, systemInterface);
mCarConfigurationService = new CarConfigurationService(serviceContext, new JsonReaderImpl());
mUserManagerHelper = new CarUserManagerHelper(serviceContext);
mCarLocationService = new CarLocationService(mContext, mCarPowerManagementService,
mCarPropertyService, mUserManagerHelper);
addTboxService();
addUpgradeService();
// Be careful with order. Service depending on other service should be inited later.
List allServices = new ArrayList<>();
allServices.add(mSystemActivityMonitoringService);
allServices.add(mCarPowerManagementService);
allServices.add(mCarPropertyService); // ★ CarPropertyService
allServices.add(mCarDrivingStateService);
allServices.add(mCarUXRestrictionsService);
allServices.add(mCarPackageManagerService);
allServices.add(mCarInputService);
allServices.add(mGarageModeService);
allServices.add(mAppFocusService);
allServices.add(mCarAudioService);
allServices.add(mCarNightService);
allServices.add(mInstrumentClusterService);
allServices.add(mCarProjectionService);
allServices.add(mSystemStateControllerService);
allServices.add(mCarBluetoothService);
allServices.add(mCarDiagnosticService);
allServices.add(mPerUserCarServiceHelper);
allServices.add(mCarStorageMonitoringService);
allServices.add(mCarConfigurationService);
allServices.add(mVmsSubscriberService);
allServices.add(mVmsPublisherService);
if (mUserManagerHelper.isHeadlessSystemUser()) {
mCarUserService = new CarUserService(serviceContext, mUserManagerHelper);
allServices.add(mCarUserService);
}
allServices.add(mCarLocationService);
mAllServices = allServices.toArray(new CarServiceBase[allServices.size()]);
}
@MainThread
void init() {
traceBegin(“VehicleHal.init”);
mHal.init();
traceEnd();
traceBegin(“CarService.initAllServices”);
for (CarServiceBase service : mAllServices) {
service.init();
}
traceEnd();
}
@Override
public IBinder getCarService(String serviceName) {
switch (serviceName) {
case Car.AUDIO_SERVICE: return mCarAudioService;
case Car.APP_FOCUS_SERVICE: return mAppFocusService;
case Car.PACKAGE_SERVICE: return mCarPackageManagerService;
case Car.DIAGNOSTIC_SERVICE:
assertAnyDiagnosticPermission(mContext);
return mCarDiagnosticService;
case Car.POWER_SERVICE:
assertPowerPermission(mContext);
return mCarPowerManagementService;
case Car.CABIN_SERVICE:
case Car.HVAC_SERVICE:
case Car.INFO_SERVICE:
case Car.PROPERTY_SERVICE:
case Car.SENSOR_SERVICE:
case Car.VENDOR_EXTENSION_SERVICE:
case Car.DYHVAC_SERVICE:
case Car.CAR_MCU_SERVICE:
case Car.DYCABIN_SERVICE:
case Car.DYSENSOR_SERVICE:
return mCarPropertyService; // ★ CarPropertyService
… …
最后
小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人
都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
资料⬅专栏获取
.DIAGNOSTIC_SERVICE:
assertAnyDiagnosticPermission(mContext);
return mCarDiagnosticService;
case Car.POWER_SERVICE:
assertPowerPermission(mContext);
return mCarPowerManagementService;
case Car.CABIN_SERVICE:
case Car.HVAC_SERVICE:
case Car.INFO_SERVICE:
case Car.PROPERTY_SERVICE:
case Car.SENSOR_SERVICE:
case Car.VENDOR_EXTENSION_SERVICE:
case Car.DYHVAC_SERVICE:
case Car.CAR_MCU_SERVICE:
case Car.DYCABIN_SERVICE:
case Car.DYSENSOR_SERVICE:
return mCarPropertyService; // ★ CarPropertyService
… …
最后
小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
[外链图片转存中…(img-EeRMYs6x-1719073309076)]一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人
都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
资料⬅专栏获取