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 汽车服务.
对于应用来说,并不会直接通过以上服务的实例调用相关功能,而是通过对应的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的启动流程, 看看它在启动过程中做了些什么事情, 作为 AAOS的核心服务, CarService需要始终在后台运行, 并在在系统启动的早期进行创建. 时序图:
细节代码如下:
/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服务的补充,在汽车设备上运行
AAOS 架构图
当服务启动之后, 首先调用其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);
.....
}
这些创建的服务就是上文介绍的汽车服务.
在上面的介绍中,我们提到CarService
中各个服务本质上是AIDL接口的实现类,属于Server端,而对应的Client端就需要一个IBinder
对象来访问Server端的方法,这些IBinder
对象在Car API中被封装在一个个XXXManager
类中。
在使用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
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和对应的服务来实现了.