Android汽车服务篇(一) CarService

一. 简介

        Android Automotive OS作为车载操作系统, 需要与车辆上其他的子系统互联互通. 

        Android Automotive OS 定义了标准的硬件抽象层HAL(Hardware Abstraction Layer)来规范各个子系统与Framework的调用接口, 并且通过CarService以及相关的Car API对上层应用提供标准编程接口.

        下文中我们把 Android Automotive OS 简称为AAOS 

         AAOS并没有大刀阔斧的改变Android原有的整体架构, 几乎所有的核心服务(AMS, WMS, PKMS)与手机并无区别,采用的是同一套代源码,   所以我们可以将AAOS 理解为Android OS + Android Automotive Services更为贴切.

        传统的手机系统加上相关的汽车服务,构成了现在的AAOS, 而其中CarService就是提供汽车相关功能的最主要的模块.

        本文重点来介绍一下 CarService , 也就是 Android 汽车服务.

二. CarService的组成

        对于应用来说,并不会直接通过以上服务的实例调用相关功能,而是通过对应的Car API完成对服务的调用, 做过Android开发的,肯定都知道安卓的通信模式基于 C/S模式,  有客户端,服务端, ,每个服务有对应的代理对象(比如ActivityManager相对服务AMS,就是客户端 ,  PackageManager相对服务 PKMS, 它就是客户端).

          作为 AAOS的核心进程, 谷歌在CarService中实现了许多与汽车密切相关的服务, 我们大致列举一下子服务,  同理每个汽车服务, 也会有自己对应的客户端, 表格如下(非完整):

 Service端 功能 Client端
AppFocusService 管理同类应用焦点的服务 CarAppFocusManager
CarAudioService 汽车音频服务 CarAudioManager
CarPackageManagerService 汽车包管理服务 CarPackageManager
CarDiagnosticService 汽车诊断服务 CarDiagnosticManager
CarPowerManagerService 汽车电源管理服务 CarPowerManager
IInstrumentClusterNavigaiton 仪表导航服务
IInstrumentClusterManagerServcie 仪表服务 IInstrumentClusterManager
CarProjecitonService 投屏服务 CarProjecitonManager
VmsSubscriberService 车辆地图服务 VmsSubscriberManager
CarBluetoothService 汽车蓝牙服务 CarBluetoothManager
CarStorageMonitoringService 汽车存储监控服务 CarStorageMonitoringManager
CarDrivingStateService 汽车驾驶状态服务 CarDrivingStateManager
CarUXRestrictionsService 汽车用户体验限制服务 CarUXRestrictionsManager
CarConfigurationService 汽车配置服务 CarConfigurationManager
CarTrustedDeviceService 授信设备管理 CarTrustAgentEnrollmentManager
CarMediaService 媒体管理服务 CarMediaManager
CarBugreportManagerService 错误报告服务 CarBugreportManager

[备注]:aosp的版本一直在更新, 服务也是越来越多, 笔者只列举了部分出来. 供参考

从命名上还是比较容易将上述对象与相关的服务对应起来, 比较特殊的是 CarInfoManager, 

CarSensorManager,   CarHvacManager,   CarCabinManager, CarVendor-ExtensionManager以及CarPropertyManager都是对应 CarPropertyService.  这个服务后面文章也会详细介绍的

三. CarService启动流程

        了解CarService的主要组成后, 我们再来看看CarService的启动流程,  看看它在启动过程中做了些什么事情, 作为 AAOS的核心服务, CarService需要始终在后台运行, 并在在系统启动的早期进行创建.  时序图:

        Android汽车服务篇(一) CarService_第1张图片

细节代码如下:

/frameworks/base/services/java/com/android/server/SystemServer.java

 if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
                traceBeginAndSlog("StartCarServiceHelperService");
                mSystemServiceManager.startService(CAR_SERVICE_HELPER_SERVICE_CLASS);
                traceEnd();
            }

然后跳转到SystemServiceManager.java文件中的startService方法

frameworks/base/services/core/java/com/android/server/SystemServiceManager.java

public SystemService startService(String className) {
        final Class serviceClass;
        try {
            serviceClass = (Class)Class.forName(className);
        } catch (ClassNotFoundException ex) {
            Slog.i(TAG, "Starting " + className);
            throw new RuntimeException("Failed to create service " + className
                    + ": service class not found, usually indicates that the caller should "
                    + "have called PackageManager.hasSystemFeature() to check whether the "
                    + "feature is available on this device before trying to start the "
                    + "services that implement it", ex);
        }
        return startService(serviceClass);
    }

 public  T startService(Class serviceClass) {

     final String name = serviceClass.getName();
     ....
      try {     //注释1
                Constructor constructor = serviceClass.getConstructor(Context.class);
                service = constructor.newInstance(mContext);
     ....
     startService(service);
     return service;
...
}

public void startService(@NonNull final SystemService service) {
        // Register it.
        mServices.add(service);
        // Start it.
        long time = SystemClock.elapsedRealtime();
        try {
            //注释2 启动CarService
            service.onStart();
.....
}

注释1处,  通过SystemServiceManager封装的方法来创建服务, 此处SystemServiceManager通过反射创建了CarServiceHelperService对象, 并调用其onStart方法, 进入到CarServiceHelperService.java文件中

public void onStart() {
        Intent intent = new Intent();
        intent.setPackage("com.android.car");
        intent.setAction(CAR_SERVICE_INTERFACE);
        if (!getContext().bindServiceAsUser(intent, mCarServiceConnection, Context.BIND_AUTO_CREATE,
                UserHandle.SYSTEM)) {
            Slog.wtf(TAG, "cannot start car service");
        }
        System.loadLibrary("car-framework-service-jni");
    }

注释二处   在onStart方法中, 创建了一个Intent    设置包名 和 Action  并调用bindServiceAsUser创建和绑定关联CarService,  同时加载了相关的JNI库(car-framework-service-jni).

通过以上的源码片段, 我们知道Intent的目标包名为"com.android.car", action为"android.car.ICar",  源码全局搜索与之相匹配的Service   

packages/services/Car/service/src/com/android/car/CarService.java





 
            
                
            
        

 通过上述流程, CarService在系统启动的早期就会随其他服务一同启动, 它的启动时机与 LocationManagerService/NotificationManagerService/WallpaperManagerService是一致的. 

从这点来说,CarService具有和其他系统主要服务有同等的地位, 不同的是 CarService是在独立的进程中运行, 而其他的服务运行在 SystemServer进程.

另一方面,从CarService的清单文件中可以看出, CarService使用的 system UID运行, 这也保证CarService拥有系统服务所具有的特性和权限.

除此之外, AAOS汽车服务的主要功能实现都集中在CarService中, 与Android原有的 Framework在源码上的耦合比较小, 在源码管理上, CarService的源码以单独的仓库进行管理.

下面来通过一个简单的架构示意图说明CarService与Android原有的系统服务之间的关系:CarService运行在独立的进程中. 其作为原有Android服务的补充,在汽车设备上运行

Android汽车服务篇(一) CarService_第2张图片

                                                                  AAOS 架构图

四. CarService源码分析

        当服务启动之后, 首先调用其onCreate方法.  CarService的onCreate方法实现如下:

 @Override
    public void onCreate() {
        Log.i(CarLog.TAG_SERVICE, "Service onCreate");
        //获取通知管理NotificationManager对象
        mCanBusErrorNotifier = new CanBusErrorNotifier(this /* context */);
        mVehicle = getVehicle();

        if (mVehicle == null) {
            throw new IllegalStateException("Vehicle HAL service is not available.");
        }
        try {
            mVehicleInterfaceName = mVehicle.interfaceDescriptor();
        } catch (RemoteException e) {
            throw new IllegalStateException("Unable to get Vehicle HAL interface descriptor", e);
        }

        Log.i(CarLog.TAG_SERVICE, "Connected to " + mVehicleInterfaceName);

        mICarImpl = new ICarImpl(this,
                mVehicle,
                SystemInterface.Builder.defaultSystemInterface(this).build(),
                mCanBusErrorNotifier,
                mVehicleInterfaceName);
        mICarImpl.init();

        linkToDeath(mVehicle, mVehicleDeathRecipient);

        ServiceManager.addService("car_service", mICarImpl);
        //设置SystemProperty属性  carService已创建
        SystemProperties.set("boot.car_service_created", "1");
        super.onCreate();
    }

主要做了两件事情:

1.  获取mVehicle 车辆相关的HIDL Binder远程对象;

2. 创建了mICarImpl对象, 并将其添加到ServiceManager管理的服务列表中.

这里的 ICarImpl起着创建并管理各个服务的作用. 在它的构造函数中,创建了各个服务的实例,并添加到服务列表中,源码如下:

packages/services/Car/service/src/com/android/car/ICarImpl.java

public ICarImpl(Context serviceContext, IVehicle vehicle, SystemInterface systemInterface,
            CanBusErrorNotifier errorNotifier, String vehicleInterfaceName) {
        mContext = serviceContext;
        mSystemInterface = systemInterface;
        mHal = new VehicleHal(vehicle);
        mVehicleInterfaceName = vehicleInterfaceName;
        //创建各种重要的服务
        mUserManagerHelper = new CarUserManagerHelper(serviceContext);
        final Resources res = mContext.getResources();
        final int maxRunningUsers = res.getInteger(
                com.android.internal.R.integer.config_multiuserMaxRunningUsers);
        mCarUserService = new CarUserService(serviceContext, mUserManagerHelper,
                ActivityManager.getService(), maxRunningUsers);
        mSystemActivityMonitoringService = new SystemActivityMonitoringService(serviceContext);
        mCarPowerManagementService = new CarPowerManagementService(mContext, mHal.getPowerHal(),
                systemInterface, mUserManagerHelper);
        mCarPropertyService = new CarPropertyService(serviceContext, mHal.getPropertyHal());
        ....
        
        //将重要的服务缓存到 CarLocalServices
        CarLocalServices.addService(CarPowerManagementService.class, mCarPowerManagementService);
        CarLocalServices.addService(CarUserService.class, mCarUserService);
        CarLocalServices.addService(CarTrustedDeviceService.class, mCarTrustedDeviceService);


         // 将创建的服务对象依次添加到一个list中保存起来
         List allServices = new ArrayList<>();
         allServices.add(mFeatureController);
         allServices.add(mCarUserService);

.....
}

这些创建的服务就是上文介绍的汽车服务. 

五. Car API 使用方式

        在上面的介绍中,我们提到CarService中各个服务本质上是AIDL接口的实现类,属于Server端,而对应的Client端就需要一个IBinder对象来访问Server端的方法,这些IBinder对象在Car API中被封装在一个个XXXManager类中。

 5.1  编译 Car API

        在使用Car API之前,我们需要先将Car API编译成jar也就是CarLib,这样才能让其它的系统应用使用, 命令如下:

make android.car android.car-system-stubs android.car-stubs

编译成功后的 android.car.jar  的输出路径为:

/out/soong/.intermediates/packages/services/Car/car-lib/android.car/android_common/javac/android.car.jar

5.2  使用 Car API

Car API 的使用并不复杂,大致有以下几个步骤

1. 首先,通过Car.createCar 创建 Car对象

if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
    Car carClient = Car.createCar(context, mCarServiceConnection);
}

通过getPackageManager().hasSystemFeature(String string)判断系统是否支持特定的模块功能

其中需要传入ServiceConnection对象, 在CarService成功连接后,收到相应的回调, 如果ServiceConnection的onServiceConnected被回调,则说明连接成功了, 便可以获取相应的服务了.

private final ServiceConnection mCarServiceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
            try {
                CarInfoManager manager = (CarInfoManager) carClient.getCarManager(Car.INFO_SERVICE);
            } catch (CarNotConnectedException e) {
                Log.e(TAG, "Car not connected in onServiceConnected");
            }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
    }
};

2.  构建出Car对象后还需要调用connect()才会连接到CarService上.

carClient.connect();

[注意事项]connect()只能调用一次,如果当前已经处于连接状态,再次调用connect()会抛出异常,client如果没有捕获该异常,则会引起client端程序crash.

@Deprecated
public void connect() throws IllegalStateException {
    synchronized (mLock) {
        if (mConnectionState != STATE_DISCONNECTED) {
            throw new IllegalStateException("already connected or connecting");
        }
        mConnectionState = STATE_CONNECTING;
        startCarService();
    }
}

3. 除了需要连接服务,还需要在不使用CarService的时候解绑服务,  通过disconnect方法释放资源:

carClient.disconnect();

上面3个步骤是在(<=Android9)之前的使用方法, 在Android10后, 获取Car对象的方法被大大简化了

应用不必在连接并接受回调后才能使用Car API, 这意味着获取 Car Manager对象的方法可以同步而非异步执行.

android10 以后获取Car对象的方法:

if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
    Car carClient = Car.createCar(context);
    CarHvacManager manager = (CarHvacManager) carClient.getCarManager(Car.HVAC_SERVICE);
}

六. 总结

        本文主要说明了CarService这一系统服务的启动流程,以及一些关键成员的创建和初始化流程.

        同时简单介绍了一下客户端是如何获取和使用CarService对象, 如上文介绍的, CarService对象只是获取各个Manager的媒介,它本身并不承担管理传感器.空调等具体的任务.

        如果要获取车辆的相关信息,如车速, 车内空调温度,诊断信息, 或对车辆进行相关的控制,如升高和降低空调温度,控制座椅和车窗, 调节音量等,就要通过具体的Manager中的API和对应的服务来实现了.

你可能感兴趣的:(Android,Automotive,车载开发,汽车服务CarService)