用戶 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來明確啟用使用者 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_enabledadb 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 必須使用下列選項之一進行回應:
  • Android 設定的預設行為(切換到上次使用的使用者或建立新使用者(如果這是第一次啟動)。
  • 切換到現有用戶。
  • 建立一個新使用者(具有名稱、標誌、系統區域設定等可選屬性)並切換到該新使用者。

注意:如果 HAL 沒有回應,預設行為是在逾時時間(預設為五秒)後執行,這會延遲啟動。如果 HAL 確實回复,但 Android 系統無法執行該操作(例如,如果已達到最大用戶數),則使用預設行為。

範例:預設情況下,Android 系統在啟動時會以最後一個活動使用者啟動。如果偵測到不同使用者的金鑰卡,ECU 會覆寫 HAL 屬性,並且在啟動過程中,Android 系統會切換到以該指定使用者啟動。

SWITCH_USER
(讀/寫)
當切換活動前台 Android 使用者時會呼叫此屬性。此屬性可以由 Android 系統或 HAL 呼叫來請求使用者切換。這三個工作流程是:
  • 現代的。切換從CarUserManager開始。
  • 遺產。 Switch是從ActivityManager開始的。
  • 車輛。由 HAL 呼叫以請求用戶切換。

現代工作流程使用兩階段提交方法來確保 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 提供自己的設定應用程式來切換用戶,則 OEM 應更改用法。

範例:如果應用程式使用ActivityManager.switchUser()切換用戶,則會向 HAL 發送單向呼叫以通知已發生用戶切換。

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

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

範例: Bob 使用 Alice 的鑰匙圈打開汽車,HAL 使用 Alice 的使用者 ID 回覆INITIAL_USER_INFO請求。接下來,生物辨識感測器 ECU 將駕駛員識別為 Bob,因此 User HAL 發送SWITCH_USER請求來切換使用者。

CREATE_USER
(讀/寫)
當建立新的 Android 使用者(使用CarUserManager.createUser() API)時,Android 系統會呼叫此屬性。

HAL 響應SUCCESSFAILURE 。如果 HAL 回應失敗,Android 系統會刪除該使用者。

範例:駕駛員點擊資訊娛樂 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 使用者與識別機制(例如金鑰卡或電話)相關聯。使用相同的屬性來getset關聯。

範例:駕駛員點擊資訊娛樂 UI 圖標,將用於打開車輛的鑰匙圈 ( KEY_123 ) 與當前活動的 Android 用戶 ( USER_11 ) 相關聯。

輔助庫

請求和回應訊息中使用的所有物件(例如UserInfoInitialUserInfoRequestInitialUSerInfoResponse等)都具有使用 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
}