当前位置:   article > 正文

Android汽车服务篇(一) CarService_android carservice

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需要始终在后台运行, 并在在系统启动的早期进行创建.  时序图:

        

细节代码如下:

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

  1. if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
  2. traceBeginAndSlog("StartCarServiceHelperService");
  3. mSystemServiceManager.startService(CAR_SERVICE_HELPER_SERVICE_CLASS);
  4. traceEnd();
  5. }

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

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

  1. public SystemService startService(String className) {
  2. final Class<SystemService> serviceClass;
  3. try {
  4. serviceClass = (Class<SystemService>)Class.forName(className);
  5. } catch (ClassNotFoundException ex) {
  6. Slog.i(TAG, "Starting " + className);
  7. throw new RuntimeException("Failed to create service " + className
  8. + ": service class not found, usually indicates that the caller should "
  9. + "have called PackageManager.hasSystemFeature() to check whether the "
  10. + "feature is available on this device before trying to start the "
  11. + "services that implement it", ex);
  12. }
  13. return startService(serviceClass);
  14. }
  15. public <T extends SystemService> T startService(Class<T> serviceClass) {
  16. final String name = serviceClass.getName();
  17. ....
  18. try { //注释1
  19. Constructor<T> constructor = serviceClass.getConstructor(Context.class);
  20. service = constructor.newInstance(mContext);
  21. ....
  22. startService(service);
  23. return service;
  24. ...
  25. }
  26. public void startService(@NonNull final SystemService service) {
  27. // Register it.
  28. mServices.add(service);
  29. // Start it.
  30. long time = SystemClock.elapsedRealtime();
  31. try {
  32. //注释2 启动CarService
  33. service.onStart();
  34. .....
  35. }

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

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

注释二处   在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

  1. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
  3. package="com.android.car"
  4. coreApp="true"
  5. android:sharedUserId="android.uid.system">
  6. <service android:name=".CarService"
  7. android:singleUser="true">
  8. <intent-filter>
  9. <action android:name="android.car.ICar" />
  10. </intent-filter>
  11. </service>

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

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

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

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

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

                                                                  AAOS 架构图

四. CarService源码分析

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

  1. @Override
  2. public void onCreate() {
  3. Log.i(CarLog.TAG_SERVICE, "Service onCreate");
  4. //获取通知管理NotificationManager对象
  5. mCanBusErrorNotifier = new CanBusErrorNotifier(this /* context */);
  6. mVehicle = getVehicle();
  7. if (mVehicle == null) {
  8. throw new IllegalStateException("Vehicle HAL service is not available.");
  9. }
  10. try {
  11. mVehicleInterfaceName = mVehicle.interfaceDescriptor();
  12. } catch (RemoteException e) {
  13. throw new IllegalStateException("Unable to get Vehicle HAL interface descriptor", e);
  14. }
  15. Log.i(CarLog.TAG_SERVICE, "Connected to " + mVehicleInterfaceName);
  16. mICarImpl = new ICarImpl(this,
  17. mVehicle,
  18. SystemInterface.Builder.defaultSystemInterface(this).build(),
  19. mCanBusErrorNotifier,
  20. mVehicleInterfaceName);
  21. mICarImpl.init();
  22. linkToDeath(mVehicle, mVehicleDeathRecipient);
  23. ServiceManager.addService("car_service", mICarImpl);
  24. //设置SystemProperty属性 carService已创建
  25. SystemProperties.set("boot.car_service_created", "1");
  26. super.onCreate();
  27. }

主要做了两件事情:

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

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

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

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

  1. public ICarImpl(Context serviceContext, IVehicle vehicle, SystemInterface systemInterface,
  2. CanBusErrorNotifier errorNotifier, String vehicleInterfaceName) {
  3. mContext = serviceContext;
  4. mSystemInterface = systemInterface;
  5. mHal = new VehicleHal(vehicle);
  6. mVehicleInterfaceName = vehicleInterfaceName;
  7. //创建各种重要的服务
  8. mUserManagerHelper = new CarUserManagerHelper(serviceContext);
  9. final Resources res = mContext.getResources();
  10. final int maxRunningUsers = res.getInteger(
  11. com.android.internal.R.integer.config_multiuserMaxRunningUsers);
  12. mCarUserService = new CarUserService(serviceContext, mUserManagerHelper,
  13. ActivityManager.getService(), maxRunningUsers);
  14. mSystemActivityMonitoringService = new SystemActivityMonitoringService(serviceContext);
  15. mCarPowerManagementService = new CarPowerManagementService(mContext, mHal.getPowerHal(),
  16. systemInterface, mUserManagerHelper);
  17. mCarPropertyService = new CarPropertyService(serviceContext, mHal.getPropertyHal());
  18. ....
  19. //将重要的服务缓存到 CarLocalServices
  20. CarLocalServices.addService(CarPowerManagementService.class, mCarPowerManagementService);
  21. CarLocalServices.addService(CarUserService.class, mCarUserService);
  22. CarLocalServices.addService(CarTrustedDeviceService.class, mCarTrustedDeviceService);
  23. // 将创建的服务对象依次添加到一个list中保存起来
  24. List<CarServiceBase> allServices = new ArrayList<>();
  25. allServices.add(mFeatureController);
  26. allServices.add(mCarUserService);
  27. .....
  28. }

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

五. 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对象

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

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

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

  1. private final ServiceConnection mCarServiceConnection = new ServiceConnection() {
  2. @Override
  3. public void onServiceConnected(ComponentName name, IBinder service) {
  4. try {
  5. CarInfoManager manager = (CarInfoManager) carClient.getCarManager(Car.INFO_SERVICE);
  6. } catch (CarNotConnectedException e) {
  7. Log.e(TAG, "Car not connected in onServiceConnected");
  8. }
  9. }
  10. @Override
  11. public void onServiceDisconnected(ComponentName name) {
  12. }
  13. };

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

carClient.connect();

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

  1. @Deprecated
  2. public void connect() throws IllegalStateException {
  3. synchronized (mLock) {
  4. if (mConnectionState != STATE_DISCONNECTED) {
  5. throw new IllegalStateException("already connected or connecting");
  6. }
  7. mConnectionState = STATE_CONNECTING;
  8. startCarService();
  9. }
  10. }

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

carClient.disconnect();

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

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

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

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

六. 总结

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

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/636418
推荐阅读
相关标签
  

闽ICP备14008679号