用戶 HAL 屬性

許多當前的車輛架構在信息娛樂系統之外包含多個電子控制單元 (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來顯式啟用 User HAL 屬性。 (這也可以在car.mk文件中完成,因此不需要手動設置。)通過轉儲UserHalService檢查是否啟用了user_hal_enabled=true

$ adb shell dumpsys car_service --hal UserHalService|grep enabled
user_hal_enabled=true

您還可以使用檢查user_hal_enabled adb shell getprop android.car.user_hal_enabled 或adb logcat CarServiceHelper *:s 。如果該屬性被禁用, 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 必須使用以下選項之一進行響應:
  • Android 設置的默認行為(如果這是第一次啟動,則切換到最後使用的用戶或創建新用戶)。
  • 切換到現有用戶。
  • 創建一個新用戶(具有名稱、標誌、系統區域設置等可選屬性)並切換到該新用戶。

注意:如果 HAL 沒有響應,默認行為是在超時時間(默認為五 (5) 秒)後執行,這會延遲啟動。如果 HAL 確實回復了,但 Android 系統未能執行該操作(例如,如果已達到最大用戶數),則使用默認行為。

例如,默認情況下,Android 系統在啟動時以最後一個活動用戶啟動。如果檢測到不同用戶的密鑰卡,ECU 會覆蓋 HAL 屬性,並且在啟動期間,Android 系統會切換到在該指定用戶中啟動。

SWITCH_USER
(讀/寫)
該屬性在切換活躍的前台 Android 用戶時被調用。 Android 系統或 HAL 都可以調用該屬性來請求用戶切換。這三個工作流程是:
  • 現代的。開關從CarUserManager開始。
  • 遺產。切換從ActivityManager開始。
  • 車輛。由 HAL 調用以請求用戶切換。

Modern 工作流程使用兩階段提交方法來確保 Android 系統和外部 ECU 同步。當 Android 發起切換時:

  1. 檢查 HAL 以確定是否可以切換用戶。

    HAL 以SUCCESSFAILURE響應,以便 Android 知道是否繼續。

  2. 完成 Android 用戶切換。

    Android 向 HAL 發送ANDROID_POST_SWITCH響應以指示切換成功或失敗。

HAL 應等到ANDROID_POST_SWITCH響應之後更新其狀態以同步 ECU 或更新其他 HAL 屬性。

例如,在行駛過程中,駕駛員嘗試在信息娛樂 UI 中切換 Android 用戶。但是,由於汽車座椅設置與 Android 用戶相關聯,因此座椅會在用戶切換期間移動。因此,控制座椅的 ECU 不確認切換,HAL 以失敗響應,Android 用戶未切換。

Legacy 工作流是用戶切換後發送的單向調用(因此 HAL 無法阻止切換)。它僅在啟動時調用(在初始用戶切換之後)或調用ActivityManager.switchUser()而不是CarUserManager.switchUser()的應用程序。參考SettingsSystemUI應用程序已經使用後者,但如果 OEM 提供自己的 Settings 應用程序來切換用戶,則 OEM 應更改使用方式。

例如,如果一個應用使用ActivityManager.switchUser()來切換用戶,那麼會向 HAL 發送一個單向調用來通知用戶切換已經發生。

Vehicle 工作流程源自 HAL,而非 Android 系統:

  1. HAL 請求用戶切換。
  2. 系統完成安卓用戶切換。
  3. Android 向 HAL 發送ANDROID_POST_SWITCH響應以指示切換成功或失敗。

例如,Bob 使用 Alice 的密鑰卡打開汽車,HAL 使用 Alice 的用戶 ID 回复INITIAL_USER_INFO請求。接下來,生物識別傳感器 ECU 將駕駛員識別為 Bob,因此用戶 HAL 發送了一個SWITCH_USER請求以切換用戶。

CREATE_USER
(讀/寫)
此屬性由 Android 系統在創建新的 Android 用戶時調用(使用CarUserManager.createUser() API)。

HAL 以SUCCESSFAILURE響應。如果 HAL 響應失敗,Android 系統將刪除用戶。

例如,駕駛員點擊信息娛樂 UI 圖標來創建新的 Android 用戶。這會向 HAL 和其他車輛子系統發送請求。 ECU 被告知新創建的用戶。然後,其他子系統和 ECU 將其內部用戶 ID 與 Android 用戶 ID 相關聯。

REMOVE_USER
(只寫)
Android 系統會在移除 Android 用戶後調用此屬性(使用CarUserManager.removeUser() API)。

這是一個單向調用 - 預計 HAL 不會響應。

例如,駕駛員在信息娛樂 UI 中點擊以刪除現有的 Android 用戶。通知 HAL 並通知其他車輛子系統和 ECU 用戶刪除,以便他們可以刪除其內部用戶 ID。

附加屬性

以下是與用戶生命週期狀態無關的附加屬性。每個都可以在不支持用戶 HAL 的情況下實現。

HAL 屬性描述
USER_IDENTIFICATION_ASSOCIATION
(讀/寫)
使用此屬性可將任何 Android 用戶與識別機制相關聯,例如密鑰卡或電話。使用相同的屬性來getset關聯。

例如,駕駛員點擊信息娛樂 UI 圖標以將用於打開車輛的密鑰卡 (KEY_123) 與當前活動的 Android 用戶 (USER_11) 相關聯。

助手庫

請求和響應消息中使用的所有對象(例如UserInfoInitialUserInfoRequestInitialUSerInfoResponse等)都使用 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
}

切換用戶

類和屬性的實際名稱略有不同,但整體工作流程相同,如下圖所示:

工作流程

圖 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)
}

USER_IDENTIFICATION_ASSOCIATION

設置示例(與用戶 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
}