Android Automotive架构与流程:VehicleHAL,CarService(1)

  • 调用流程

    • APP端
  • CarAPI (car-lib:android.car.jar)

  • CarService

  • Vehicle

  • EVS

Vehicle

Vehicle HAL架构

在这里插入图片描述

代码位置:

  • 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) { }

};

  1. 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) { }

};

  1. 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;

}

  1. 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;

}

  1. 具体的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
  1. 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;

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

总结

【Android 详细知识点思维脑图(技能树)】

我个人是做Android开发,已经有十来年了,目前在某创业公司任职CTO兼系统架构师。虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。

这里附上上述的面试题相关的几十套字节跳动,京东,小米,腾讯、头条、阿里、美团等公司19年的面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。

由于篇幅有限,这里以图片的形式给大家展示一小部分。

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

最后,赠与大家一句话,共勉!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-DQsJjFma-1711899557894)]

总结

【Android 详细知识点思维脑图(技能树)】

[外链图片转存中…(img-V73D5C7v-1711899557894)]

我个人是做Android开发,已经有十来年了,目前在某创业公司任职CTO兼系统架构师。虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。

这里附上上述的面试题相关的几十套字节跳动,京东,小米,腾讯、头条、阿里、美团等公司19年的面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。

由于篇幅有限,这里以图片的形式给大家展示一小部分。

[外链图片转存中…(img-Ln7YRFgY-1711899557895)]

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

最后,赠与大家一句话,共勉!

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

  • 10
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值