Nhiều cấu trúc xe hiện tại chứa nhiều đơn vị điều khiển điện tử (ECU) bên ngoài hệ thống thông tin giải trí để kiểm soát các yếu tố về công thái học, chẳng hạn như chế độ cài đặt chỗ ngồi và điều chỉnh gương. Dựa trên cấu trúc phần cứng và nguồn điện hiện tại, nhiều ECU sẽ khởi động trước khi hệ thống thông tin giải trí dựa trên Android khởi động. Các ECU này có thể giao tiếp với một hệ thống thông tin giải trí dựa trên Android thông qua lớp trừu tượng phần cứng xe (VHAL).
Kể từ Android 11, Android Automotive OS (AAOS) đã ra mắt một bộ thuộc tính mới trên VHAL để tạo, chuyển đổi, xoá và liên kết các phụ kiện bên ngoài nhằm xác định người dùng. Ví dụ: những thuộc tính mới này cho phép người lái xe ghép nối một phụ kiện bên ngoài (chẳng hạn như thiết bị điều khiển từ xa cầm tay) với người dùng Android. Sau đó, khi người lái xe đến gần xe, ECU sẽ thức dậy và phát hiện chìa khoá điện tử. ECU này cho HAL biết người dùng Android nào sẽ bắt đầu khởi động thông tin giải trí, giúp giảm thời gian người lái xe chờ người dùng Android tải.
Bật HAL (Lớp trừu tượng phần cứng) cho người dùng
Bạn phải bật rõ ràng các thuộc tính HAL của người dùng bằng cách đảm bảo thuộc tính hệ thống android.car.user_hal_enabled
được đặt thành true
.
(Bạn có thể thực hiện việc này trong tệp car.mk
để không cần phải đặt theo cách thủ công.) Kiểm tra để đảm bảo user_hal_enabled=true
đã được bật bằng cách đổ UserHalService
:
$ adb shell dumpsys car_service --hal UserHalService|grep enabled user_hal_enabled=true
Bạn cũng có thể kiểm tra user_hal_enabled
bằng cách sử dụng adb shell
getprop android.car.user_hal_enabled
hoặc adb logcat
CarServiceHelper *:s
. Nếu thuộc tính này bị tắt, một thông báo như sau sẽ hiển thị khi system_server
khởi động:
I CarServiceHelper: Not using User HAL
Để bật user_hal_enabled
theo cách thủ công, hãy đặt thuộc tính hệ thống android.car.user_hal_enabled
và khởi động lại system_server
:
$ adb shell setprop android.car.user_hal_enabled true $ adb shell stop && adb shell start
Kết quả logcat
sẽ xuất hiện như sau:
I CarServiceHelper: User HAL enabled with timeout of 5000ms D CarServiceHelper: Got result from HAL: OK I CarServiceHelper: User HAL returned DEFAULT behavior
Thuộc tính HAL của người dùng
Thuộc tính vòng đời người dùng
Các thuộc tính sau đây cung cấp thông tin HAL cho các trạng thái vòng đời của người dùng, cho phép đồng bộ hoá vòng đời của người dùng giữa hệ thống Android và ECU bên ngoài. Các thuộc tính này sử dụng giao thức yêu cầu và phản hồi, trong đó hệ thống Android đưa ra yêu cầu bằng cách đặt giá trị thuộc tính và HAL phản hồi bằng cách phát hành sự kiện thay đổi thuộc tính.
Lưu ý: Khi giao diện HAL của người dùng được hỗ trợ, bạn phải triển khai tất cả các thuộc tính sau.
Thuộc tính HAL | Mô tả |
---|---|
INITIAL_USER_INFO (đọc/ghi) |
Hệ thống Android gọi thuộc tính này để xác định người dùng Android nào mà hệ thống sẽ khởi động khi thiết bị khởi động hoặc tiếp tục từ trạng thái Tạm ngưng vào RAM (STR). Khi được gọi, HAL phải phản hồi bằng một trong các lựa chọn sau:
Lưu ý: Nếu HAL không phản hồi, hành vi mặc định sẽ là thực thi sau một khoảng thời gian chờ (mặc định là 5 giây), điều này sẽ làm chậm quá trình khởi động. Nếu HAL phản hồi nhưng hệ thống Android không thực thi được hành động (ví dụ: nếu đã đạt đến số lượng người dùng tối đa), thì hành vi mặc định sẽ được sử dụng. Ví dụ: Theo mặc định, hệ thống Android sẽ khởi động trong người dùng đang hoạt động gần đây nhất khi khởi động. Nếu phát hiện thấy một chìa khoá thông minh cho một người dùng khác, ECU sẽ ghi đè thuộc tính HAL và trong quá trình khởi động, hệ thống Android sẽ chuyển sang khởi động trong người dùng đã chỉ định đó. |
SWITCH_USER (đọc/ghi) |
Thuộc tính này được gọi khi chuyển đổi người dùng Android đang hoạt động ở nền trước.
Hệ thống Android hoặc HAL có thể gọi thuộc tính này để yêu cầu người dùng chuyển đổi. Ba quy trình công việc đó là:
Quy trình làm việc hiện đại sử dụng phương pháp cam kết hai giai đoạn để đảm bảo hệ thống Android và ECU bên ngoài được đồng bộ hoá. Khi Android khởi tạo nút chuyển:
HAL phải đợi cho đến khi phản hồi Ví dụ: Khi đang di chuyển, người lái xe cố gắng chuyển đổi người dùng Android trong giao diện người dùng thông tin giải trí. Tuy nhiên, vì chế độ cài đặt ghế ô tô được liên kết với người dùng Android, nên ghế sẽ di chuyển trong quá trình chuyển đổi người dùng. Do đó, ECU điều khiển ghế không xác nhận công tắc, HAL sẽ phản hồi khi gặp lỗi và người dùng Android không được chuyển.
Quy trình làm việc cũ là một lệnh gọi một chiều được gửi sau khi người dùng được chuyển đổi (vì vậy, HAL không thể chặn nút chuyển). Phương thức này chỉ được gọi khi khởi động (sau khi người dùng chuyển đổi ban đầu) hoặc đối với các ứng dụng gọi
Ví dụ: Nếu một ứng dụng sử dụng Quy trình công việc của Xe bắt nguồn từ HAL, chứ không phải từ hệ thống Android:
Ví dụ: Bob dùng chìa khoá thông minh của Alice để mở xe và HAL trả lời yêu cầu |
CREATE_USER (đọc/ghi) |
Thuộc tính này được hệ thống Android gọi khi một người dùng Android mới được tạo (sử dụng API CarUserManager.createUser() ).
HAL phản hồi bằng Ví dụ: Người lái xe nhấn vào biểu tượng giao diện người dùng thông tin giải trí để tạo một người dùng Android mới. Thao tác này sẽ gửi một yêu cầu đến HAL và các hệ thống con còn lại của xe. ECU được thông báo về người dùng mới tạo. Sau đó, các hệ thống con và ECU khác sẽ liên kết mã nhận dạng người dùng nội bộ với mã nhận dạng người dùng Android. |
REMOVE_USER (chỉ GHI) |
Hệ thống Android gọi thuộc tính này sau khi người dùng Android bị xoá (bằng phương thức CarUserManager.removeUser() ).
Đây là lệnh gọi một chiều, không có phản hồi nào từ HAL. Ví dụ: Người lái xe nhấn để xoá một người dùng Android hiện có trong giao diện người dùng thông tin giải trí. HAL sẽ được thông báo, đồng thời các hệ thống phụ và ECU khác của xe sẽ được thông báo về hoạt động xoá người dùng để họ có thể xoá mã nhận dạng người dùng nội bộ. |
Các thuộc tính bổ sung
Sau đây là các thuộc tính bổ sung, không liên quan đến trạng thái vòng đời của người dùng. Bạn có thể triển khai từng phương thức mà không cần hỗ trợ HAL người dùng.
Thuộc tính HAL | Mô tả |
---|---|
USER_IDENTIFICATION_ASSOCIATION (đọc/ghi) |
Sử dụng thuộc tính này để liên kết bất kỳ người dùng Android nào với một cơ chế nhận dạng, chẳng hạn như chìa khoá thông minh hoặc điện thoại. Sử dụng thuộc tính này để liên kết get hoặc set .
Ví dụ: Người lái xe nhấn vào biểu tượng giao diện người dùng thông tin giải trí để liên kết khoá thông minh dùng để mở xe ( |
Thư viện trợ giúp
Tất cả đối tượng được sử dụng trong thông báo yêu cầu và phản hồi (chẳng hạn như UserInfo
, InitialUserInfoRequest
, InitialUSerInfoResponse
, v.v.) đều có bản trình bày cấp cao bằng cách sử dụng struct
C++, nhưng việc xoá phải được làm phẳng thành các đối tượng VehiclePropValue
tiêu chuẩn (xem ví dụ bên dưới). Để dễ dàng phát triển, một thư viện trình trợ giúp C++ được cung cấp trong AOSP để tự động chuyển đổi User HAL structs
thành VehiclePropValue
(và ngược lại).
Ví dụ
INITIAL_USER_INFO
Ví dụ về yêu cầu (khi khởi động lần đầu)
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 }
Ví dụ về phản hồi (tạo người dùng Quản trị viên)
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
Tên thực tế của các lớp và thuộc tính có khác biệt nhỏ nhưng quy trình làm việc tổng thể vẫn giống nhau, như minh hoạ trong hình:
Hình 1. Quy trình làm việc của thuộc tính HAL người dùng.
Ví dụ về yêu cầu quy trình công việc hiện đại
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) }
Ví dụ về phản hồi của quy trình công việc hiện đại
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 }
Ví dụ về phản hồi sau khi chuyển đổi quy trình công việc hiện đại
Phản hồi này thường xảy ra khi một nút chuyển Android thành công:
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) }
Phản hồi sau khi chuyển đổi quy trình công việc hiện đại
Phản hồi này thường xảy ra khi nút chuyển Android không hoạt động:
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) }
Ví dụ về yêu cầu quy trình công việc cũ
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) }
Ví dụ về yêu cầu quy trình công việc của xe
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 }
Phản hồi sau khi chuyển đổi quy trình làm việc cũ
Phản hồi này thường xảy ra khi một nút chuyển Android thành công:
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) }
NGƯỜI DÙNG TẠO
Ví dụ về yêu cầu
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) }
Ví dụ về phản hồi
VehiclePropValue { // flattened from CreateUserResponse prop: 299896585 // CREATE_USER prop.values.int32Values: [0] = 42 // Request ID (must match request) [1] = 3 // CreateUserStatus::SUCCESS }
REMOVE_USER
Ví dụ về yêu cầu
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) }
NGƯỜI DÙNG_IDENTIFICATION_ASSOCIATION
Ví dụ về bộ thiết lập (vòng tay khoá được liên kết với Người dùng 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 }