封面座舱配图 – 集度ROBO-01
前言
在之前的文章从运用工程师的视点再谈车载 Android 体系中说到了 “CarService
是车载Android体系的中心服务之一,全部运用都需求经过CarService
来查询、操控整车的状况”,不仅仅是车辆操控,实际上CarService
简直便是整个车载Framework最中心的组件,这也让CarService
成了各种bug的重灾区,一部分原因便是开发同学关于CarService
的运转原理与完成办法了解的不行深,那么本篇咱们就来解说Android Automotive R上CarService
是怎么完成。
本文是车载Android中心服务系列文章的第一篇,系列目录如下:
1.【Android R】车载 Android 中心服务 – CarService 解析
2.【Android R】车载 Android 中心服务 – CarPropertyService 解析
这个系列文章首要目的在于整理原生车载Android体系中,一些中心Service的运转原理与源码完成,所以会有大段的源码解读,内容会比较单调。假如阅览本文时还没有车载或车载相关的经验并不丰富,主张先阅览从运用工程师的视点再谈车载 Android 体系,了解车载Android体系的基础结构。
本文说到的
CarService
首要是依据原生Android Automotive,实际量产的各种车载Android体系中由于业务、技术、人员配置等各方面原因会对CarService
做进一步的拆分,所以功用上会与原生的CarService
会存在差异。
CarService 概述
CarService 源码方位:/packages/services/Car/service/
简介
经过之前的文章咱们了解到,Android体系首要运用于中控和副驾屏幕,原生的车载Android本质上能够看作是Android OS + Automotive Services + Automotive APPs组成的体系。用户会经过显现在中控屏幕上App,将对车辆的操作信息经过Car API 传递给Framework Service
,Service再经过HIDL将信息处理后传递给HAL Service
,HAL Service
再将数据处理后传递给MCU
,MCU
经过CAN bus
将信息传递给轿车上的各个ECU(中心忽略了一些不需求了解的过程),然后由ECU操控轿车的机械零部件进行活动,这样就完成了一次从Android APP到车辆机械零部件间的通讯。
HIDL是一种相似于AIDL的跨进程通讯手段,首要运用于HAL层程序的跨进程通讯。Google在Android 8中引入并在Android 10中抛弃,Android 10 今后被AIDL取代。
以上通讯过程起到承上启下效果的Framework Service便是咱们的主角 — CarService
。
原生Android Automotive 体系里
CarService
完成的功用十分多,架构图里描述的仅仅其间的冰山一角,架构图描述的含义仅仅为了引出CarService
。
CarService 的组成
作为 Android Automotive 的中心进程,原生的CarService
业务量十分巨大,包括了许多与轿车相关的服务,首要有以下几个:
- CarPropertyService
此类完成ICarProperty
的binder接口。有助于更容易地创立处理车辆特点的多个Manager。
- CarInputService
CarInputService
经过车辆HAL监控和处理输入事件。
- CarLocationService
此服务在车辆停放时存储LocationManager
中最终一个已知方位,并在车辆通电时康复该方位。
- CarMediaService
CarMediaService
办理轿车运用程序的当时活动媒体源。这与MediaSessionManager
的活动会话不同,由于同一时刻内车内只能有一个活动源。
在车内,活动的媒体源纷歧定有活动的MediaSession
,例如,假如仅仅在阅览它。可是,该源依然被视为活动源,而且应该是任何媒体相关UI(媒体中心、主屏幕等)中显现的源。
- CarPowerManagementService
轿车电源办理服务。操控电源状况并与体系的其他部分交互以确保其自身状况。
- CarProjectionService
轿车投屏服务。
- CarAudioService
担任与轿车音响体系交互的服务。
- AppFocusService
运用程序焦点服务确保一次只要一个运用程序类型的实例处于活动状况。
- GarageModeService
车库方式。车库方式启用车内闲暇时刻。
- InstrumentClusterService
担任与轿车仪表盘交互的服务。
- CarPackageManagerService
轿车包办理服务。
- CarUserService
轿车多用户服务。在发动时办理用户。包括:
- 创立用作驱动程序的用户。
- 创立用作乘客的用户。
- 初次运转时创立辅助办理员用户。
- 切换驾驭员。
- CarStorageMonitoringService
供给存储监视数据(如I/O统计数据)的服务。为了接纳此类数据,用户需求完成IIoStatsListener
并依据此服务注册自己。
- CarBluetoothService
车载蓝牙服务-保护当时用户的蓝牙设备和配置文件衔接。
- FixedActivityService
监控显现器顶部的Activity,并确保在固定方式下的Activity在崩溃或因任何原因进入后台时重新发动。此组件还监视方针包的更新,并在更新完成后重新发动它。
- CarBugreportManagerService
Bug report服务
- CarConfigurationService
该服务将查看体系上的默认JSON配置文件并解析其结果。该服务将查找映射到R.raw.car_config
的JSON文件。假如此值不存在或格式不正确,则此服务不会失败;相反,它回来各种配置的默认值。
- CarDiagnosticService
轿车确诊服务。工程方式会用到此服务。
- CarDrivingStateService
揣度车辆当时驾驭状况的服务。它经过侦听CarPropertyService
的相关特点来核算驾驭状况。
- CarExperimentalFeatureServiceController
操控与ExperimentalCarService
的绑定以及试验功用的接口。
- CarFeatureController
操控轿车特性的部件。
- CarNightService
用于处理用于将车辆设置为夜间方式的事件。
- CarOccupantZoneService
用于完成CarOccupantZoneManager
API的服务。
- CarTestService
允许测验/模仿车辆HAL的服务。该服务直接运用车辆HAL API,由于车辆HAL模仿无论怎么都需求直接拜访该等级。
- CarUxRestrictionsManagerService
用户体验约束的服务。依据监听到的车辆当时驾驭状况,约束HMI显现。
- OccupantAwarenessService
一种服务,经过HAL边界监听占用者感知检测体系,并经过OccupantAwarenessManager
将数据暴露给Android中的体系客户端。
- SystemActivityMonitoringService
监控AMS新Activity或Service发动的服务。
- SystemStateControllerService
体系状况操控服务。原生体系中是一个空服务,并没有完成。
- CarMonitoringService
监视运用程序资源运用状况的服务。
- CarTrustedDeviceService
轿车服务中启用受信任设备功用的部分。可信设备是一项功用,其间长途设备注册为可信设备,能够授权Android用户而不是用户输入暗码或PIN。
- CarUserNoticeService
向用户显现初始告诉UI的服务。它仅在启用设置时发动它,并依据用户的请求告诉UI自行关闭。
- VmsBrokerService
VMS客户端完成,运用HAL特定音讯编码将VmsPublisher/VmsSubscriber API调用代理到车辆HAL。
- CarWatchdogService
完成CarWatchdogManager
API的服务。CarWatchdogService
作为轿车监控中介运转,它查看客户端的健康状况,并将结果报告给轿车监控服务器。
加粗的各个
Service
归于CarService
中比较重要的功用,今后都会独自开坑讲。往简略地说,车载Framework的功用性开发根本便是围绕着
CarService
中的这些服务做增改,假如能把全部这些服务和背后原理都了解透彻,车载Framework根本就算完事了。当然或许也有些过于抱负化了,由于还有android自身的Framework需求修改,比如网络体系、蓝牙协议栈等等。
以上便是Android Automotive中CarService
支撑的全部功用,虽然冠名了xxxService但这些服务其实并不是四大组件含义上的Service
,它们没有承继自android.app.Service
,相反它们都承继自ICarxxxx.Stub
,本质上归于AIDL接口的完成类。到这一步也能够看出CarService
本质上仅仅作为这些服务的容器而存在的,自身并没有完成业务逻辑上的功用。
既然这些Service都是AIDL接口的完成类,本质上便是AIDL的Server端,那运用就还需求经过相应的API SDK才干调用Server的办法,这个API SDK便是Car API。
Car API 运用办法
不同的公司或车机体系项目关于Car API的定位、完成并不相同,本文首要从原生Android Automotive的视点介绍。
Car API 源码地址:packages/services/Car/car-lib/
Car API 简介
在上面的介绍中,咱们说到CarService
中各个服务本质上是AIDL接口的完成类,归于Server端,而对应的Client端就需求一个IBinder
目标来拜访Server端的办法,这些IBinder
目标在Car API中被封装在一个个XXXManager
类中。
Car API与CarService
中的服务,称号上存在对应关系,所以很好了解。例如:CarWatchdogManager
对应CarWatchdogService
,CarMediaManager
对应CarMediaService
。
不过也有破例:CarInfoManager
、CarSensorManager
、CarHvacManager
、CarCabinManager
、CarVendorExtensionManager
都对应CarPropertyService
。可是在Android 11中这些Manager都现已过时,Google主张统一运用CarPropertyManager
。
实际项目中咱们纷歧定要按照Google主张的那样编写Car API,能够按实际状况施行。我个人也经历过某个把Car API源码整个移除,从头重写CarService的项目。
编译 Car API
在运用Car API之前,咱们需求先将Car API编译成jar也便是CarLib,这样才干让其它的体系运用运用。
编译CarLib有三种不同指令:
1)make android.car
编译成功后的jar存放在/out/soong/.intermediates/packages/services/Car/car-lib/android.car/android_common/javac/
目录下。
编译出的CarLib库包括Car API中界说的全部办法以及完成细节。导入到android studio中翻开后,如下所示:
2)make android.car-system-stubs
编译成功后的jar存放在/out/soong/.intermediates/packages/services/Car/car-lib/android.car-system-stubs/android_common/javac/
目录下。
编译出的CarLib库包括CarAPI中界说的全部办法,可是不包括完成细节,一些与完成细节有关的变量也会被躲藏
。实际项目中这种方式较为常用。导入到android studio中翻开后,如下所示:
3)make android.car-stubs
编译成功后的jar存放在/out/soong/.intermediates/packages/services/Car/car-lib/android.car-stubs/android_common/javac/
目录下。
编译出的CarLib库仅包括没有被@SystemApi润饰办法,而且办法同样不包括完成细节,是最严格的编译方式。此方式下编译出的CarLib甚至现已没有CarDiagnosticManager
这个体系API了。
以上三个指令也能够一起运用
上述的编译过程对应的是运用Android Studio开发的体系运用。原生android automotive中的体系运用则是直接在android.bp中将CarLib引入,能够参考Settings/Android.bp第81行。
运用 Car API
Car API 的运用并不杂乱,大致有以下几个过程。
经过Car.createCar()
办法能够创立出Car的目标。
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
Car carApiClient = Car.createCar(context, mCarServiceConnection);
}
经过getPackageManager().hasSystemFeature(String string)判断体系是否支撑特定的模块功用
Car.createCar()
需求传入ServiceConnection
,并在service衔接成功后,获取想要的Manager实例,完成办法如下:
private final ServiceConnection mCarServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
try {
CarHvacManager manager = (CarHvacManager) mCarApiClient.getCarManager(Car.HVAC_SERVICE);
} catch (CarNotConnectedException e) {
Log.e(TAG, "Car not connected in onServiceConnected");
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
构建出Car目标后还需求调用connect()
才会衔接到CarService
上。
carApiClient.connect();
connect()
只能调用一次,假如当时现已处于衔接状况,再次调用connect()
会抛出反常,client假如没有捕获该反常,则会引起client端程序崩溃(血的经验!)。
@Deprecated
public void connect() throws IllegalStateException {
synchronized (mLock) {
if (mConnectionState != STATE_DISCONNECTED) {
throw new IllegalStateException("already connected or connecting");
}
mConnectionState = STATE_CONNECTING;
startCarService();
}
}
与connect()
对应的还有disconnect()
。
carApiClient.disconnect();
不知道你有没有留意到,connect()
被标记为Deprecated过时的办法了。
这是由于在android 10 今后,Google改写了Car API的运用办法,Android 10今后构建Car目标不再主张传入ServiceConnection
而是运用下面的办法:
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
Car carApiClient = Car.createCar(context);
CarHvacManager manager = (CarHvacManager) mCarApiClient.getCarManager(Car.HVAC_SERVICE);
}
Android 10今后Car Api的调用办法由异步办法改为了同步办法,保留了disconnect()
,可是不再需求调用connect()
,这样运用起来更简略。
这种调用办法是乐观的认为CarService
不会产生反常,与CarService
的衔接也不会断开。可是假如CarService
产生反常,衔接被断开的话,client端调用方就会直接被杀死,运用下面这种调用办法能够避免这种状况。
Car car = Car.createCar(this, workThreadHandler, 2000, new Car.CarServiceLifecycleListener() {
@Override
public void onLifecycleChanged(@NonNull Car car, boolean ready) {
// ready 在Service断开衔接时会变为false
if (ready) {
} else {
// CarService 产生反常或衔接被断开了,需求client端处理。
}
}
});
为什么上面的那种调用办法会导致client端的进程被杀死呢?这就需求咱们继续深入的探究一下Car Api是怎么完成的。
Car API 完成原理
讨论Car API的完成原理咱们能够它的入口类Car开始。源码方位:/packages/services/Car/car-lib/src/android/car/Car.java
createCar
有三个不同的重载办法,别离如下所示:
public static Car createCar(Context context)
public static Car createCar(Context context, @Nullable Handler handler)
public static Car createCar(@NonNull Context context,
@Nullable Handler handler, long waitTimeoutMs,
@NonNull CarServiceLifecycleListener statusChangeListener)
createCar(context)
在完成上是直接调用了createCar(context, handler)
,如下所示:
public static Car createCar(Context context) {
return createCar(context, (Handler) null);
}
createCar(context, handler)
与createCar(context, handler, waitTimeoutMs, statusChangeListener)
之间则没有调用关系,各自有各自的完成办法,可是逻辑上大致相同,而且第三种的createCar(context, handler, waitTimeoutMs, statusChangeListener)
逻完成上要更杂乱一些。所以咱们直接看createCar(context, handler, waitTimeoutMs, statusChangeListener)
是完成的就能够了。
- createCar(context, handler, waitTimeoutMs, statusChangeListener)
Handler handler:将全部CarXXXManager事件发送到此handler。可是statusChangeListener
将始终调度到主线程。传递null会导致将全部CarXXXManager回调发送到主线程。
long waitTimeoutMs:将其设置为CAR_WAIT_TIMEOUT_DO_NOT_WAIT
则不等候CarService
衔接安排妥当。将此设置为CAR_WAIT_TIMEOUT_WAIT_FOREVER
将堵塞调用,直到CarService
衔接成功为止。
设置的值大于0则为超时时刻,当存在有限的超时时刻时,回来的Car目标不能确保是可用的。
CarServiceLifecycleListener statusChangeListener: 监听CarService
是否衔接安排妥当。
createCar
在完成流程上能够分为三个部分:
第一步,核算出绑定CarService
的最大重试次数。这个次数决议了后边,多久会显现衔接反常的日志。
public static Car createCar(@NonNull Context context,
@Nullable Handler handler, long waitTimeoutMs,
@NonNull CarServiceLifecycleListener statusChangeListener) {
long maxRetryCount = 0;
if (waitTimeoutMs > 0) {
maxRetryCount = waitTimeoutMs / CAR_SERVICE_BINDER_POLLING_INTERVAL_MS; // 50 ms
// 假如是正值,则至少等候一次。
if (maxRetryCount == 0) {
maxRetryCount = 1;
}
}
...
}
第二步也是最关键的一步,构造出Car目标并回来给调用方,一起将状况经过statusChangeListener
回调给调用方。正常流程下到createCar()办法履行到这儿就现已完毕了。
public static Car createCar(@NonNull Context context,
@Nullable Handler handler, long waitTimeoutMs,
@NonNull CarServiceLifecycleListener statusChangeListener) {
...
Car car = null;
IBinder service = null;
boolean started = false;
int retryCount = 0;
...
boolean isMainThread = Looper.myLooper() == Looper.getMainLooper();
while (true) {
// 这个 CAR_SERVICE_BINDER_SERVICE_NAME 是在CarService发动时添加的。
service = ServiceManager.getService(CAR_SERVICE_BINDER_SERVICE_NAME);
if (car == null) {
// service能够为空,构造办法关于空service是安全的。
car = new Car(context, ICar.Stub.asInterface(service), null, statusChangeListener,
handler);
}
if (service != null) {
if (!started) {
car.dispatchCarReadyToMainThread(isMainThread);
car.startCarService();
// 正常流程下,while (true)循环履行到这儿就完毕了,后边的办法只要CarService发动呈现反常时才会呈现。
return car;
}
break;
}
if (!started) {
car.startCarService();
started = true;
}
// 假如衔接失败,每隔50毫秒重试一次,尝试达到必定的阈值后,日志上会显现反常
retryCount++;
if (waitTimeoutMs < 0 && retryCount >= CAR_SERVICE_BINDER_POLLING_MAX_RETRY
&& retryCount % CAR_SERVICE_BINDER_POLLING_MAX_RETRY == 0) {
// 日志警告
Log.w(TAG_CAR, "car_service not ready, waited for car service (ms):"
+ retryCount * CAR_SERVICE_BINDER_POLLING_INTERVAL_MS,
new RuntimeException());
} else if (waitTimeoutMs >= 0 && retryCount > maxRetryCount) {
if (waitTimeoutMs > 0) {
Log.w(TAG_CAR, "car_service not ready, waited for car service (ms):"
+ waitTimeoutMs,
new RuntimeException());
}
return car;
}
try {
// 休眠 50 ms
Thread.sleep(CAR_SERVICE_BINDER_POLLING_INTERVAL_MS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
Log.w(TAG_CAR, "interrupted", new RuntimeException());
return car;
}
}
最终一步,首要是应对一些反常状况,正常状况不会触发。
public static Car createCar(@NonNull Context context,
@Nullable Handler handler, long waitTimeoutMs,
@NonNull CarServiceLifecycleListener statusChangeListener) {
...
// 加锁是为了让 mServiceConnectionListener 能在主线程中正常拜访 car 实例
synchronized (car.mLock) {
Log.w(TAG_CAR,
"waited for car_service (ms):"
+ retryCount * CAR_SERVICE_BINDER_POLLING_INTERVAL_MS,
new RuntimeException());
// ServiceConnection 现已处理了全部,直接回来 car 实例
if (car.mService != null) {
return car;
}
// mService check in ServiceConnection prevents calling onLifecycleChanged.
// So onLifecycleChanged should be called explicitly but do it outside lock.
car.mService = ICar.Stub.asInterface(service);
car.mConnectionState = STATE_CONNECTED;
}
car.dispatchCarReadyToMainThread(isMainThread);
return car;
}
在createCar()
办法中分发Car实例状况时,会调用startCarService()
绑定CarService
。
private void startCarService() {
Intent intent = new Intent();
intent.setPackage(CAR_SERVICE_PACKAGE);
intent.setAction(Car.CAR_SERVICE_INTERFACE_NAME);
boolean bound = mContext.bindServiceAsUser(intent, mServiceConnectionListener,
Context.BIND_AUTO_CREATE, UserHandle.CURRENT_OR_SELF);
synchronized (mLock) {
if (!bound) {
// 绑定失败时的重试机制
mConnectionRetryCount++;
if (mConnectionRetryCount > CAR_SERVICE_BIND_MAX_RETRY) {
Log.w(TAG_CAR, "cannot bind to car service after max retry");
mMainThreadEventHandler.post(mConnectionRetryFailedRunnable);
} else {
mEventHandler.postDelayed(mConnectionRetryRunnable,
CAR_SERVICE_BIND_RETRY_INTERVAL_MS);
}
} else {
// 绑定成功时要取消重试机制
mEventHandler.removeCallbacks(mConnectionRetryRunnable);
mMainThreadEventHandler.removeCallbacks(mConnectionRetryFailedRunnable);
mConnectionRetryCount = 0;
mServiceBound = true;
}
}
}
private final Runnable mConnectionRetryRunnable = new Runnable() {
@Override
public void run() {
startCarService();
}
};
private final Runnable mConnectionRetryFailedRunnable = new Runnable() {
@Override
public void run() {
mServiceConnectionListener.onServiceDisconnected(new ComponentName(CAR_SERVICE_PACKAGE,
CAR_SERVICE_CLASS));
}
};
在绑定CarService
时,需求运用ServiceConnection
监听与CarService
的衔接状况,并处理service衔接成功与衔接断开的状况。
1)衔接成功:由于在createCar中现已创立好了mService,所以正常流程下,履行到return就完毕了,后边流程根本都是呈现反常触发了重连。
private final ServiceConnection mServiceConnectionListener = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
synchronized (mLock) {
ICar newService = ICar.Stub.asInterface(service);
if (newService == null) {
Log.wtf(TAG_CAR, "null binder service", new RuntimeException());
return; // 这不该该产生
}
if (mService != null && mService.asBinder().equals(newService.asBinder())) {
// 由于在createCar中现已创立好了mService,所以正常流程下,履行到这一步就完毕了
return;
}
mConnectionState = STATE_CONNECTED;
mService = newService;
}
// 分发衔接状况
if (mStatusChangeCallback != null) {
mStatusChangeCallback.onLifecycleChanged(Car.this, true);
} else if (mServiceConnectionListenerClient != null) {
mServiceConnectionListenerClient.onServiceConnected(name, service);
}
}
...
};
2)衔接断开:分发Car目标的状况,此时Client不该该再运用Car的实例。所以假如Client端调用createCar()时没有监听衔接状况,Car Api会触发finishClient()
,直接杀死client端。
private final ServiceConnection mServiceConnectionListener = new ServiceConnection() {
...
@Override
public void onServiceDisconnected(ComponentName name) {
// 重新发动后,CarService能够接纳功用更改。
mFeatures.resetCache();
synchronized (mLock) {
if (mConnectionState == STATE_DISCONNECTED) {
// 当客户端调用在 onServiceDisconnected 调用之前断开衔接时,或许会产生这种状况。
return;
}
handleCarDisconnectLocked();
}
if (mStatusChangeCallback != null) {
mStatusChangeCallback.onLifecycleChanged(Car.this, false);
} else if (mServiceConnectionListenerClient != null) {
mServiceConnectionListenerClient.onServiceDisconnected(name);
} else {
// client端没有正确处理CarService会重新发动的状况,因此直接杀死client端
finishClient();
}
}
};
在finishClient()
中会依据传入client传入的context类型,履行不同的操作。
情形一:context = null,在Client端抛出反常。
情形二:context 是 Activity,完毕该Activity,不会终止Client端的进程。
情形三:context 是 Service,终止Client端的进程。
情形四:context 不是以上的状况,终止Client端的进程。
private void finishClient() {
if (mContext == null) {
throw new IllegalStateException("Car service has crashed, null Context");
}
if (mContext instanceof Activity) {
Activity activity = (Activity) mContext;
if (!activity.isFinishing()) {
Log.w ( TAG_CAR,
"Car service crashed, client not handling it, finish Activity, created "
+ "from " + mConstructionStack);
activity.finish();
}
return;
} else if (mContext instanceof Service) {
Service service = (Service) mContext;
killClient(service.getPackageName() + "," + service.getClass().getSimpleName());
} else {
killClient(/ * clientInfo= */ null);
}
}
private void killClient(@Nullable String clientInfo) {
Log.w ( TAG_CAR, "**Car service has crashed. Client(" + clientInfo + ") is not handling it."
+ " Client should use Car.createCar(..., CarServiceLifecycleListener, .."
+ ".) to handle it properly. Check pritned callstack to check where other "
+ "version of Car.createCar() was called. Killing the client process**",
mConstructionStack);
Process.killProcess( Process.myPid( ));
}
正是由于finishClient()
这种机制的存在,所以调用方应该要监听CarService的衔接状况。
最终咱们再看一下getCarManager()
这个办法是怎么完成的。
getCarManager()
完成机制上利用了BinderPool的思路,运用ICar.aidl
的getService()
来获取Server端的Binder目标,然后将Binder目标封装在Manager里边,一起将Manager目标缓存在一个Map调集中,后续就能够从Map取出需求的Manager,削减IPC通讯开销。如下所示:
@Nullable
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;
}
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;
}
@Nullable
private CarManagerBase createCarManagerLocked(String serviceName, IBinder binder) {
CarManagerBase manager = null;
switch (serviceName) {
case AUDIO_SERVICE:
manager = new CarAudioManager(this, binder);
break;
case SENSOR_SERVICE:
manager = new CarSensorManager(this, binder);
break;
case INFO_SERVICE:
manager = new CarInfoManager(this, binder);
break;
...
default:
// Experimental or non-existing
String className = null;
try {
className = mService.getCarManagerClassForFeature(serviceName);
} catch (RemoteException e) {
handleRemoteExceptionFromCarService(e);
return null;
}
if (className == null) {
Log.e(TAG_CAR, "Cannot construct CarManager for service:" + serviceName
+ " : no class defined");
return null;
}
manager = constructCarManager(className, binder);
break;
}
return manager;
}
以上就Car API的完成过和原理了。留意在createCar()
中有这样一段代码。
IBinder service = null;
service = ServiceManager.getService(CAR_SERVICE_BINDER_SERVICE_NAME);
在Client端与CarService
树立衔接之前,经过ServiceManager.getService()
就能够直接取出IBinder目标,而不用等到与service树立衔接后再从onServiceConnected(ComponentName name, IBinder service)
中取。
可是这样操作的前提是运用ServiceManager.addService()
添加了这个IBinder,那么是哪里添加的呢,IBinder是Server端完成的,那么答案就需求去CarService
中寻找了。
CarService 的完成原理
想要说清楚CarService
完成办法,咱们需求搞明白CarService
是怎么发动的。
CarService 发动流程
CarService
作为Android Automotive的中心服务,它是在SystemServer
中发动的,SystemServer
会在startOtherServices()
办法中让SystemServiceManager
先经过反射的方式创立出StartCarServiceHelperService
这个目标。
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
...
// 仅在automotive中发动
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
t.traceBegin("StartCarServiceHelperService");
mSystemServiceManager.startService(CAR_SERVICE_HELPER_SERVICE_CLASS);
t.traceEnd();
}
...
}
然后在SystemServiceManager
中调用StartCarServiceHelperService
的onStart()
办法。
CarServiceHelperService
是CarService
的SystemService端的配套服务。
public SystemService startService(String className) {
final Class<SystemService> serviceClass = loadClassFromLoader(className,
this.getClass().getClassLoader());
return startService(serviceClass);
}
public void startService(@NonNull final SystemService service) {
// Register it.
mServices.add(service);
long time = SystemClock.elapsedRealtime();
try {
service.onStart();
} catch (RuntimeException ex) {
throw new RuntimeException("Failed to start service " + service.getClass().getName()
+ ": onStart threw an exception", ex);
}
warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
}
最终在onStart()
办法中发动CarService
,并加载jni库为CarService
供给必要的API。
CarServiceHelperService 源码方位:/frameworks/opt/car/services/src/com/android/internal/car/CarServiceHelperService.java
留意:CarServiceHelperService并不是android.app.Service
@Override
public void onStart() {
...
Intent intent = new Intent();
intent.setPackage("com.android.car");
intent.setAction(ICarConstants.CAR_SERVICE_INTERFACE);
if (!mContext.bindServiceAsUser(intent, mCarServiceConnection, Context.BIND_AUTO_CREATE,
UserHandle.SYSTEM)) {
Slog.wtf(TAG, "cannot start car service");
}
loadNativeLibrary();
}
void loadNativeLibrary() {
System.loadLibrary("car-framework-service-jni");
}
经过以上的过程CarService
就完成了发动,CarService
的发动时序如下所示:
CarService 初始化
CarService
进入发动时序后,会onCreate()
办法中进行一系列的自身的初始化操作,过程如下:
1)经过HIDL接口获取到HAL层的IHwBinder目标-IVehicle
,与AIDL的用法相似,必须持有IHwBinder目标咱们才干够与Vehicle HAL层进行通讯。有关HIDL、VechicleHAL今后都会独自介绍。
2)创立ICarImpl目标,并调用init
办法,它便是ICar.aidl
接口的完成类,咱们需求经过它才干拿到其他的Service的IBinder目标。
3)将ICar.aidl
的完成类添加到ServiceManager中。这就回答了咱们在Car API中疑问。
4)设定SystemProperty,将CarService
设定为创立完成状况,只要包括CarService
在内的全部的中心Service都完成初始化,才干完毕开机动画并发送开机播送。
@Override
public void onCreate() {
Log.i(CarLog.TAG_SERVICE, "Service onCreate");
mCanBusErrorNotifier = new CanBusErrorNotifier(this /* context */ );
mVehicle = getVehicle();
EventLog.writeEvent(EventLogTags.CAR_SERVICE_CREATE, mVehicle == null ? 0 : 1);
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);
EventLog.writeEvent(EventLogTags.CAR_SERVICE_CONNECTED, mVehicleInterfaceName);
mICarImpl = new ICarImpl(this,
mVehicle,
SystemInterface.Builder.defaultSystemInterface(this).build(),
mCanBusErrorNotifier,
mVehicleInterfaceName);
mICarImpl.init();
// 处理 HIDL 衔接
linkToDeath(mVehicle, mVehicleDeathRecipient);
ServiceManager.addService("car_service", mICarImpl);
SystemProperties.set("boot.car_service_created", "1");
super.onCreate();
}
@Nullable
private static IVehicle getVehicle() {
final String instanceName = SystemProperties.get("ro.vehicle.hal", "default");
try {
return android.hardware.automotive.vehicle.V2_0.IVehicle.getService(instanceName);
} catch (RemoteException e) {
Log.e(CarLog.TAG_SERVICE, "Failed to get IVehicle/" + instanceName + " service", e);
} catch (NoSuchElementException e) {
Log.e(CarLog.TAG_SERVICE, "IVehicle/" + instanceName + " service not registered yet");
}
return null;
}
接着咱们再来看ICarImpl
的完成,如下所示:
1)创立各个中心服务目标。
2)把服务目标缓存到CarLocalServices中,这儿首要是为了方便Service之间的彼此拜访。
ICarImpl的源码方位:/packages/services/Car/service/src/com/android/car/ICar
ICarImpl(Context serviceContext, IVehicle vehicle, SystemInterface systemInterface,
CanBusErrorNotifier errorNotifier, String vehicleInterfaceName,
@Nullable CarUserService carUserService,
@Nullable CarWatchdogService carWatchdogService) {
...
// 创立 中心服务目标
mCarPowerManagementService = new CarPowerManagementService(mContext, mHal.getPowerHal(),
systemInterface, mCarUserService);
...
// 将重要的服务缓存到 CarLocalServices
CarLocalServices.addService(CarPowerManagementService.class, mCarPowerManagementService);
CarLocalServices.addService(CarPropertyService.class, mCarPropertyService);
CarLocalServices.addService(CarUserService.class, mCarUserService);
CarLocalServices.addService(CarTrustedDeviceService.class, mCarTrustedDeviceService);
CarLocalServices.addService(CarUserNoticeService.class, mCarUserNoticeService);
CarLocalServices.addService(SystemInterface.class, mSystemInterface);
CarLocalServices.addService(CarDrivingStateService.class, mCarDrivingStateService);
CarLocalServices.addService(PerUserCarServiceHelper.class, mPerUserCarServiceHelper);
CarLocalServices.addService(FixedActivityService.class, mFixedActivityService);
CarLocalServices.addService(VmsBrokerService.class, mVmsBrokerService);
CarLocalServices.addService(CarOccupantZoneService.class, mCarOccupantZoneService);
CarLocalServices.addService(AppFocusService.class, mAppFocusService);
// 将创立的服务目标顺次添加到一个list中保存起来
List<CarServiceBase> allServices = new ArrayList<>();
allServices.add(mFeatureController);
allServices.add(mCarUserService);
...
allServices.add(mCarWatchdogService);
// Always put mCarExperimentalFeatureServiceController in last.
addServiceIfNonNull(allServices, mCarExperimentalFeatureServiceController);
mAllServices = allServices.toArray(new CarServiceBase[allServices.size()]);
}
3)将服务目标放置一个list中。这样init办法中就能够以循环的方式直接调用服务目标的init,而不需求一个个调用。VechicleHAL的程序也会在这儿完成初始化。
@MainThread
void init() {
mBootTiming = new TimingsTraceLog(VHAL_TIMING_TAG, Trace.TRACE_TAG_HAL);
traceBegin("VehicleHal.init");
// 初始化 Vechicle HAL
mHal.init();
traceEnd();
traceBegin("CarService.initAllServices");
// 初始化全部服务
for (CarServiceBase service : mAllServices) {
service.init();
}
traceEnd();
}
4)最终完成ICar.aidl
中界说的各个接口就能够了,如下所示:
@Override
public IBinder getCarService(String serviceName) {
if (!mFeatureController.isFeatureEnabled(serviceName)) {
Log.w(CarLog.TAG_SERVICE, "getCarService for disabled service:" + serviceName);
return null;
}
switch (serviceName) {
case Car.AUDIO_SERVICE:
return mCarAudioService;
case Car.APP_FOCUS_SERVICE:
return mAppFocusService;
case Car.PACKAGE_SERVICE:
return mCarPackageManagerService;
...
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;
}
}
总结一下CarService
的发动时序如下所示:
总结
本篇解说了CarService
的总体结构,以及Car API 的完成原理,CarService
中完成的功用十分巨大,就像文章中重复在强调的那样,在CarService
完成的功用简直便是覆盖了整个车载Framework。
但是现实中为了确保各个中心服务的稳定性,一起下降CarService
协同开发的难度,一般会选择将一些重要的服务拆分出来,作为一个独立的Service运转在自己的进程中,导致有的车机体系中CarService
名不符实,根本上只完成了CarPropertyService
的功用。
文中说到的其他中心Service,会在今后的时刻里逐一介绍,感谢你的阅览,希望对你有所帮助。