AAOS系列之(四) ---APP端如何获取CarService中的各个服务代理
一文讲透AAOS架构,点到为止不藏私
📌 这篇帖子给大家分析下 APP端如何获取CarService中的各个服务代理
1. ICar.aidl 接口定义:
-
为了实现 APP 进程与 CarService 进程之间的跨进程通信,系统通过定义 AIDL 接口 ICar.aidl 来规范双方的通信协议。该接口作为桥梁,允许客户端进程调用 CarService 中提供的服务能力,涵盖用户生命周期事件通知、服务查询、功能控制等核心操作。
-
ICar 是 Android Automotive 系统中 APP 进程与 CarService 进程进行跨进程通信的关键接口。该接口采用 AIDL(Android Interface Definition Language)定义,允许客户端调用车载系统的核心服务能力,涵盖用户生命周期事件通知、初始用户信息获取、功能开关控制等功能。
接口设计遵循以下原则:
部分方法声明为 oneway,用于异步通知,确保系统服务调用效率和实时性;按方法编号固定调用顺序,避免因接口方法调整引发系统服务端调用错误;支持通过 IBinder 传递内部隐藏类型,实现模块间解耦;提供丰富的用户管理事件回调和车载功能管理接口。
主要方法包括:
setCarServiceHelper(IBinder helper):设置内部辅助服务的绑定;onUserLifecycleEvent(int eventType, long timestampMs, int fromUserId, int toUserId):通知用户切换和生命周期事件;onFirstUserUnlocked(int userId, long timestampMs, long duration, int halResponseTime):首次用户解锁通知,用于指标采集;getInitialUserInfo(int requestType, int timeoutMs, IBinder receiver):调用底层 HAL 获取初始用户信息;setInitialUser(int userId):设置系统启动后的初始用户;getCarService(String serviceName):获取指定车载服务的 Binder 对象;isFeatureEnabled(String featureName) / enableFeature(String featureName) / disableFeature(String featureName):车载功能的状态查询及控制;getAllEnabledFeatures()、getAllPendingDisabledFeatures()、getAllPendingEnabledFeatures():批量获取车载功能的启用及待变更列表;getCarManagerClassForFeature(String featureName):获取实验性功能对应的管理类名。
该接口为 Android 车载系统提供了统一、稳定、高效的跨进程服务调用通道,保障系统模块协同运行的灵活性和扩展性,内容定义如下:
/** Copyright (C) 2015 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package android.car;/** @hide */
interface ICar {// All oneway methods are called from system server and should be placed in top positions.// Do not change the number of oneway methods as system server make binder calls based on these// numbers - if you change them, you need to change the constants on CarServiceHelperService./*** IBinder is ICarServiceHelper but passed as IBinder due to aidl hidden.*/oneway void setCarServiceHelper(in IBinder helper) = 0;/*** Notify of user lifecycle events.** @param eventType - type as defined by CarUserManager.UserLifecycleEventType* @param timestampMs - when the event happened* @param fromUserId - user id of previous user when type is SWITCHING (or UserHandle.USER_NULL)* @param toUserId - user id of new user.*/oneway void onUserLifecycleEvent(int eventType, long timestampMs, int fromUserId,int toUserId) = 1;/*** Notify when first user was unlocked, for metrics (and lifecycle) purposes.** @param userId - id of first non-system user locked* @param timestampMs - when the user was unlocked* @param duration - how long it took to unlock (from SystemServer start)* @param halResponseTime - see CarServiceHelperService.mHalResponseTime*/oneway void onFirstUserUnlocked(int userId, long timestampMs, long duration,int halResponseTime) = 2;/*** Calls User HAL to get the initial user info.** @param requestType - as defined by InitialUserInfoRequestType.* @param timeoutMs - how long to wait for HAL's response.* @param receiver - a com.android.internal.os.IResultReceiver callback.*/oneway void getInitialUserInfo(int requestType, int timeoutMs, in IBinder receiver) = 3;/*** Sets the initial user after boot.** @param userId - the id of the initial user*/// TODO(b/150413515): should pass UserInfo instead, but for some reason passing the whole// UserInfo through a raw binder transaction on CarServiceHelper is not working.oneway void setInitialUser(int userId) = 4;// Methods below start on 11 to make it easier to add more oneway methods aboveIBinder getCarService(in String serviceName) = 11;int getCarConnectionType() = 12;boolean isFeatureEnabled(in String featureName) = 13;int enableFeature(in String featureName) = 14;int disableFeature(in String featureName) = 15;List<String> getAllEnabledFeatures() = 16;List<String> getAllPendingDisabledFeatures() = 17;List<String> getAllPendingEnabledFeatures() = 18;/*** Get class name for experimental feature. Class should have constructor taking (Car, IBinder)* and should inherit CarManagerBase.*/String getCarManagerClassForFeature(in String featureName) = 19;
}
从上面的aidl文件描述了进程间通讯的规范,细心的你可能发现了, 部分方法前面加了oneway , 而另外的一些方法并没有加oneway这个限制. 这是为什么呢?
由于 AIDL 跨进程通信采用客户端-服务端模型(C/S 架构),客户端运行在 APP 所在进程中,每个进程会创建自己的服务代理对象;而服务端则运行在 CarService 所在的独立进程中,整个系统仅有一个服务端实例。
在调用服务端方法时,如果客户端需要等待服务端的返回结果才能继续执行(即同步调用),则不能为该方法添加 oneway 关键字。此类调用在多个客户端同时发起时,服务端会依次处理,每个调用需排队等待返回,期间客户端线程会阻塞。
而对于一些无需等待返回结果的方法(如 setXxx() 类设置接口),可以使用 oneway 关键字。这种调用是异步的:客户端只负责发送请求,不等待服务端响应,调用过程不会阻塞客户端线程,适用于不依赖结果的轻量级指令下发场景。
UML类图如下:
2.以下是 ICar.aidl 接口在服务端的实现示例:
在服务端实现中,CarService 持有多个子服务实例,这些服务分别负责车载系统中的不同功能模块,涵盖了系统监控、电源管理、输入控制、驾驶状态、用户体验限制、乘员感知、音频处理、投影管理、属性管理、夜间模式、应用焦点、固定活动、车库模式、仪表盘、定位、系统状态控制、蓝牙、诊断、存储监控、配置管理、可信设备、媒体服务、用户管理、乘员区域管理、用户通知、车辆管理、报告管理、统计、实验性功能控制及系统守护等领域。
这些服务协同工作,构成了车载系统丰富的功能生态,确保了系统的稳定、高效与智能体验。
@android11.0/packages/services/Car/service/src/com/android/car/ICarImpl.java@
public class ICarImpl extends ICar.Stub {// 服务端定义的各个服务如下:private final SystemActivityMonitoringService mSystemActivityMonitoringService;private final CarPowerManagementService mCarPowerManagementService;private final CarPackageManagerService mCarPackageManagerService;private final CarInputService mCarInputService;private final CarDrivingStateService mCarDrivingStateService;private final CarUxRestrictionsManagerService mCarUXRestrictionsService;private final OccupantAwarenessService mOccupantAwarenessService;private final CarAudioService mCarAudioService;private final CarProjectionService mCarProjectionService;private final CarPropertyService mCarPropertyService;private final CarNightService mCarNightService;private final AppFocusService mAppFocusService;private final FixedActivityService mFixedActivityService;private final GarageModeService mGarageModeService;private final InstrumentClusterService mInstrumentClusterService;private final CarLocationService mCarLocationService;private final SystemStateControllerService mSystemStateControllerService;private final CarBluetoothService mCarBluetoothService;private final PerUserCarServiceHelper mPerUserCarServiceHelper;private final CarDiagnosticService mCarDiagnosticService;private final CarStorageMonitoringService mCarStorageMonitoringService;private final CarConfigurationService mCarConfigurationService;private final CarTrustedDeviceService mCarTrustedDeviceService;private final CarMediaService mCarMediaService;private final CarUserManagerHelper mUserManagerHelper;private final CarUserService mCarUserService;private final CarOccupantZoneService mCarOccupantZoneService;private final CarUserNoticeService mCarUserNoticeService;private final VmsBrokerService mVmsBrokerService;private final CarBugreportManagerService mCarBugreportManagerService;private final CarStatsService mCarStatsService;private final CarExperimentalFeatureServiceController mCarExperimentalFeatureServiceController;private final CarWatchdogService mCarWatchdogService;}
3. APP 端通过调用 getCarService(String serviceName) 方法获取所需的车载服务实例,随后即可调用该服务暴露的各项功能接口,实现与车载系统的交互:
@Overridepublic IBinder getCarService(String serviceName) {
switch (serviceName) {case Car.AUDIO_SERVICE:return mCarAudioService;case Car.APP_FOCUS_SERVICE:return mAppFocusService;case Car.PACKAGE_SERVICE:return mCarPackageManagerService;case Car.DIAGNOSTIC_SERVICE:assertAnyDiagnosticPermission(mContext);return mCarDiagnosticService;case Car.POWER_SERVICE:assertPowerPermission(mContext);return mCarPowerManagementService;case Car.INFO_SERVICE:case Car.PROPERTY_SERVICE:case Car.SENSOR_SERVICE:case Car.VENDOR_EXTENSION_SERVICE:return mCarPropertyService;case Car.CAR_NAVIGATION_SERVICE:assertNavigationManagerPermission(mContext);IInstrumentClusterNavigation navService =mInstrumentClusterService.getNavigationService();return navService == null ? null : navService.asBinder();case Car.CAR_INSTRUMENT_CLUSTER_SERVICE:assertClusterManagerPermission(mContext);return mInstrumentClusterService.getManagerService();case Car.PROJECTION_SERVICE:return mCarProjectionService;case Car.VEHICLE_MAP_SERVICE:assertAnyVmsPermission(mContext);return mVmsBrokerService;case Car.VMS_SUBSCRIBER_SERVICE:assertVmsSubscriberPermission(mContext);return mVmsBrokerService;case Car.TEST_SERVICE: {assertPermission(mContext, Car.PERMISSION_CAR_TEST_SERVICE);synchronized (mLock) {if (mCarTestService == null) {mCarTestService = new CarTestService(mContext, this);}return mCarTestService;}}case Car.BLUETOOTH_SERVICE:return mCarBluetoothService;case Car.STORAGE_MONITORING_SERVICE:assertPermission(mContext, Car.PERMISSION_STORAGE_MONITORING);return mCarStorageMonitoringService;case Car.CAR_DRIVING_STATE_SERVICE:assertDrivingStatePermission(mContext);return mCarDrivingStateService;case Car.CAR_UX_RESTRICTION_SERVICE:return mCarUXRestrictionsService;case Car.OCCUPANT_AWARENESS_SERVICE:return mOccupantAwarenessService;case Car.CAR_CONFIGURATION_SERVICE:return mCarConfigurationService;case Car.CAR_TRUST_AGENT_ENROLLMENT_SERVICE:assertTrustAgentEnrollmentPermission(mContext);return mCarTrustedDeviceService.getCarTrustAgentEnrollmentService();case Car.CAR_MEDIA_SERVICE:return mCarMediaService;case Car.CAR_OCCUPANT_ZONE_SERVICE:return mCarOccupantZoneService;case Car.CAR_BUGREPORT_SERVICE:return mCarBugreportManagerService;case Car.CAR_USER_SERVICE:return mCarUserService;case Car.CAR_WATCHDOG_SERVICE:return mCarWatchdogService;case Car.CAR_INPUT_SERVICE:return mCarInputService;default:IBinder service = null;if (mCarExperimentalFeatureServiceController != null) {service = mCarExperimentalFeatureServiceController.getCarService(serviceName);}if (service == null) {Log.w(CarLog.TAG_SERVICE, "getCarService for unknown service:"+ serviceName);}return service;}}}
4. APP可以获取到的这服务是在创建的呢?
原来是在ICarImpl的构造方法中实例化好了这些服务,等待APP端的调用.
@android11.0/packages/services/Car/service/src/com/android/car/ICarImpl.java@ICarImpl(Context serviceContext, IVehicle vehicle, SystemInterface systemInterface,CanBusErrorNotifier errorNotifier, String vehicleInterfaceName,@Nullable CarUserService carUserService,@Nullable CarWatchdogService carWatchdogService) {mContext = serviceContext;mSystemInterface = systemInterface;mHal = new VehicleHal(serviceContext, vehicle);// Do this before any other service components to allow feature check. It should work// even without init. For that, vhal get is retried as it can be too early.VehiclePropValue disabledOptionalFeatureValue = mHal.getIfAvailableOrFailForEarlyStage(VehicleProperty.DISABLED_OPTIONAL_FEATURES, INITIAL_VHAL_GET_RETRY);String[] disabledFeaturesFromVhal = null;if (disabledOptionalFeatureValue != null) {String disabledFeatures = disabledOptionalFeatureValue.value.stringValue;if (disabledFeatures != null && !disabledFeatures.isEmpty()) {disabledFeaturesFromVhal = disabledFeatures.split(",");}}if (disabledFeaturesFromVhal == null) {disabledFeaturesFromVhal = new String[0];}Resources res = mContext.getResources();String[] defaultEnabledFeatures = res.getStringArray(R.array.config_allowed_optional_car_features);mFeatureController = new CarFeatureController(serviceContext, defaultEnabledFeatures,disabledFeaturesFromVhal , mSystemInterface.getSystemCarDir());CarLocalServices.addService(CarFeatureController.class, mFeatureController);mVehicleInterfaceName = vehicleInterfaceName;mUserManagerHelper = new CarUserManagerHelper(serviceContext);if (carUserService != null) {mCarUserService = carUserService;} else {UserManager userManager =(UserManager) serviceContext.getSystemService(Context.USER_SERVICE);int maxRunningUsers = res.getInteger(com.android.internal.R.integer.config_multiuserMaxRunningUsers);mCarUserService = new CarUserService(serviceContext, mHal.getUserHal(),mUserManagerHelper, userManager, ActivityManager.getService(), maxRunningUsers);}mCarOccupantZoneService = new CarOccupantZoneService(serviceContext);mSystemActivityMonitoringService = new SystemActivityMonitoringService(serviceContext);mCarPowerManagementService = new CarPowerManagementService(mContext, mHal.getPowerHal(),systemInterface, mCarUserService,this);if (mFeatureController.isFeatureEnabled(CarFeatures.FEATURE_CAR_USER_NOTICE_SERVICE)) {mCarUserNoticeService = new CarUserNoticeService(serviceContext);} else {mCarUserNoticeService = null;}mCarPropertyService = new CarPropertyService(serviceContext, mHal.getPropertyHal());mCarDrivingStateService = new CarDrivingStateService(serviceContext, mCarPropertyService);mCarUXRestrictionsService = new CarUxRestrictionsManagerService(serviceContext,mCarDrivingStateService, mCarPropertyService);if (mFeatureController.isFeatureEnabled(Car.OCCUPANT_AWARENESS_SERVICE)) {mOccupantAwarenessService = new OccupantAwarenessService(serviceContext);} else {mOccupantAwarenessService = null;}mCarPackageManagerService = new CarPackageManagerService(serviceContext,mCarUXRestrictionsService,mSystemActivityMonitoringService);mCarSomeipService = new SomeipHalService(serviceContext);mPerUserCarServiceHelper = new PerUserCarServiceHelper(serviceContext, mCarUserService);mCarBluetoothService = new CarBluetoothService(serviceContext, mPerUserCarServiceHelper);mCarInputService = new CarInputService(serviceContext, mHal.getInputHal(), mCarUserService);mCarProjectionService = new CarProjectionService(serviceContext, null /* handler */, mCarInputService, mCarBluetoothService);mGarageModeService = new GarageModeService(mContext);mAppFocusService = new AppFocusService(serviceContext, mSystemActivityMonitoringService);mCarAudioService = new CarAudioService(serviceContext,mSystemActivityMonitoringService);
5. APP端如何获取Car的各个服务的呢?
经过CarService的onCreate,调用了ICarImpl的构造方法, 实例化完成了各个服务的实力,且保存到了ICarImpl的成员变量中, 同时,ICarImpl是ICar这个接口的Stub服务端.给APP提供了调用的实现.
那APP端是如何调用getService来获取服务的呢, 接下来我们来看下APP端的代码:
- 当APP端需要使用服务时, 根据serviceName先从缓存中获取.
- 这个缓存是运行在APP的进程,每个进程有一份自己的缓存数据.
- 如果缓存中没有这个服务的代理对象,那么就调用mService.getCarService()跨进程从服务端获取, 再保存到缓存.
- 返回对应的Manager对象给APP端使用.
public final class Car {public Object getCarManager(String serviceName) {CarManagerBase manager;synchronized (mLock) {if (mService == null) {Log.w(TAG_CAR, "getCarManager not working while car service not ready");return null;}// 当APP端需要使用服务时, 根据serviceName先从缓存中获取manager = mServiceMap.get(serviceName);if (manager == null) {try {IBinder binder = mService.getCarService(serviceName);if (binder == null) {Log.w(TAG_CAR, "getCarManager could not get binder for service:"+ serviceName);return null;}manager = createCarManagerLocked(serviceName, binder);if (manager == null) {Log.w(TAG_CAR, "getCarManager could not create manager for service:"+ serviceName);return null;}mServiceMap.put(serviceName, manager);} catch (RemoteException e) {handleRemoteExceptionFromCarService(e);}}}return manager;}
}}
6. APP的调用示例如下:
APP 端在初始化 Car 对象时,通过调用 Car.createCar() 来实例化 ICar 接口对象。随后,在初始化完成的回调方法中,APP 便可以通过 getCarManager() 方法获取服务端已经实例化好的各个车载服务,从而调用它们提供的功能。
public Car initCar(@NonNull Context context) {if (mCar == null) {mCar = Car.createCar(context, null, 1000, new Car.CarServiceLifecycleListener() {@Overridepublic void onLifecycleChanged(Car car, boolean isConnect) {Log.i(TAG, "onLifecycleChanged, isConnect = " + isConnect + " car = " + car);mCar = car;if (isConnect) {//服务连接上后再做各模块初始化mCarPropertyManager = (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE);initCarManager();} else {unregisterCallback();}}});}return mCar;}