目前許多車輛架構都包含多個電子控制單元 (ECU),這些 ECU 位於資訊娛樂系統之外,用於控制人體工學,例如座椅設定和後視鏡調整。在啟動 Android 資訊娛樂系統前,許多 ECU 都是以目前的硬體和電源架構為基礎。這些 ECU 可透過車輛硬體抽象層 (VHAL) 與 Android 資訊娛樂系統連接。
從 Android 11 開始,Android Automotive OS (AAOS) 在 VHAL 上導入了一組新的屬性,可用於建立、切換、移除及連結外部配件,方便識別使用者。舉例來說,這些新屬性可讓駕駛人將外部配件 (例如鍵盤遙控) 與 Android 使用者配對。之後,駕駛人靠近車輛時,ECU 便會喚醒並偵測鑰匙。 這個 ECU 會向 HAL 指出該由哪個 Android 使用者啟動資訊娛樂系統,進而縮短驅動程式等待 Android 使用者載入的時間。
啟用使用者 HAL
您必須明確啟用使用者 HAL 屬性,方法是確保系統屬性 android.car.user_hal_enabled
設為 true
。(您可以在 car.mk
檔案中執行這項操作,因此不必手動設定)。請將 UserHalService
傾印出來,確認 user_hal_enabled=true
已啟用:
$ adb shell dumpsys car_service --hal UserHalService|grep enabled user_hal_enabled=true
您也可以使用 adb shell
getprop android.car.user_hal_enabled
或 adb logcat
CarServiceHelper *:s
檢查 user_hal_enabled
。如果停用這項屬性,system_server
啟動時會顯示類似以下的訊息:
I CarServiceHelper: Not using User HAL
如要手動啟用 user_hal_enabled
,請設定 android.car.user_hal_enabled
系統屬性並重新啟動 system_server
:
$ adb shell setprop android.car.user_hal_enabled true $ adb shell stop && adb shell start
logcat
的輸出結果如下所示:
I CarServiceHelper: User HAL enabled with timeout of 5000ms D CarServiceHelper: Got result from HAL: OK I CarServiceHelper: User HAL returned DEFAULT behavior
使用者 HAL 屬性
使用者生命週期屬性
下列屬性提供使用者生命週期狀態的 HAL 資訊,以便在 Android 系統和外部 ECU 之間同步處理使用者生命週期。這些屬性會使用要求和回應通訊協定,其中 Android 系統會透過設定屬性值提出要求,而 HAL 會透過發出屬性變更事件做出回應。
注意:如果支援 User HAL,則必須實作以下所有屬性。
HAL 屬性 | 說明 |
---|---|
INITIAL_USER_INFO (讀取/寫入) |
Android 系統會呼叫這項屬性,以決定系統在裝置啟動或從「Suspend-to-RAM」(STR) 狀態恢復時,要啟動哪個 Android 使用者。在呼叫時,HAL 必須回應下列其中一個選項:
注意:如果 HAL 沒有回應,預設行為是在逾時期間 (預設為五秒) 後執行,這會延遲啟動。如果 HAL 回應,但 Android 系統無法執行動作 (例如,如果已達到使用者人數上限),則會採用預設行為。 範例:根據預設,Android 系統會在開機時,於最後一位活躍使用者中啟動。如果系統偵測到其他使用者的車鑰,ECU 會覆寫 HAL 屬性,並在啟動期間切換至以該指定使用者啟動 Android 系統。 |
SWITCH_USER (讀取/寫入) |
切換有效的前景 Android 使用者時,系統會呼叫這個屬性。Android 系統或 HAL 可以呼叫這個屬性,要求使用者切換。這三個工作流程如下:
現代化工作流程會使用兩階段提交方法,確保 Android 系統和外部 ECU 同步。Android 啟動切換時:
HAL 應等到 範例:駕駛人在行駛中嘗試在資訊娛樂系統 UI 中切換 Android 使用者。不過,由於兒童安全座椅設定與 Android 使用者綁定,因此在使用者切換時,座椅會移動。因此,控管座位的 ECU 不會確認切換開關,HAL 會回應失敗,且 Android 使用者不會切換。
舊版工作流程是在使用者切換後傳送的單向呼叫 (因此 HAL 無法封鎖切換)。系統只會在啟動時 (初始使用者切換後) 或呼叫
範例:如果應用程式使用 車輛工作流程源自 HAL,而非 Android 系統:
範例:Bob 使用 Alice 的車鑰開啟車門,HAL 則以 Alice 的使用者 ID 回覆 |
CREATE_USER (讀取/寫入) |
在使用 CarUserManager.createUser() API 建立新 Android 使用者時,Android 系統會呼叫這個屬性。
HAL 會以 範例:駕駛人輕觸 infotainment UI 圖示,建立新的 Android 使用者。這會將要求傳送至 HAL 和車輛子系統的其他子系統。ECU 會收到新建立使用者的通知。其他子系統和 ECU 隨後將他們的內部使用者 ID 與 Android 使用者 ID 建立關聯。 |
REMOVE_USER (僅限寫入) |
Android 系統會在移除 Android 使用者 (使用 CarUserManager.removeUser() 方法) 後呼叫此屬性。此為單向呼叫,但 HAL 不會有任何回應。 範例:駕駛人在資訊娛樂 UI 中輕觸來移除現有的 Android 使用者。系統會通知 HAL,並通知其他車輛子系統和 ECU 使用者移除作業,以便移除內部使用者 ID。 |
其他屬性
以下是與使用者生命週期狀態無關的其他資源。每個類別都可以實作,而無須支援 User HAL。
HAL 屬性 | 說明 |
---|---|
USER_IDENTIFICATION_ASSOCIATION (讀取/寫入) |
您可以使用這個屬性,將任何 Android 使用者與識別機制 (例如鑰匙圈或手機) 建立關聯。使用相同的屬性來建立 get 或 set 關聯。
範例:駕駛人輕觸資訊娛樂系統 UI 圖示,將用於開啟車輛的車鑰 ( |
輔助程式庫
在要求和回應訊息中使用的所有物件 (例如 UserInfo
、InitialUserInfoRequest
、InitialUSerInfoResponse
等) 都會透過 C++ struct
以高層級呈現,但移除作業必須整併為標準 VehiclePropValue
物件 (請參閱下方範例)。為簡化開發作業,AOSP 提供 C++ 輔助程式庫,可自動將 User HAL structs
轉換為 VehiclePropValue
(反之亦然)。
範例
INITIAL_USER_INFO
要求範例 (首次啟動時)
VehiclePropValue { // flattened from InitialUserInfoRequest prop: 299896583 // INITIAL_USER_INFO prop.values.int32Values: [0] = 1 // Request ID [1] = 1 // InitialUserInfoRequestType.FIRST_BOOT [2] = 0 // user id of current user [3] = 1 // flags of current user (SYSTEM) [4] = 1 // number of existing users [5] = 0 // existingUser[0].id [6] = 1 // existingUser[0].flags }
回應範例 (建立管理員使用者)
VehiclePropValue { // flattened from InitialUserInfoResponse prop: 299896583 // INITIAL_USER_INFO prop.values.int32Values: [0] = 1 // Request ID (must match request) [1] = 2 // InitialUserInfoResponseAction.CREATE [2] = -10000 // user id (not used on CREATE) [3] = 8 // user flags (ADMIN) prop.values.stringValue: "en-US||Car Owner" // User locale and user name }
SWITCH_USER
類別和屬性的實際名稱略有不同,但整體工作流程皆相同,如圖所示:
圖 1. 使用者 HAL 屬性工作流程。
現代化工作流程要求範例
VehiclePropValue { // flattened from SwitchUserRequest prop: 299896585 // SWITCH_USER prop.values.int32Values: [0] = 42 // Request ID [1] = 2 // SwitchUserMessageType::ANDROID_SWITCH ("modern") [2,3] = 11,0 // target user id (11) and flags (none in this case) [4,5] = 10,8 // current user id (10) and flags (ADMIN) [6] = 3 // number of existing users (0, 10, 11) [7,8] = 0,1 // existingUser[0] (id=0, flags=SYSTEM) [9,10] = 10,8 // existingUser[1] (id=10, flags=ADMIN) [11,12] = 11,0 // existingUser[2] (id=11, flags=NONE) }
現代化工作流程回應範例
VehiclePropValue { // flattened from SwitchUserResponse prop: 299896584 // SWITCH_USER prop.values.int32Values: [0] = 42 // Request ID (must match request) [1] = 3 // SwitchUserMessageType::VEHICLE_RESPONSE [2] = 1 // SwitchUserStatus::SUCCESS }
現代化工作流程的切換回應範例
此回應通常會在 Android 切換成功時發生:
VehiclePropValue { // flattened from SwitchUserRequest prop: 299896584 // SWITCH_USER prop.values.int32Values: [0] = 42 // Request ID (must match "pre"-SWITCH_USER request ) [1] = 5 // SwitchUserMessageType::ANDROID_POST_SWITCH [2,3] = 11,0 // target user id (11) and flags (none in this case) [4,5] = 11,0 // current user id (11) and flags (none in this case) [6] = 3 // number of existing users (0, 10, 11) [7,8] = 0,1 // existingUser[0] (id=0, flags=SYSTEM) [9,10] = 10,8 // existingUser[1] (id=10, flags=ADMIN) [11,12] = 11,0 // existingUser[2] (id=11, flags=NONE) }
現代化工作流程切換後的應變措施
這類回應通常會在 Android 切換失敗時發生:
VehiclePropValue { // flattened from SwitchUserRequest prop: 299896584 // SWITCH_USER prop.values.int32Values: [0] = 42 // Request ID (must match "pre"-SWITCH_USER request ) [1] = 5 // SwitchUserMessageType::ANDROID_POST_SWITCH [2,3] = 11,0 // target user id (11) and flags (none in this case) [4,5] = 10,8 // current user id (10) and flags (ADMIN) [6] = 3 // number of existing users (0, 10, 11) [7,8] = 0,1 // existingUser[0] (id=0, flags=SYSTEM) [9,10] = 10,8 // existingUser[1] (id=10, flags=ADMIN) [11,12] = 11,0 // existingUser[2] (id=11, flags=NONE) }
舊版工作流程要求示例
VehiclePropValue { // flattened from SwitchUserRequest prop: 299896584 // SWITCH_USER prop.values.int32Values: [0] = 2 // Request ID [1] = 1 // SwitchUserMessageType::LEGACY_ANDROID_SWITCH [2,3] = 10,8 // target user id (10) and flags (ADMIN) [4,5] = 0,1 // current user id (0) and flags (SYSTEM) [6] = 3 // number of existing users (0, 10, 11) [7,8] = 0,1 // existingUser[0] (id=0, flags=SYSTEM) [9,10] = 10,8 // existingUser[1] (id=10, flags=ADMIN) [11,12] = 11,0 // existingUser[2] (id=11, flags=NONE) }
車輛工作流程要求示例
VehiclePropValue { // flattened from SwitchUserRequest prop: 299896584 // SWITCH_USER prop.values.int32Values: [0] = -108 // Request ID (must be negative) [1] = 4 // SwitchUserMessageType::VEHICLE_REQUEST [2] = 11 // target user id }
舊版工作流程的切換後回應
這個回應通常會在 Android 切換成功時發生:
VehiclePropValue { // flattened from SwitchUserRequest prop: 299896584 // SWITCH_USER prop.values.int32Values: [0] = -108 // Request ID (must match from vehicle request ) [1] = 5 // SwitchUserMessageType::ANDROID_POST_SWITCH [2,3] = 11,0 // target user id (11) and flags (none in this case) [4,5] = 11,0 // current user id (11) and flags (none in this case) [6] = 3 // number of existing users (0, 10, 11) [7,8] = 0,1 // existingUser[0] (id=0, flags=SYSTEM) [9,10] = 10,8 // existingUser[1] (id=10, flags=ADMIN) [11,12] = 11,0 // existingUser[2] (id=11, flags=NONE) }
CREATE_USER
要求範例
VehiclePropValue { // flattened from CreateUserRequest prop: 299896585 // CREATE_USER prop.values.int32Values: [0] = 42 // Request ID [1,2] = 11,6 // Android id of the created user and flags (id=11, flags=GUEST, EPHEMERAL) [3,4] = 10,0 // current user id (10) and flags (none in this case) [5] = 3 // number of existing users (0, 10, 11) [6,7] = 0,1 // existingUser[0] (id=0, flags=SYSTEM) [8,9] = 10,8 // existingUser[1] (id=10, flags=ADMIN) [10,11] = 11,6 // newUser[2] (id=11, flags=GUEST,EPHEMERAL) }
回應範例
VehiclePropValue { // flattened from CreateUserResponse prop: 299896585 // CREATE_USER prop.values.int32Values: [0] = 42 // Request ID (must match request) [1] = 3 // CreateUserStatus::SUCCESS }
REMOVE_USER
要求範例
VehiclePropValue { // flattened from RemoveUserRequest prop: 299896586 // REMOVE_USER prop.values.int32Values: [0] = 42 // Request ID [1,2] = 11,0 // Android id of the removed user and flags (none in this case) [3,4] = 10,0 // current user id (10) and flags (none in this case) [5] = 2 // number of existing users (0, 10) [6,7] = 0,1 // existingUser[0] (id=0, flags=SYSTEM) [8,9] = 10,8 // existingUser[1] (id=10, flags=ADMIN) }
使用者 ID
設定範例 (與使用者 10 相關聯的索引鍵)
VehiclePropValue { // flattened from UserIdentificationSetRequest prop: 299896587 // USER_IDENTIFICATION_ASSOCIATION prop.values.int32Values: [0] = 43 // Request ID [1,2] = 10,0 // Android id (10) and flags (none in this case) [3] = 1 // number of associations being set [4] = 1 // 1st type: UserIdentificationAssociationType::KEY_FOB [5] = 1 // 1st value: UserIdentificationAssociationSetValue::ASSOCIATE_CURRENT_USER }