前言
在之前的文章從應(yīng)用工程師的角度再談車載 Android 系統(tǒng)中提到了"CarService
是車載Android系統(tǒng)的核心服務(wù)之一,所有應(yīng)用都需要通過CarService
來查詢、控制整車的狀態(tài)",不僅僅是車輛控制,實際上CarService
幾乎就是整個車載Framework最核心的組件,這也讓CarService
成了各種bug的重災(zāi)區(qū),一部分原因就是開發(fā)同學(xué)對于CarService
的運行原理與實現(xiàn)方式理解的不夠深,那么本篇我們就來講解Android Automotive R上CarService
是如何實現(xiàn)。
本文提到的
CarService
主要是基于原生Android Automotive,實際量產(chǎn)的各種車載Android系統(tǒng)中由于業(yè)務(wù)、技術(shù)、人員配置等各方面原因會對CarService
做進(jìn)一步的拆分,所以功能上會與原生的CarService
會存在差異。
CarService 概述
CarService 源碼位置:/packages/services/Car/service/
簡介
通過之前的文章我們了解到,Android系統(tǒng)主要應(yīng)用于中控和副駕屏幕,原生的車載Android本質(zhì)上可以看作是Android OS + Automotive Services + Automotive APPs組成的系統(tǒng)。用戶會通過顯示在中控屏幕上App,將對車輛的操作信息通過Car API 傳遞給Framework Service
,Service再通過HIDL將信息處理后傳遞給HAL Service
,HAL Service
再將數(shù)據(jù)處理后傳遞給MCU
,MCU
通過CAN bus
將信息傳遞給汽車上的各個ECU(中間忽略了一些不需要理解的步驟),然后由ECU控制汽車的機(jī)械零部件進(jìn)行活動,這樣就完成了一次從Android APP到車輛機(jī)械零部件間的通信。
HIDL是一種類似于AIDL的跨進(jìn)程通信手段,主要應(yīng)用于HAL層程序的跨進(jìn)程通信。Google在Android 8中引入并在Android 10中廢棄,Android 10 以后被AIDL取代。
以上通信過程起到承上啟下作用的Framework Service就是我們的主角 — CarService
。
原生Android Automotive 系統(tǒng)里
CarService
實現(xiàn)的功能非常多,架構(gòu)圖里描述的只是其中的冰山一角,架構(gòu)圖描述的意義只是為了引出CarService
。
CarService 的組成
作為 Android Automotive 的核心進(jìn)程,原生的CarService
業(yè)務(wù)量非常龐大,包含了許多與汽車相關(guān)的服務(wù),主要有以下幾個:
- CarPropertyService
此類實現(xiàn)ICarProperty
的binder接口。有助于更容易地創(chuàng)建處理車輛屬性的多個Manager。
- CarInputService
CarInputService
通過車輛HAL監(jiān)控和處理輸入事件。
- CarLocationService
此服務(wù)在車輛停放時存儲LocationManager
中最后一個已知位置,并在車輛通電時恢復(fù)該位置。
- CarMediaService
CarMediaService
管理汽車應(yīng)用程序的當(dāng)前活動媒體源。這與MediaSessionManager
的活動會話不同,因為同一時間內(nèi)車內(nèi)只能有一個活動源。
在車內(nèi),活動的媒體源不一定有活動的MediaSession
,例如,如果只是在瀏覽它。但是,該源仍然被視為活動源,并且應(yīng)該是任何媒體相關(guān)UI(媒體中心、主屏幕等)中顯示的源。
- CarPowerManagementService
汽車電源管理服務(wù)。控制電源狀態(tài)并與系統(tǒng)的其他部分交互以確保其自身狀態(tài)。
- CarProjectionService
汽車投屏服務(wù)。
- CarAudioService
負(fù)責(zé)與汽車音響系統(tǒng)交互的服務(wù)。
- AppFocusService
應(yīng)用程序焦點服務(wù)確保一次只有一個應(yīng)用程序類型的實例處于活動狀態(tài)。
- GarageModeService
車庫模式。車庫模式啟用車內(nèi)空閑時間。
- InstrumentClusterService
負(fù)責(zé)與汽車儀表盤交互的服務(wù)。
- CarPackageManagerService
汽車包管理服務(wù)。
- CarUserService
汽車多用戶服務(wù)。在啟動時管理用戶。包括:
- 創(chuàng)建用作驅(qū)動程序的用戶。
- 創(chuàng)建用作乘客的用戶。
- 首次運行時創(chuàng)建輔助管理員用戶。
- 切換駕駛員。
- CarStorageMonitoringService
提供存儲監(jiān)視數(shù)據(jù)(如I/O統(tǒng)計數(shù)據(jù))的服務(wù)。為了接收此類數(shù)據(jù),用戶需要實現(xiàn)IIoStatsListener
并根據(jù)此服務(wù)注冊自己。
- CarBluetoothService
車載藍(lán)牙服務(wù)-維護(hù)當(dāng)前用戶的藍(lán)牙設(shè)備和配置文件連接。
- FixedActivityService
監(jiān)控顯示器頂部的Activity,并確保在固定模式下的Activity在崩潰或因任何原因進(jìn)入后臺時重新啟動。此組件還監(jiān)視目標(biāo)包的更新,并在更新完成后重新啟動它。
- CarBugreportManagerService
Bug report服務(wù)
- CarConfigurationService
該服務(wù)將查看系統(tǒng)上的默認(rèn)JSON配置文件并解析其結(jié)果。該服務(wù)將查找映射到R.raw.car_config
的JSON文件。如果此值不存在或格式不正確,則此服務(wù)不會失敗;相反,它返回各種配置的默認(rèn)值。
- CarDiagnosticService
汽車診斷服務(wù)。工程模式會用到此服務(wù)。
- CarDrivingStateService
推斷車輛當(dāng)前駕駛狀態(tài)的服務(wù)。它通過偵聽CarPropertyService
的相關(guān)屬性來計算駕駛狀態(tài)。
- CarExperimentalFeatureServiceController
控制與ExperimentalCarService
的綁定以及實驗功能的接口。
- CarFeatureController
控制汽車特性的部件。
- CarNightService
用于處理用于將車輛設(shè)置為夜間模式的事件。
- CarOccupantZoneService
用于實現(xiàn)CarOccupantZoneManager
API的服務(wù)。
- CarTestService
允許測試/模擬車輛HAL的服務(wù)。該服務(wù)直接使用車輛HAL API,因為車輛HAL模擬無論如何都需要直接訪問該級別。
- CarUxRestrictionsManagerService
用戶體驗限制的服務(wù)。根據(jù)監(jiān)聽到的車輛當(dāng)前駕駛狀態(tài),限制HMI顯示。
- OccupantAwarenessService
一種服務(wù),通過HAL邊界監(jiān)聽占用者感知檢測系統(tǒng),并通過OccupantAwarenessManager
將數(shù)據(jù)暴露給Android中的系統(tǒng)客戶端。
- SystemActivityMonitoringService
監(jiān)控AMS新Activity或Service啟動的服務(wù)。
- SystemStateControllerService
系統(tǒng)狀態(tài)控制服務(wù)。原生系統(tǒng)中是一個空服務(wù),并沒有實現(xiàn)。
- CarMonitoringService
監(jiān)視應(yīng)用程序資源使用情況的服務(wù)。
- CarTrustedDeviceService
汽車服務(wù)中啟用受信任設(shè)備功能的部分。可信設(shè)備是一項功能,其中遠(yuǎn)程設(shè)備注冊為可信設(shè)備,可以授權(quán)Android用戶而不是用戶輸入密碼或PIN。
- CarUserNoticeService
向用戶顯示初始通知UI的服務(wù)。它僅在啟用設(shè)置時啟動它,并根據(jù)用戶的請求通知UI自行關(guān)閉。
- VmsBrokerService
VMS客戶端實現(xiàn),使用HAL特定消息編碼將VmsPublisher/VmsSubscriber API調(diào)用代理到車輛HAL。
- CarWatchdogService
實現(xiàn)CarWatchdogManager
API的服務(wù)。CarWatchdogService
作為汽車監(jiān)控中介運行,它檢查客戶端的健康狀況,并將結(jié)果報告給汽車監(jiān)控服務(wù)器。
加粗的各個
Service
屬于CarService
中比較重要的功能,以后都會單獨開坑講。往簡單地說,車載Framework的功能性開發(fā)基本就是圍繞著
CarService
中的這些服務(wù)做增改,如果能把所有這些服務(wù)和背后原理都理解透徹,車載Framework基本就算完事了。當(dāng)然可能也有些過于理想化了,因為還有android自身的Framework需要修改,比如網(wǎng)絡(luò)系統(tǒng)、藍(lán)牙協(xié)議棧等等。
以上就是Android Automotive中CarService
支持的所有功能,雖然冠名了xxxService但這些服務(wù)其實并不是四大組件意義上的Service
,它們沒有繼承自android.app.Service
,相反它們都繼承自ICarxxxx.Stub
,本質(zhì)上屬于AIDL接口的實現(xiàn)類。到這一步也可以看出CarService
本質(zhì)上只是作為這些服務(wù)的容器而存在的,本身并沒有實現(xiàn)業(yè)務(wù)邏輯上的功能。
既然這些Service都是AIDL接口的實現(xiàn)類,本質(zhì)上就是AIDL的Server端,那應(yīng)用就還需要通過相應(yīng)的API SDK才能調(diào)用Server的方法,這個API SDK就是Car API。
Car API 使用方式
不同的公司或車機(jī)系統(tǒng)項目對于Car API的定位、實現(xiàn)并不相同,本文主要從原生Android Automotive的角度介紹。
Car API 源碼地址:packages/services/Car/car-lib/
Car API 簡介
在上面的介紹中,我們提到CarService
中各個服務(wù)本質(zhì)上是AIDL接口的實現(xiàn)類,屬于Server端,而對應(yīng)的Client端就需要一個IBinder
對象來訪問Server端的方法,這些IBinder
對象在Car API中被封裝在一個個XXXManager
類中。
Car API與CarService
中的服務(wù),名稱上存在對應(yīng)關(guān)系,所以很好理解。例如:CarWatchdogManager
對應(yīng)CarWatchdogService
,CarMediaManager
對應(yīng)CarMediaService
。
不過也有例外:CarInfoManager
、CarSensorManager
、CarHvacManager
、CarCabinManager
、CarVendorExtensionManager
都對應(yīng)CarPropertyService
。但是在Android 11中這些Manager都已經(jīng)過時,Google建議統(tǒng)一使用CarPropertyManager
。
實際項目中我們不一定要按照Google建議的那樣編寫Car API,可以按實際情況實施。我個人也經(jīng)歷過某個把Car API源碼整個移除,從頭重寫CarService的項目。
編譯 Car API
在使用Car API之前,我們需要先將Car API編譯成jar也就是CarLib,這樣才能讓其它的系統(tǒng)應(yīng)用使用。
編譯CarLib有三種不同指令:
1)make android.car
編譯成功后的jar存放在/out/soong/.intermediates/packages/services/Car/car-lib/android.car/android_common/javac/
目錄下。
編譯出的CarLib庫包含Car API中定義的所有方法以及實現(xiàn)細(xì)節(jié)。導(dǎo)入到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中定義的所有方法,但是不包含實現(xiàn)細(xì)節(jié),一些與實現(xiàn)細(xì)節(jié)有關(guān)的變量也會被隱藏
。實際項目中這種模式較為常用。導(dǎo)入到android studio中打開后,如下所示:
3)make android.car-stubs
編譯成功后的jar存放在/out/soong/.intermediates/packages/services/Car/car-lib/android.car-stubs/android_common/javac/
目錄下。
編譯出的CarLib庫僅包含沒有被@SystemApi修飾方法,而且方法同樣不包含實現(xiàn)細(xì)節(jié),是最嚴(yán)格的編譯模式。此模式下編譯出的CarLib甚至已經(jīng)沒有CarDiagnosticManager
這個系統(tǒng)API了。
以上三個指令也可以一起使用
上述的編譯步驟對應(yīng)的是使用Android Studio開發(fā)的系統(tǒng)應(yīng)用。原生android automotive中的系統(tǒng)應(yīng)用則是直接在android.bp中將CarLib引入,可以參考Settings/Android.bp第81行。
使用 Car API
Car API 的使用并不復(fù)雜,大致有以下幾個步驟。
通過Car.createCar()
方法可以創(chuàng)建出Car的對象。
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
Car carApiClient = Car.createCar(context, mCarServiceConnection);
}
通過getPackageManager().hasSystemFeature(String string)判斷系統(tǒng)是否支持特定的模塊功能
Car.createCar()
需要傳入ServiceConnection
,并在service連接成功后,獲取想要的Manager實例,實現(xiàn)方式如下:
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) {
}
};
構(gòu)建出Car對象后還需要調(diào)用connect()
才會連接到CarService
上。
carApiClient.connect();
connect()
只能調(diào)用一次,如果當(dāng)前已經(jīng)處于連接狀態(tài),再次調(diào)用connect()
會拋出異常,client如果沒有捕獲該異常,則會引起client端程序崩潰(血的教訓(xùn)!)。
@Deprecated
public void connect() throws IllegalStateException {
synchronized (mLock) {
if (mConnectionState != STATE_DISCONNECTED) {
throw new IllegalStateException("already connected or connecting");
}
mConnectionState = STATE_CONNECTING;
startCarService();
}
}
與connect()
對應(yīng)的還有disconnect()
。
carApiClient.disconnect();
不知道你有沒有注意到,connect()
被標(biāo)記為Deprecated過時的方法了。
這是因為在android 10 以后,Google改寫了Car API的使用方式,Android 10以后構(gòu)建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的調(diào)用方式由異步方法改為了同步方法,保留了disconnect()
,但是不再需要調(diào)用connect()
,這樣使用起來更簡單。
這種調(diào)用方式是樂觀的認(rèn)為CarService
不會發(fā)生異常,與CarService
的連接也不會斷開。但是如果CarService
發(fā)生異常,連接被斷開的話,client端調(diào)用方就會直接被殺死,使用下面這種調(diào)用方式可以避免這種情況。
Car car = Car.createCar(this, workThreadHandler, 2000, new Car.CarServiceLifecycleListener() {
@Override
public void onLifecycleChanged(@NonNull Car car, boolean ready) {
// ready 在Service斷開連接時會變?yōu)閒alse
if (ready) {
} else {
// CarService 發(fā)生異常或連接被斷開了,需要client端處理。
}
}
});
為什么上面的那種調(diào)用方式會導(dǎo)致client端的進(jìn)程被殺死呢?這就需要我們繼續(xù)深入的探究一下Car Api是如何實現(xiàn)的。
Car API 實現(xiàn)原理
探討Car API的實現(xiàn)原理我們可以它的入口類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)
在實現(xiàn)上是直接調(diào)用了createCar(context, handler)
,如下所示:
public static Car createCar(Context context) {
return createCar(context, (Handler) null);
}
createCar(context, handler)
與createCar(context, handler, waitTimeoutMs, statusChangeListener)
之間則沒有調(diào)用關(guān)系,各自有各自的實現(xiàn)方式,但是邏輯上大致相同,并且第三種的createCar(context, handler, waitTimeoutMs, statusChangeListener)
邏實現(xiàn)上要更復(fù)雜一些。所以我們直接看createCar(context, handler, waitTimeoutMs, statusChangeListener)
是實現(xiàn)的就可以了。
- createCar(context, handler, waitTimeoutMs, statusChangeListener)
Handler handler:將所有CarXXXManager事件發(fā)送到此handler。但是statusChangeListener
將始終調(diào)度到主線程。傳遞null會導(dǎo)致將所有CarXXXManager回調(diào)發(fā)送到主線程。
long waitTimeoutMs:將其設(shè)置為CAR_WAIT_TIMEOUT_DO_NOT_WAIT
則不等待CarService
連接就緒。將此設(shè)置為CAR_WAIT_TIMEOUT_WAIT_FOREVER
將阻塞調(diào)用,直到CarService
連接成功為止。
設(shè)置的值大于0則為超時時間,當(dāng)存在有限的超時時間時,返回的Car對象不能保證是可用的。
CarServiceLifecycleListener statusChangeListener: 監(jiān)聽CarService
是否連接就緒。
createCar
在實現(xiàn)流程上可以分為三個部分:
第一步,計算出綁定CarService
的最大重試次數(shù)。這個次數(shù)決定了后面,多久會顯示連接異常的日志。
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;
}
}
...
}
第二步也是最關(guān)鍵的一步,構(gòu)造出Car對象并返回給調(diào)用方,同時將狀態(tài)通過statusChangeListener
回調(diào)給調(diào)用方。正常流程下到createCar()方法執(zhí)行到這里就已經(jīng)結(jié)束了。
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可以為空,構(gòu)造方法對于空service是安全的。
car = new Car(context, ICar.Stub.asInterface(service), null, statusChangeListener,
handler);
}
if (service != null) {
if (!started) {
car.dispatchCarReadyToMainThread(isMainThread);
car.startCarService();
// 正常流程下,while (true)循環(huán)執(zhí)行到這里就結(jié)束了,后面的方法只有CarService啟動出現(xiàn)異常時才會出現(xiàn)。
return car;
}
break;
}
if (!started) {
car.startCarService();
started = true;
}
// 如果連接失敗,每隔50毫秒重試一次,嘗試達(dá)到一定的閾值后,日志上會顯示異常
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;
}
}
最后一步,主要是應(yīng)對一些異常情況,正常情況不會觸發(fā)。
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 已經(jīng)處理了一切,直接返回 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()
方法中分發(fā)Car實例狀態(tài)時,會調(diào)用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) {
// 綁定失敗時的重試機(jī)制
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 {
// 綁定成功時要取消重試機(jī)制
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
監(jiān)聽與CarService
的連接狀態(tài),并處理service連接成功與連接斷開的情況。
1)連接成功:由于在createCar中已經(jīng)創(chuàng)建好了mService,所以正常流程下,執(zhí)行到return就結(jié)束了,后面流程基本都是出現(xiàn)異常觸發(fā)了重連。
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; // 這不應(yīng)該發(fā)生
}
if (mService != null && mService.asBinder().equals(newService.asBinder())) {
// 由于在createCar中已經(jīng)創(chuàng)建好了mService,所以正常流程下,執(zhí)行到這一步就結(jié)束了
return;
}
mConnectionState = STATE_CONNECTED;
mService = newService;
}
// 分發(fā)連接狀態(tài)
if (mStatusChangeCallback != null) {
mStatusChangeCallback.onLifecycleChanged(Car.this, true);
} else if (mServiceConnectionListenerClient != null) {
mServiceConnectionListenerClient.onServiceConnected(name, service);
}
}
...
};
2)連接斷開:分發(fā)Car對象的狀態(tài),此時Client不應(yīng)該再使用Car的實例。所以如果Client端調(diào)用createCar()時沒有監(jiān)聽連接狀態(tài),Car Api會觸發(fā)finishClient()
,直接殺死client端。
private final ServiceConnection mServiceConnectionListener = new ServiceConnection() {
...
@Override
public void onServiceDisconnected(ComponentName name) {
// 重新啟動后,CarService可以接收功能更改。
mFeatures.resetCache();
synchronized (mLock) {
if (mConnectionState == STATE_DISCONNECTED) {
// 當(dāng)客戶端調(diào)用在 onServiceDisconnected 調(diào)用之前斷開連接時,可能會發(fā)生這種情況。
return;
}
handleCarDisconnectLocked();
}
if (mStatusChangeCallback != null) {
mStatusChangeCallback.onLifecycleChanged(Car.this, false);
} else if (mServiceConnectionListenerClient != null) {
mServiceConnectionListenerClient.onServiceDisconnected(name);
} else {
// client端沒有正確處理CarService會重新啟動的情況,因此直接殺死client端
finishClient();
}
}
};
在finishClient()
中會根據(jù)傳入client傳入的context類型,執(zhí)行不同的操作。
情景一:context = null,在Client端拋出異常。
情景二:context 是 Activity,結(jié)束該Activity,不會終止Client端的進(jìn)程。
情景三:context 是 Service,終止Client端的進(jìn)程。
情景四:context 不是以上的情況,終止Client端的進(jìn)程。
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()
這種機(jī)制的存在,所以調(diào)用方應(yīng)該要監(jiān)聽CarService的連接狀態(tài)。
最后我們再看一下getCarManager()
這個方法是如何實現(xiàn)的。
getCarManager()
實現(xiàn)機(jī)制上利用了BinderPool的思路,使用ICar.aidl
的getService()
來獲取Server端的Binder對象,然后將Binder對象封裝在Manager里面,同時將Manager對象緩存在一個Map集合中,后續(xù)就可以從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的實現(xiàn)過和原理了。注意在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端實現(xiàn)的,那么答案就需要去CarService
中尋找了。
CarService 的實現(xiàn)原理
想要說清楚CarService
實現(xiàn)方式,我們需要搞明白CarService
是怎么啟動的。
CarService 啟動流程
CarService
作為Android Automotive的核心服務(wù),它是在SystemServer
中啟動的,SystemServer
會在startOtherServices()
方法中讓SystemServiceManager
先通過反射的形式創(chuàng)建出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
中調(diào)用StartCarServiceHelperService
的onStart()
方法。
CarServiceHelperService
是CarService
的SystemService端的配套服務(wù)。
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
進(jìn)入啟動時序后,會onCreate()
方法中進(jìn)行一系列的自身的初始化操作,步驟如下:
1)通過HIDL接口獲取到HAL層的IHwBinder對象-IVehicle
,與AIDL的用法類似,必須持有IHwBinder對象我們才可以與Vehicle HAL層進(jìn)行通信。有關(guān)HIDL、VechicleHAL以后都會單獨介紹。
2)創(chuàng)建ICarImpl對象,并調(diào)用init
方法,它就是ICar.aidl
接口的實現(xiàn)類,我們需要通過它才能拿到其他的Service的IBinder對象。
3)將ICar.aidl
的實現(xiàn)類添加到ServiceManager中。這就解答了我們在Car API中疑問。
4)設(shè)定SystemProperty,將CarService
設(shè)定為創(chuàng)建完成狀態(tài),只有包含CarService
在內(nèi)的所有的核心Service都完成初始化,才能結(jié)束開機(jī)動畫并發(fā)送開機(jī)廣播。
@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
的實現(xiàn),如下所示:
1)創(chuàng)建各個核心服務(wù)對象。
2)把服務(wù)對象緩存到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) {
...
// 創(chuàng)建 核心服務(wù)對象
mCarPowerManagementService = new CarPowerManagementService(mContext, mHal.getPowerHal(),
systemInterface, mCarUserService);
...
// 將重要的服務(wù)緩存到 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);
// 將創(chuàng)建的服務(wù)對象依次添加到一個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)將服務(wù)對象放置一個list中。這樣init方法中就可以以循環(huán)的形式直接調(diào)用服務(wù)對象的init,而不需要一個個調(diào)用。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");
// 初始化所有服務(wù)
for (CarServiceBase service : mAllServices) {
service.init();
}
traceEnd();
}
4)最后實現(xiàn)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;
}
}
總結(jié)一下CarService
的啟動時序如下所示:
總結(jié)
本篇講解了CarService
的總體結(jié)構(gòu),以及Car API 的實現(xiàn)原理,CarService
中實現(xiàn)的功能非常龐大,就像文章中反復(fù)在強(qiáng)調(diào)的那樣,在CarService
實現(xiàn)的功能幾乎就是覆蓋整個車載Framework的核心。
然而現(xiàn)實中為了保證各個核心服務(wù)的穩(wěn)定性,同時降低CarService
協(xié)同開發(fā)的難度,一般會選擇將一些重要的服務(wù)拆分單獨作為一個獨立的Service運行在獨立的進(jìn)程中,導(dǎo)致有的車機(jī)系統(tǒng)中CarService
只實現(xiàn)了CarPropertyService
的功能。
文中提到的其他核心Service,會在以后的時間里逐個介紹,感謝你的閱讀,希望對你有所幫助。