【Android R】車載 Android 核心服務 - CarService 解析

語言: CN / TW / HK

theme: simplicity-green

封面座艙配圖 - 集度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 ServiceHAL Service再將資料處理後傳遞給MCUMCU通過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

汽車多使用者服務。在啟動時管理使用者。包括:

  1. 建立用作驅動程式的使用者。
  2. 建立用作乘客的使用者。
  3. 首次執行時建立輔助管理員使用者。
  4. 切換駕駛員。

  5. 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

用於實現CarOccupantZoneManagerAPI的服務。

  • 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

實現CarWatchdogManagerAPI的服務。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對應CarWatchdogServiceCarMediaManager對應CarMediaService

不過也有例外:CarInfoManagerCarSensorManagerCarHvacManagerCarCabinManagerCarVendorExtensionManager都對應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.aidlgetService()來獲取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中呼叫StartCarServiceHelperServiceonStart()方法。

CarServiceHelperServiceCarService的SystemService端的配套服務。

``` public SystemService startService(String className) { final Class 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 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,會在以後的時間裡逐個介紹,感謝你的閱讀,希望對你有所幫助。