许多当前的车辆架构包含信息娱乐系统外部的多个电子控制单元 (ECU),这些电子控制单元控制人体工程学,例如座椅设置和后视镜调整。根据当前的硬件和电源架构,许多 ECU 在基于 Android 的信息娱乐系统启动之前就已启动。这些 ECU 可以通过 车辆硬件抽象层 (VHAL) 与基于 Android 的信息娱乐系统进行交互。
从 Android 11 开始,Android Automotive OS (AAOS) 在 VHAL 上引入了一组新的属性,用于创建、切换、移除外部配件以及将外部配件与用户关联,以识别用户。例如,这些新属性使驾驶员能够将其外部配件(例如钥匙遥控器)与自己的 Android 用户配对绑定。然后,当驾驶员靠近车辆时,ECU 会唤醒并检测钥匙遥控器。此 ECU 会向 HAL 指示信息娱乐系统应启动哪个 Android 用户,从而缩短驾驶员等待加载其 Android 用户的时间。
启用 User HAL
必须显式启用 User 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
User HAL 属性
用户生命周期属性
以下属性为用户生命周期状态提供 HAL 信息,从而实现 Android 系统和外部 ECU 之间的用户生命周期同步。这些属性使用请求和响应协议,其中 Android 系统通过设置属性值发出请求,HAL 通过发出属性更改事件进行响应。
注意:当支持 User 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 用户不会切换。 旧式工作流是在用户切换后发送的单向调用(因此 HAL 无法阻止切换)。它仅在启动时(初始用户切换后)或对于调用
示例:如果应用使用 车辆工作流源自 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 用户后(使用 CarUserManager.removeUser() 方法),Android 系统会调用此属性。这是一个单向调用,无需 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. User 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) }
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 }