当前的许多车辆架构在信息娱乐系统外部包含多个电子控制单元 (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 }