Android 车机 Car模式原理

1,035 阅读8分钟

1.简述

车机系统:Android Automotive OS,这是Android操作系统为汽车量身定制的版本‌;基于Android的强大平台和功能集进行开发,利用了现有的安全模型、兼容性程序、开发人员工具和基础架构。它保持了Android的高度可定制性和可移植性,同时完全免费和开源‌。这个系统为汽车特定要求、功能和技术提供了支持,通过在原先的Android系统架构上增加与车相关的模块来实现,这些模块包括Car App(包括OEM和第三方开发的App)、Car API(提供给汽车App特有的接口)、Car Service(系统中与车相关的服务)等‌。

常说的car模式,就是Car api, Car service,Vehicle HAL;源码位置:

  • Car API:packages\services\Car\car-lib
  • Car Service:packages\services\Car\service
  • Vehicle HAL:hardware\interfaces\automotive\vehicle\2.0

备注:本文章内容以android 10 原生代码为基准

下面是Android车机中简易模块图,本文章主要介绍Car API ---Car Service --- Vehicle HAL数据的通讯部分(一般说MCU通讯)

image.png

2 Car API

系统自动编译sdk,编译时引用即可,系统运行时,已经加载了这些类库;每个APP 进程fork时自动拥有了这个执行类库

2.1 Car类

Car sdk入口,主要功能

  • Car服务端连接,提供自动重试机制、连接状态获取与监听、断开连接默认处理机制
  • 获取相关管理类,这个类以CarManagerBase为基类,可感知连接状态,与服务端实现Binder相关联
  • 映射缓存管理类,并根据断连状态进行处理

2.1.1 使用

Car使用一般需要3个流程:

  1. 创建Car对象
  2. 进行连接(连接服务定义如右图)
  3. 连接成功后,获取管理类

Android 10 中,已经不建议调用connect方法进行连接,而是在构造对象实例时自动连接

主要使用方法

//创建实例,并进行监听:
public static Car createCar(Context,Handler, long,CarServiceLifecycleListener)
//服务连接,10已经不推荐使用此方法了
public void connect() throws IllegalStateException
//断开服务
public void disconnect()
//是否连接
public boolean isConnected()
//是否正在连接
public boolean isConnecting()
//获取管理类
public Object getCarManager(String serviceName)

连接服务信息如下:

image.png

2.1.2 类图

image.png

使用基类CarManagerBase对所有的管理类进行了统一规格处理

  • Car服务断开连接通知
  • MCU数据事件处理Handler
  • 异常处理

2.1.3 断开连接

public void onServiceDisconnected(ComponentName name) {
    synchronized (mLock) {
        if (mConnectionState  == STATE_DISCONNECTED) {
            // can happen when client calls disconnect before onServiceDisconnected call.
            return;
        }
        handleCarDisconnectLocked();
    }
    if (mStatusChangeCallback != null) {
        mStatusChangeCallback.onLifecycleChanged(Car.this, false);
    } else if (mServiceConnectionListenerClient != null) {
        mServiceConnectionListenerClient.onServiceDisconnected(name);
    } else {
        // This client does not handle car service restart, so should be terminated.
        finishClient();
    }
}
  • 数据复位
  • 缓存清理
  • 服务封装的管理类销毁
  • 回调,如无回调则默认处理

默认处理规则:若Context上下文为Activity,finish Activity,否则杀死进程

2.2 CarPropertyManager类

Android车机系统中用于设置和获取车辆各个属性状态的重要类。作为CarPropertyService在客户端的代理,通过其提供的API,开发者可以实现对车辆属性的读写操作。这些属性包括但不限于车窗升降、空调控制、油量、续航等‌。在实际开发中,当开发者想要控制这些车辆功能时,就需要与其进行交互。

2.2.1 使用

//实例获取
(CarPropertyManager) mCar. getCarManager(Car.PROPERTY_SERVICE)

//属性获取
public boolean getXXXProperty(int prop, int area), XXXBooleanFloatIntIntArray
// 属性设置
public <E> void setProperty(@NonNull Class<E> clazz, int propId, int areaId, @NonNull E val)
public void setXXXProperty(int prop, int areaId,XXX val), XXXBoolean,Float,Int

//属性监听操作:
public boolean registerCallback(CarPropertyEventCallback callback, int propertyId,float rate)

//属性解除监听
public void unregisterCallback(@NonNull CarPropertyEventCallback callback)
public void unregisterCallback(@NonNull CarPropertyEventCallback callback, int propertyId)

// 属性是否可用
public boolean isPropertyAvailable(int propId, int area)

// 属性读写权限
public String getWritePermission(int propId)
public String getReadPermission(int propId)

// 属性配置信息
public List<CarPropertyConfig> getPropertyList(@NonNull ArraySet<Integer> propertyIds) 
public List<CarPropertyConfig> getPropertyList()

2.2.2 类图

image.png

2.3 VmsSubscriberManager类

作为与车辆管理系统交互的一个重要组件,负责处理订阅相关的请求和事件。它可能通过特定的API与VehicleHAL(硬件抽象层)或其他系统服务进行通信,以实现车辆状态信息的获取和控制。用户也可以自定义发布客户端实现进程间的事件交互。

2.3.1 使用

//实例获取
(VmsSubscriberManager) mCar. getCarManager(Car.VMS_SUBSCRIBER_SERVICE)

//最新信息
public byte[] getPublisherInfo(int publisherId)
// 可订阅消息
public VmsAvailableLayers getAvailableLayers()
// 设置消息订阅回调以及执行线程
public void setVmsSubscriberClientCallback(Executor,VmsSubscriberClientCallback)
//清除订阅信息
public void clearVmsSubscriberClientCallback()
// 订阅所有消息
public void startMonitoring()
// 停止订阅所有消息
public void stopMonitoring()
//订阅特定消息
public void subscribe(@NonNull VmsLayer layer)
public void subscribe(@NonNull VmsLayer layer, int publisherId)
//解除订阅特定消息
public void unsubscribe(@NonNull VmsLayer layer)
public void unsubscribe(@NonNull VmsLayer layer, int publisherId)

2.3.2 类图

image.png

2.3.3 VmsPublisherClientService

发布客户端Service基类,需要实现下面两个方法

  • onVmsPublisherServiceReady:发布准备完成,可以调用publish方法进行发布消息
  • onVmsSubscriptionChange:消息订阅状态变化通知

主要使用方法

//设置提供哪些可被订阅消息
public final void setLayersOffering(@NonNull VmsLayersOffering offering)

//发布消息
public final void publish(@NonNull VmsLayer layer, int publisherId, byte[] payload)

//获取当前订阅状态
public final VmsSubscriptionState getSubscriptions()

3 Car Service

3.1 CarService类

Service类,以bind方式提供ICar实现;并对接Vehicle HAL,获取Ivehicle实现,来完成具体硬件信号交互;

image.png

IVehicle binder获取

private static IVehicle getVehicle() {
    try {
        return android.hardware.automotive.vehicle.V2_0.IVehicle.getService();
    } catch (RemoteException e) {
        Log.e(CarLog.TAG_SERVICE, "Failed to get IVehicle service", e);
    } catch (NoSuchElementException e) {
        Log.e(CarLog.TAG_SERVICE, "IVehicle service not registered yet");
    }
    return null;
}

IVehicle服务死亡代理处理

  1. 若配置允许,则杀死Car Service
  2. 不杀死,则进行一定时间内重新连接获取
  3. 获取失败则崩溃重启,重连成功,则ICarImpl重置Ivehicle对象
@Override
public void serviceDied(long cookie) {
    if (RESTART_CAR_SERVICE_WHEN_VHAL_CRASH) {
        Log.wtf(CarLog.TAG_SERVICE, "***Vehicle HAL died. Car service will restart***");
        Process.killProcess(Process.myPid());
        return;
    }

    Log.wtf(CarLog.TAG_SERVICE, "***Vehicle HAL died.***");

    try {
        mVehicle.unlinkToDeath(this);
    } catch (RemoteException e) {
        Log.e(CarLog.TAG_SERVICE, "Failed to unlinkToDeath", e);  // Log and continue.
    }
    mVehicle = null;

    mVhalCrashTracker.crashDetected();

    Log.i(CarLog.TAG_SERVICE, "Trying to reconnect to Vehicle HAL: " +
            mVehicleInterfaceName);
    mVehicle = getVehicleWithTimeout(WAIT_FOR_VEHICLE_HAL_TIMEOUT_MS);
    if (mVehicle == null) {
        throw new IllegalStateException("Failed to reconnect to Vehicle HAL");
    }

    linkToDeath(mVehicle, this);

    Log.i(CarLog.TAG_SERVICE, "Notifying car service Vehicle HAL reconnected...");
    mICarImpl.vehicleHalReconnected(mVehicle);
}

3.2 ICarImpl

ICar实现,跨进程调用入口,与Car对接,并获取Vehicle HAL层服务句柄;

生命周期依据Service生命周期而定

  • init方法,对应Service onCreate
  • Release方法,对应Service onDestory
  • vehicleHalReconnected方法: Vehicle HAL服务重连成功通知
  • getCarService方法:提供特定功能binder实现

image.png

3.3 VehicleHal

实现了Vehicale HAL回调,其内部对不同的硬件信号按照功能等进行了分类,并进行信号订阅管理与分发

  • 普通属性: PropertyHalService桥接类
  • 电源属性:PowerHalService桥接类
  • 输入事件属性:InputHalService桥接类
  • 订阅发布:VmsHalService桥接类
  • 诊断事件属性:DiagnosticHalService桥接类

HalClient类才是对Vehicle HAL层封装的直接实现类,并增加了属性获取设置的重试机制

3.4 CarPropertyService

CarPropertyService是与Vehicle HAL、Car API交互的经典实现;着重对接的是Car API,PropertyHalService类实现了Vehicle HAL的桥接(包括处理属性管控)

image.png

与Car API桥接处理

  • 属性设置、获取
  • 属性监听、分发
  • 跨进程死亡检测

与Vehical HAL桥接处理

  • 属性设置、获取
  • 属性监听

PropertyHalServiceIds类: 管理着处理属性以及属性读写权限

3.5 VMS发布-订阅

发布订阅框架

  • 发布服务端,在Car Service中, 见2.3.1
  • 订阅服务端,在Car Service中,见2.3.3
  • 发布客服端,仅仅与硬件信号相关的在Car service中
  • 订阅客户端,仅仅与硬件信号相关的在Car service中

image.png

实现主要依赖下面几个类

  • VmsClientManager:订阅客户端死亡检测、根据配置进行发布客户端收集与死亡检测
  • VmsBrokerService:订阅发布信息变化通知与缓存
  • VmsSubscriberService: 订阅服务端,框架订阅入口
  • VmsPublisherService: 发布服务端,对接发布客户端
  • VmsHalService:硬件信号消息的订阅发布客户端封装,(信号属性唯一,为VehicleProperty.VEHICLE_MAP_SERVICE)

自动客户端收集配置,在XML,分下图中两个属性

image.png

4 Vehicle HAL

IVehicle服务是Android Automotive在硬件抽象层的一个核心native服务,用于处理和车辆相关的功能,并为系统提供获取车身信息以及设置相关状态的接口‌。IVehicle服务作为Android Automotive的核心组件,位于硬件抽象层,是连接车辆硬件和系统框架的重要桥梁。它提供了一系列接口,使得上层应用能够方便地获取车辆状态信息,并能够对车辆进行一定的控制操作。

采用HIDL定义,主要定义如右图:

image.png

实现类图:

image.png

  • VehicleService: 进程启动入口
  • VehicleHalManager:IVehicle服务实现
  • VehiclePropertyStore:配置管理、数据缓存
  • SubscriptionManager:订阅信息存储;
  • VehicleEmulator:交换数据读取写入调度与数据桥接;
  • EmulatedVehicleHal:数据事件调度管理;
  • CommConn: 交换数据读写的基类

报文属性配置信息以及默认值,在DefaultConfig.h中

// 每个属性的信息结构
struct ConfigDeclaration {
    VehiclePropConfig config;

    /* This value will be used as an initial value for the property. If this field is specified for
     * property that supports multiple areas then it will be used for all areas unless particular
     * area is overridden in initialAreaValue field. */
    VehiclePropValue::RawValue initialValue;
    /* Use initialAreaValues if it is necessary to specify different values per each area. */
    std::map<int32_t, VehiclePropValue::RawValue> initialAreaValues;
};

// 此属性为定义的变量
const ConfigDeclaration kVehicleProperties[] {
}

5 总结

这里讲解了MCU报文整个通讯流程;在常见Car模式使用中,也是基本只使用这一部分的;作为Car模式中MCU数据开发维护,主要有以下工作

  • Vehicle层,实现CommConn类,完成IPC连接以及读写解析
  • 报文ID配置,Vehicle层,Car service层
  • 报文ID值类型定义,以及是否为APP和Vehicle进行桥接转换

如果在此文章中您有所收获,请给作者一个鼓励,点个赞,谢谢支持

技术变化都很快,但基础技术、理论知识永远都是那些;作者希望在余后的生活中,对常用技术点进行基础知识分享;如果你觉得文章写的不错,请给予关注和点赞;如果文章存在错误,也请多多指教!