ToB企服应用市场:ToB评测及商务社交产业平台

标题: Android 车载应用开发指南(4)- CarService 详解 [打印本页]

作者: 用户国营    时间: 2024-6-15 02:26
标题: Android 车载应用开发指南(4)- CarService 详解
Android 车载应用开发指南系列文章

Android 车载应用开发指南(1)- 车载操作体系全解析
Android 车载应用开发指南(2)- 应用开发入门
Android 车载应用开发指南(3)- SystemUI 详解
Android 车载应用开发指南(4)- CarService 详解
Android 车载应用开发指南(5)- CAN Bus 协议详解
Android 车载应用开发指南(6)- 汽车混动技术简介
一 概述

CarService 是车载 Android 操作体系 Android Automotive OS(下文简介 AAOS)的焦点服务之一,所有车载相干的应用都需要通过 CarService 来查询、控制整车的状态,不但仅是车辆控制,实际上 CarService 险些就是整个车载 Framework 最焦点的组件。

二 CarService 架构

2.1 简介

AAOS 并没有大刀阔斧的改变 Android 原有的整体架构,险些所有的焦点服务 (AMS、WMS、PMS) 与手机并无区别,采用的是同一套源代码,以是我们可以将 AAOS 理解为 Android OS + Automotive Services + Automotive APPs
传统的手机体系加上相干的汽车服务,构成了现在的 AAOS,而此中 CarService 就是提供汽车相干功能的最主要的模块。
AAOS 界说了尺度的硬件抽象层 HAL(Hardware Abstraction Layer) 来规范各个子体系与 Framework 的调用接口,并且通过 CarService 以及相干的 Car API 对上层应用提供尺度编程接口。

车载 HAL 与 AAOS 架构:

2.2 CarService 构成

   CarService 源码位置:/packages/services/Car
  其目录结构如下所示:
  1. .
  2. ├── Android.mk
  3. ├── apicheck.mk
  4. ├── apicheck_msg_current.txt
  5. ├── apicheck_msg_last.txt
  6. ├── car-cluster-logging-renderer    //LoggingClusterRenderingService 继承 InstrumentClusterRenderingService
  7. ├── car-default-input-service   //按键消息处理
  8. ├── car-lib         //提供给汽车 App 特有的接口,许多定制的模块都在这里实现,包括 Sensor,HVAC,Cabin,ActiveParkingAssiance,Diagnostic,Vendor 等
  9. ├── car-maps-placeholder    //地图软件相关
  10. ├── car_product         //系统编译相关
  11. ├── car-support-lib     //android.support.car
  12. ├── car-systemtest-lib  //系统测试相关
  13. ├── car-usb-handler     //开机自启,用于管理车机 USB
  14. ├── CleanSpec.mk
  15. ├── evs  
  16. ├── obd2-lib
  17. ├── PREUPLOAD.cfg
  18. ├── procfs-inspector
  19. ├── service    //com.android.car 是一个后台运行的组件,可以长时间运行并且不需要和用户去交互的,这里即使应用被销毁,它也可以正常工作
  20. ├── tests
  21. ├── tools   //是一系列的工具,要提到的是里面的 emulator,测试需要用到的。python 写的,通过 adb 可以连接 vehicleHal 的工具,用于模拟测试
  22. ├── TrustAgent
  23. └── vehicle-hal-support-lib
复制代码
Android 通信模式通常基于 C/S 模式,即有客户端和服务端,每个服务有对应的代理对象(比如 ActivityManager 相对服务 AMS,就是客户端)。
对于 CarService 也是采用了 C/S 模式Car App 并不会直接通过 CarService 的实例调用相干功能,而是通过对应的 Car API 完成对服务的调用。这里的 CarService 就是服务端,Car API 就是客户端。
Android 原生 CarService 包含了许多功能服务: Car ** Service(C/S 模式中的服务端)它们与 HAL 层的 VehicleHAL 通信,进而通过车载总线(例如 CAN 总线)与车身进行通讯,同时它们还通过 Car API:Car ** Manger(C/S 模式中的客户端)为应用层的 Car App 提供接口,从而让 App 可以或许实现对车身的控制与状态的显示。

   Car***Manager:packages/services/Car/car-lib/src/android/car/
    Car***Service:packages/services/Car/service/src/com/android/car/
  以下列举 CarService 中焦点服务:
Service 端功能Client 端AppFocusService管理同类应用焦点的服务CarAppFocusManagerCarAudioService汽车音频服务CarAudioManagerCarPackageManagerService汽车包管理服务CarPackageManagerCarDiagnosticService汽车诊断服务CarDiagnosticManagerCarPowerManagerService汽车电源管理服务CarPowerManagerIInstrumentClusterManagerServcie仪表服务IInstrumentClusterManagerCarProjecitonService投屏服务CarProjecitonManagerVmsSubscriberService车辆地图服务VmsSubscriberManagerCarBluetoothService汽车蓝牙服务CarBluetoothManagerCarStorageMonitoringService汽车存储监控服务CarStorageMonitoringManagerCarDrivingStateService汽车驾驶状态服务CarDrivingStateManagerCarUXRestrictionsService汽车用户体验限定服务CarUXRestrictionsManagerCarConfigurationService汽车配置服务CarConfigurationManagerCarTrustedDeviceService授信设备管理CarTrustAgentEnrollmentManagerCarMediaService媒体管理服务CarMediaManagerCarBugreportManagerService错误陈诉服务CarBugreportManager 2.3 使用 CarService

   阐明:本文源码分析基于版本:android-12.0.0_r3
  前文提到,CarService 需要通过 Car API 为应用层提供接口,以是应用开发者只需要知道怎样使用 Car API
第一步:判断平台是否支持车载功能
APP 层在调用 Car API 之前首先会调用 PMS 中的 hasSystemFeature() 方法判断设备是否支持车载功能
  1. if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
  2.      .....
  3. }
复制代码
  源码路径:frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
  1.      @GuardedBy("mAvailableFeatures")
  2.      final ArrayMap<String, FeatureInfo> mAvailableFeatures;
  3.      @Override
  4.      public boolean hasSystemFeature(String name, int version) {
  5.          // allow instant applications
  6.          synchronized (mAvailableFeatures) {
  7.              final FeatureInfo feat = mAvailableFeatures.get(name);
  8.              if (feat == null) {
  9.                  return false;
  10.              } else {
  11.                  return feat.version >= version;
  12.              }
  13.          }
  14.      }
复制代码
mAvailableFeatures 内里的内容是通过读取/system/etc/permissions下面的 xml 文件(对应 SDK 的位置—frameworks/native/data/etc 下的 XML 文件中的 feature 字段)
   源码路径:frameworks/native/data/etc/car_core_hardware.xml
  1. <permissions>
  2.      <!-- Feature to specify if the device is a car -->
  3.      <feature name="android.hardware.type.automotive" />
  4.      .....
  5. </permission>
复制代码
  源码路径:frameworks/native/data/etc/android.hardware.type.automotive.xml
  1. <!-- These features determine that the device running android is a car. -->
  2. <permissions>
  3.      <feature name="android.hardware.type.automotive" />
  4. </permissions>
复制代码
第二步:创建 Car 对象,获取 Manager
   Car 作为汽车平台最高品级的 API(packages/services/Car/car-lib/src/android/car/Car.java),为外界提供汽车所有服务和数据的访问
  
  1.      // 创建 Car 实例
  2.      Car carApiClient = Car.createCar(context);
  3.      // 获取 CarHvacManager
  4.      CarHvacManager manager = (CarHvacManager) mCarApiClient.getCarManager(Car.HVAC_SERVICE);
复制代码
  1.      // 调用 disconnect() 断开连接
  2.       carApiClient.disconnect();
复制代码

三 CarService 实现原理

想要弄清晰CarService实现方式,首先需要搞明白CarService的启动流程。
CarService 启动流程主要分为以下四个步骤:
3.1 启动 CarServiceHelperService 服务

SystemServer会在startOtherServices()方法中让SystemServiceManager先通过反射的形式创建出StartCarServiceHelperService对象。
   源码路径:frameworks/base/services/java/com/android/server/SystemServer.java
  1. private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
  2.      ...
  3.      // 仅在 automotive 中启动
  4.      if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
  5.          t.traceBegin("StartCarServiceHelperService");
  6.          final SystemService cshs = mSystemServiceManager
  7.              .startService(CAR_SERVICE_HELPER_SERVICE_CLASS);
  8.          if (cshs instanceof Dumpable) {
  9.              mDumper.addDumpable((Dumpable) cshs);
  10.          }
  11.          if (cshs instanceof DevicePolicySafetyChecker) {
  12.              dpms.setDevicePolicySafetyChecker((DevicePolicySafetyChecker) cshs);
  13.          }
  14.          t.traceEnd();
  15.      }
  16.      ...
  17. }
复制代码
然后在SystemServiceManager中调用StartCarServiceHelperService的onStart()方法。
CarServiceHelperService是CarService的 SystemService 端的配套服务。
   源码路径: frameworks/base/services/core/java/com/android/server/SystemServiceManager.java
  1. public SystemService startService(String className) {
  2.      final Class<SystemService> serviceClass = loadClassFromLoader(className,
  3.              this.getClass().getClassLoader());
  4.      return startService(serviceClass);
  5. }
  6. public void startService(@NonNull final SystemService service) {
  7.      // Register it.
  8. mServices.add(service);
  9.      long time = SystemClock.elapsedRealtime();
  10.      try {
  11.          service.onStart();
  12.      } catch (RuntimeException ex) {
  13.          throw new RuntimeException("Failed to start service " + service.getClass().getName()
  14.                  + ": onStart threw an exception", ex);
  15.      }
  16.      warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
  17. }
复制代码
3.2 绑定 CarService 服务

   源码路径: frameworks/opt/car/services/src/com/android/internal/car/CarServiceHelperService.java
  1.      private static final String CAR_SERVICE_INTERFACE = "android.car.ICar";
  2.      @Override
  3.      public void onStart() {
  4.          EventLog.writeEvent(EventLogTags.CAR_HELPER_START);
  5.          IntentFilter filter = new IntentFilter(Intent.ACTION_REBOOT);
  6.          filter.addAction(Intent.ACTION_SHUTDOWN);
  7.          mContext.registerReceiverForAllUsers(mShutdownEventReceiver, filter, null, null);
  8.          mCarWatchdogDaemonHelper.addOnConnectionChangeListener(mConnectionListener);
  9.          mCarWatchdogDaemonHelper.connect();
  10.          Intent intent = new Intent();
  11.          intent.setPackage("com.android.car");  // 绑定包名,设置广播仅对该包有效
  12.          intent.setAction(CAR_SERVICE_INTERFACE);  // 绑定 action,表明想要启动能够响应设置的这个 action 的活动,并在清单文件 AndroidManifest.xml 中设置 action 属性
  13.          // 绑定后回调
  14.          if (!mContext.bindServiceAsUser(intent, mCarServiceConnection, Context.BIND_AUTO_CREATE,
  15.                  mHandler, UserHandle.SYSTEM)) {
  16.              Slogf.wtf(TAG, "cannot start car service");
  17.          }
  18.          loadNativeLibrary();
  19.      }
复制代码
  源码路径:packages/services/Car/service/AndroidManifest.xml
  sharedUserId 是体系级别的,类似 SystemUI,它编译出来同样是一个 APK 文件
   设备文件路径: /system/priv-app/CarService/CarService.apk
  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.      ......
  7.      <application android:label="@string/app_title"
  8.           android:directBootAware="true"
  9.           android:allowBackup="false"
  10.           android:persistent="true">
  11.          <service android:name=".CarService"
  12.               android:singleUser="true"
  13.               android:exported="true">
  14.              <intent-filter>
  15.                  <action android:name="android.car.ICar"/>
  16.              </intent-filter>
  17.          </service>
  18.          ......
  19.      </application>
复制代码
3.3 CarService 初始化

CarService进入启动时序后,会在onCreate()方法中进行一系列自身的初始化操作,步骤如下:
1)通过 HIDL 接口获取到 HAL 层的 IHwBinder 对象IVehicle,与 AIDL 的用法类似,必须持有 IHwBinder 对象我们才可以与 Vehicle HAL 层进行通信。
2)创建 ICarImpl 对象,并调用init方法,它就是ICar.aidl接口的实现类,我们需要通过它才能拿到其他的 Service 的 IBinder 对象。
3)将ICar.aidl的实现类添加到 ServiceManager 中。
4)设定 SystemProperty,将CarService设定为创建完成状态,只有包含CarService在内的所有的焦点 Service 都完成初始化,才能结束开机动画并发送开机广播。
   源码路径:packages/services/Car/service/src/com/android/car/CarService.java
  1.      @Override
  2.      public void onCreate() {
  3.          LimitedTimingsTraceLog initTiming = new LimitedTimingsTraceLog(CAR_SERVICE_INIT_TIMING_TAG,
  4.                  Trace.TRACE_TAG_SYSTEM_SERVER, CAR_SERVICE_INIT_TIMING_MIN_DURATION_MS);
  5.          initTiming.traceBegin("CarService.onCreate");
  6.          initTiming.traceBegin("getVehicle");
  7.          // 获取 hal 层的 Vehicle service
  8.          mVehicle = getVehicle();
  9.          initTiming.traceEnd();
  10.          ...
  11.          //创建 ICarImpl 实例
  12.          mICarImpl = new ICarImpl(this,
  13.                  mVehicle,
  14.                  SystemInterface.Builder.defaultSystemInterface(this).build(),
  15.                  mVehicleInterfaceName);
  16.          //然后调用 ICarImpl 的 init 初始化方法
  17.          mICarImpl.init();
  18.          linkToDeath(mVehicle, mVehicleDeathRecipient);
  19.          //将该 service 注册到 ServiceManager
  20.          ServiceManager.addService("car_service", mICarImpl);
  21.          //设置 boot.car_service_created 属性
  22.          SystemProperties.set("boot.car_service_created", "1");
  23.          super.onCreate();
  24.          initTiming.traceEnd(); // "CarService.onCreate"
  25.      }
  26.      @Nullable
  27.      private static IVehicle getVehicle() {
  28.          final String instanceName = SystemProperties.get("ro.vehicle.hal", "default");
  29.          try {
  30.              //该 service 启动文件 hardware/interfaces/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc
  31.              return android.hardware.automotive.vehicle.V2_0.IVehicle.getService(instanceName);
  32.          } catch (RemoteException e) {
  33.              Slog.e(CarLog.TAG_SERVICE, "Failed to get IVehicle/" + instanceName + " service", e);
  34.          } catch (NoSuchElementException e) {
  35.              Slog.e(CarLog.TAG_SERVICE, "IVehicle/" + instanceName + " service not registered yet");
  36.          }
  37.          return null;
  38.      }
复制代码
接着再看ICarImpl的实现,如下所示:
1)创建各个焦点服务对象
2)把服务对象缓存到 CarLocalServices 中,这里主要是为了方便 Service 之间的相互访问
   源码路径:/packages/services/Car/service/src/com/android/car/ICarImpl.java
  1.      @VisibleForTesting
  2.      ICarImpl(Context serviceContext, IVehicle vehicle, SystemInterface systemInterface,
  3.              String vehicleInterfaceName,
  4.              @Nullable CarUserService carUserService,
  5.              @Nullable CarWatchdogService carWatchdogService,
  6.              @Nullable ICarPowerPolicySystemNotification powerPolicyDaemon) {
  7.          ...
  8.          mContext = serviceContext;
  9.          mSystemInterface = systemInterface;
  10.          CarLocalServices.addService(SystemInterface.class, mSystemInterface);
  11.          //创建 VehicleHal 对象
  12.          mHal = constructWithTrace(t, VehicleHal.class,
  13.                  () -> new VehicleHal(serviceContext, vehicle));
  14.          ...
  15.          // 创建核心服务对象,并缓存到 CarLocalServices
  16.          mCarPropertyService = constructWithTrace(t, CarPropertyService.class, () -> new CarPropertyService(serviceContext, mHal.getPropertyHal()));
  17.          mCarDrivingStateService = constructWithTrace(t, CarDrivingStateService.class,() -> new CarDrivingStateService(serviceContext, mCarPropertyService));
  18.          mCarUXRestrictionsService = constructWithTrace(t, CarUxRestrictionsManagerService.class, () -> new CarUxRestrictionsManagerService(serviceContext, mCarDrivingStateService, mCarPropertyService));
  19.          ...
  20.          // 将创建的服务对象依次添加到一个 list 中保存起来
  21.          List<CarServiceBase> allServices = new ArrayList<>();
  22.          allServices.add(mFeatureController);
  23.          allServices.add(mCarUXRestrictionsService); // mCarUserService depends on it
  24.          allServices.add(mCarUserService);
  25.          allServices.add(mSystemActivityMonitoringService);
  26.          allServices.add(mCarPowerManagementService);
  27.          allServices.add(mCarPropertyService);
  28.          allServices.add(mCarDrivingStateService);
  29.          allServices.add(mCarOccupantZoneService);
  30.          addServiceIfNonNull(allServices, mOccupantAwarenessService);
  31.          allServices.add(mCarPackageManagerService);
  32.          allServices.add(mCarInputService);
  33.          allServices.add(mGarageModeService);   
  34.          ...
  35.      }
  36.      @MainThread
  37.      void init() {
  38.          LimitedTimingsTraceLog t = new LimitedTimingsTraceLog(CAR_SERVICE_INIT_TIMING_TAG,
  39.                  Trace.TRACE_TAG_SYSTEM_SERVER, CAR_SERVICE_INIT_TIMING_MIN_DURATION_MS);
  40.          t.traceBegin("ICarImpl.init");
  41.          t.traceBegin("VHAL.init");
  42.          mHal.init();
  43.          t.traceEnd();
  44.          t.traceBegin("CarService.initAllServices");
  45.          //启动的所有服务遍历调用 init 初始化(各个都继承了 CarServiceBase)
  46.          for (CarServiceBase service : mAllServices) {
  47.              t.traceBegin(service.getClass().getSimpleName());
  48.              service.init();
  49.              t.traceEnd();
  50.          }
  51.          t.traceEnd(); // "CarService.initAllServices"
  52.          t.traceEnd(); // "ICarImpl.init"
  53.      }
复制代码
然后将上面 onCreate() 创建的 mICarImpl 对象返回:
   源码路径:/packages/services/Car/service/src/com/android/car/CarService.java
  1.      @Override
  2.      public IBinder onBind(Intent intent) {
  3.          return mICarImpl;
  4.      }
复制代码
以是此处的 mICarImpl 会作为 IBinder 返回给CarServiceHelperService.java - bindServiceAsUser方法中的参数 mCarServiceConnection(回调)
3.4 回调 ServiceConnection

   ICarImpl 初始化完毕,会作为 IBinder 返回给CarServiceHelperService.java - bindServiceAsUser方法中绑定此服务的 mCarServiceConnection(回调)
  mCarServiceConnection 初始化如下:
   源码路径:/frameworks/opt/car/services/src/com/android/internal/car/CarServiceHelperService.java
  1. private static final String CAR_SERVICE_INTERFACE = "android.car.ICar";
  2. private IBinder mCarService;
  3. private final ICarServiceHelperImpl mHelper = new ICarServiceHelperImpl();
  4.      private final ServiceConnection mCarServiceConnection = new ServiceConnection() {
  5.          @Override
  6.          public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
  7.              if (DBG) {
  8.                  Slogf.d(TAG, "onServiceConnected: %s", iBinder);
  9.              }
  10.              handleCarServiceConnection(iBinder);
  11.          }
  12.          @Override
  13.          public void onServiceDisconnected(ComponentName componentName) {
  14.              handleCarServiceCrash();
  15.          }
  16.      };
  17.      
  18.      @VisibleForTesting
  19.      void handleCarServiceConnection(IBinder iBinder) {
  20.          synchronized (mLock) {
  21.              if (mCarServiceBinder == iBinder) {
  22.                  return; // already connected.
  23.              }
  24.              Slogf.i(TAG, "car service binder changed, was %s new: %s", mCarServiceBinder, iBinder);
  25.              //1. 返回的 ICarImpl 被保存在了 CarServiceHelperService 的 mCarServiceBinder
  26.              mCarServiceBinder = iBinder;
  27.              Slogf.i(TAG, "**CarService connected**");
  28.          }
  29.          sendSetSystemServerConnectionsCall();
  30.          ...
  31.      }
  32.      private void sendSetSystemServerConnectionsCall() {
  33.          Parcel data = Parcel.obtain();
  34.          data.writeInterfaceToken(CAR_SERVICE_INTERFACE);
  35.          data.writeStrongBinder(mHelper.asBinder());
  36.          //将 ICarServiceHelperImpl 类型的对象作为数据跨进程传递
  37.          data.writeStrongBinder(mCarServiceConnectedCallback.asBinder());
  38.          IBinder binder;
  39.          synchronized (mLock) {
  40.              binder = mCarServiceBinder;
  41.          }
  42.          int code = IBinder.FIRST_CALL_TRANSACTION;
  43.          try {
  44.              //2. 跨进程传输
  45.              //对端是 mCarService 即 ICarImpl,调用 binder 的 transact 进行跨进程通信
  46.              //其 code 代表需要调用的对端方法,data 为携带的传输数据
  47.              //FIRST_CALL_TRANSACTION  = 0x00000001,即调用对端 ICar.aidl 中定义的第一个方法 setCarServiceHelper
  48.              if (VERBOSE) Slogf.v(TAG, "calling one-way binder transaction with code %d", code);
  49.              // oneway void setSystemServerConnections(in IBinder helper, in IBinder receiver) = 0;
  50.              binder.transact(code, data, null, Binder.FLAG_ONEWAY);
  51.              if (VERBOSE) Slogf.v(TAG, "finished one-way binder transaction with code %d", code);
  52.          }
  53.          ...
  54.      }
复制代码
跨历程 setSystemServerConnections
  1.      @Override
  2.      public void setSystemServerConnections(IBinder helper, IBinder receiver) {
  3.          Bundle bundle;
  4.          try {
  5.              EventLog.writeEvent(EventLogTags.CAR_SERVICE_SET_CAR_SERVICE_HELPER,
  6.                      Binder.getCallingPid());
  7.              assertCallingFromSystemProcess();
  8.              //将 ICarServiceHelper 的代理端保存在 ICarImpl 内部 mICarServiceHelper
  9.              ICarServiceHelper carServiceHelper = ICarServiceHelper.Stub.asInterface(helper);
  10.              synchronized (mLock) {
  11.                  mICarServiceHelper = carServiceHelper;
  12.              }
  13.              //同时也传给了 SystemInterface
  14.              //此时他们有能力跨进程访问 CarServiceHelperService
  15.              mSystemInterface.setCarServiceHelper(carServiceHelper);
  16.              mCarOccupantZoneService.setCarServiceHelper(carServiceHelper);
  17.              mCarUserService.setCarServiceHelper(carServiceHelper);
  18.              ...
  19.      }
复制代码
3.5 小结

CarService的启动时序如下所示:


四 总结

本文讲解了CarService的总体结构、使用方法及启动流程。CarService中实现的功能非常庞大,可以说相比传统手机端的 Android 体系,AAOS 中独特且最重要的部分都在 Framework 的CarService中。


五 参考

Android carservice 架构及启动流程
【Android R】车载 Android 焦点服务 - CarService 解析

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4