目前的許多車輛架構在資訊娛樂系統外部包含多個電子控制單元 (ECU),用於控制人體工學,例如座椅設定和後視鏡調節。基於目前的硬體和電源架構,許多 ECU 在基於 Android 的資訊娛樂系統啟動之前啟動。這些 ECU 可以透過車輛硬體抽象層 (VHAL)與基於 Android 的資訊娛樂系統進行互動。
從 Android 11 開始,Android Automotive OS (AAOS) 在 VHAL 上引入了一組新屬性,用於建立、切換、刪除和關聯外部配件以識別使用者。例如,這些新屬性使驅動程式能夠將外部配件(例如密鑰卡)與其 Android 用戶配對。然後,當駕駛員接近車輛時,ECU 被喚醒並偵測到鑰匙圈。該 ECU 向 HAL 指示資訊娛樂系統應啟動哪個 Android 用戶,從而減少驅動程式等待其 Android 用戶載入的時間。
啟用用戶 HAL
必須透過確保系統屬性android.car.user_hal_enabled
設定為true
來明確啟用使用者 HAL 屬性。 (這也可以在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 透過發出屬性變更事件來回應。
注意:當支援使用者 HAL 時,必須實現以下所有屬性。
哈爾屬性 | 描述 |
---|---|
INITIAL_USER_INFO (讀/寫) | Android 系統會呼叫此屬性來決定當裝置啟動或從掛起到 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 用戶不會切換。 Legacy 工作流程是在使用者切換後發送的單向呼叫(因此 HAL 無法阻止切換)。它僅在啟動時(初始使用者切換後)或呼叫 範例:如果應用程式使用 Vehicle 工作流程源自 HAL,而非 Android 系統:
範例: Bob 使用 Alice 的鑰匙圈打開汽車,HAL 使用 Alice 的使用者 ID 回覆 |
CREATE_USER (讀/寫) | 當建立新的 Android 使用者(使用CarUserManager.createUser() API)時,Android 系統會呼叫此屬性。 HAL 響應 範例:駕駛員點擊資訊娛樂 UI 圖示來建立新的 Android 用戶。這會向 HAL 和其餘車輛子系統發送請求。 ECU 會收到新建立的使用者的通知。然後,其他子系統和 ECU 將其內部使用者 ID 與 Android 使用者 ID 關聯起來。 |
REMOVE_USER (僅限寫入) | Android 系統在刪除 Android 使用者後呼叫此屬性(使用CarUserManager.removeUser() 方法)。這是一個單向呼叫 — HAL 不會做出任何回應。 範例:駕駛點擊以刪除資訊娛樂 UI 中的現有 Android 用戶。 HAL 會收到通知,其他車輛子系統和 ECU 也會收到用戶刪除的通知,以便他們可以刪除其內部用戶 ID。 |
附加屬性
以下是與使用者生命週期狀態無關的附加屬性。每個都可以在不支援用戶 HAL 的情況下實現。
哈爾地產 | 描述 |
---|---|
USER_IDENTIFICATION_ASSOCIATION (讀/寫) | 使用此屬性將任何 Android 使用者與識別機制(例如金鑰卡或電話)相關聯。使用相同的屬性來get 或set 關聯。範例:駕駛員點擊資訊娛樂 UI 圖標,將用於打開車輛的鑰匙圈 ( |
輔助庫
請求和回應訊息中使用的所有物件(例如UserInfo
、 InitialUserInfoRequest
、 InitialUSerInfoResponse
等)都具有使用 C++ struct
的高級表示,但刪除必須展平為標準VehiclePropValue
物件(請參閱下面的範例)。為了方便開發,AOSP 中提供了一個C++ 幫助程式庫,用於自動將 User HAL structs
轉換為VehiclePropValue
(反之亦然)。
例子
初始使用者資訊
請求範例(首次啟動時)
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 }
切換用戶
類別和屬性的實際名稱略有不同,但整體工作流程是相同的,如下所示:
圖 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) }
創建用戶
請求範例
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) }
使用者識別協會
設定範例(與使用者 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 }