Thuộc tính HAL của người dùng

Nhiều kiến trúc xe hiện tại có nhiều bộ điều khiển điện tử (ECU) bên ngoài hệ thống thông tin giải trí điều khiển các thiết bị công thái học, chẳng hạn như ghế ngồi chế độ cài đặt và điều chỉnh đồng bộ hoá hai chiều. Dựa trên phần cứng và nguồn hiện tại nhiều kiến trúc, nhiều ECU được kích hoạt trước hệ thống thông tin giải trí dựa trên Android đã được kích hoạt. 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 hệ thống thông qua Lớp trừu tượng về phần cứng xe (VHAL).

Kể từ Android 11, Android Automotive OS (AAOS) đã giới thiệu một bộ tính năng mới gồm các thuộc tính trên VHAL để tạo, chuyển đổi, xoá và liên kết phụ kiện bên ngoài để nhận dạng 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 của mình. Sau đó, khi người lái xe đến gần xe, bộ ECU sẽ đánh thức và phát hiện chìa khoá điện tử. ECU này cho HAL biết thông tin giải trí mà Người dùng Android nên khởi động để giảm thời gian người lái xe đợi thiết bị Android Người dùng cần 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 các thuộc tính HAL của người dùng một cách rõ ràng bằng cách đảm bảo hệ thống thuộc tính android.car.user_hal_enabled được đặt thành true. (Bạn cũng có thể thực hiện việc này trong tệp car.mk để không cần đặt theo cách thủ công). Kiểm tra để đảm bảo rằng bạn đã bật user_hal_enabled=true bằng kết xuất 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 cơ sở lưu trú bị vô hiệu hoá, một thông báo như sẽ hiển thị thông tin sau đây 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 rồi 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 của người dùng

Các thuộc tính sau cung cấp thông tin HAL cho Vòng đời của người dùng Trạng thái cho phép đồng bộ hoá vòng đời người dùng giữa hệ thống Android và một bộ ECU bên ngoài. Các thuộc tính này sử dụng một 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 đưa ra một sự kiện thay đổi thuộc tính.

Lưu ý: Khi HAL người dùng được hỗ trợ, tất cả các điều sau phải được triển khai.

Thuộc tính HAL Mô tả
INITIAL_USER_INFO
(ĐỌC/GHI)
Thuộc tính này được hệ thống Android gọi để xác định xem Android nào Người dùng mà hệ thống khởi động khi thiết bị khởi động hoặc tiếp tục từ Tạm ngưng với RAM (STR). Khi được gọi, HAL phải phản hồi bằng một trong các tuỳ chọn sau:
  • Hành vi mặc định do Android đặt (chuyển sang hành vi sử dụng gần đây nhất Người dùng hoặc tạo Người dùng mới nếu đây là lần khởi động đầu tiên).
  • Chuyển sang một Người dùng hiện có.
  • Tạo một Người dùng mới (có các thuộc tính không bắt buộc như tên, cờ, hệ thống ngôn ngữ, v.v.) và chuyển sang Người dùng mới đó.

Lưu ý: Nếu HAL không phản hồi, thì chế độ mặc định sẽ là thực thi sau một khoảng thời gian chờ (5 giây theo mặc định) để trì hoãn quá trình khởi động. Nếu HAL trả lời nhưng hệ thống Android không thực thi được thao tác đó (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 khởi động trong người dùng đang hoạt động khi khởi động. Nếu thiết bị điều khiển từ xa cầm tay của một Người dùng khác được phát hiện, thì ECU ghi đè thuộc tính HAL và trong khi khởi động, hệ thống Android sẽ chuyển sang trong Người dùng được 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 để yêu cầu chuyển đổi Người dùng. Ba quy trình công việc này là:
  • Hiện đại. Đã bắt đầu chuyển đổi từ CarUserManager.
  • Cũ. Đã bắt đầu chuyển đổi từ ActivityManager.
  • Xe cộ. Do HAL (Lớp trừu tượng phần cứng) gọi để yêu cầu chuyển đổi Người dùng.

Quy trình làm việc hiện đại sử dụng phương pháp cam kết 2 giai đoạn nhằm đảm bảo Hệ thống Android và ECU bên ngoài được đồng bộ hoá. Khi Android bắt đầu nút chuyển:

  1. Kiểm tra HAL để xác định xem có thể chuyển đổi Người dùng hay không.

    HAL phản hồi bằng SUCCESS hoặc FAILURE để Android sẽ biết có nên tiếp tục hay không.

  2. Hoàn tất quá trình chuyển đổi Người dùng Android.

    Android gửi phản hồi ANDROID_POST_SWITCH đến HAL để cho biết nút chuyển thành công hay không thành công.

HAL sẽ đợi cho đến sau ANDROID_POST_SWITCH phản hồi để cập nhật trạng thái nhằm đồng bộ hoá ECU hoặc cập nhật HAL khác các thuộc tính.

Ví dụ: Khi đang chuyển động, 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ì ghế ngồi trên ô tô được liên kết với Người dùng Android, ghế sẽ di chuyển trong Chuyển đổi người dùng. Do đó, ECU điều khiển ghế không xác nhận việc chuyển đổi, HAL phản hồi với lỗi và Người dùng Android không được chuyển đổi.

Quy trình làm việc cũ là cuộc gọi một chiều được gửi sau khi Người dùng được chuyển đổi (để HAL không chặn công tắc). Phương thức này chỉ được gọi khi khởi động (sau khi chuyển đổi người dùng ban đầu) hoặc cho các ứng dụng gọi ActivityManager.switchUser() thay vì CarUserManager.switchUser() Tham chiếu Ứng dụng SettingsSystemUI đã sử dụng nhưng nếu OEM cung cấp ứng dụng Cài đặt riêng để chuyển đổi Người dùng, OEM nên thay đổi cách sử dụng.

Ví dụ: Nếu một ứng dụng sử dụng ActivityManager.switchUser() thành chuyển đổi Người dùng, thì cuộc gọi một chiều sẽ được gửi đến HAL để thông báo rằng Người dùng đang sử dụng đã diễn ra.

Quy trình làm việc của Xe bắt nguồn từ HAL (Lớp trừu tượng phần cứng), không phải từ hệ thống Android:

  1. HAL yêu cầu một nút chuyển Người dùng.
  2. Hệ thống hoàn tất quá trình chuyển đổi người dùng Android.
  3. Android gửi phản hồi ANDROID_POST_SWITCH đến HAL để cho biết chuyển đổi thành công hoặc không thành công.

Ví dụ: Bob dùng thiết bị điều khiển từ xa cầm tay của Alice để mở ô tô và HAL đã trả lời yêu cầu INITIAL_USER_INFO bằng Mã nhận dạng người dùng của Alice. Tiếp theo, ECU cảm biến sinh trắc học đã xác định người lái xe là Bob, nên HAL của người dùng đã gửi một yêu cầu SWITCH_USER để chuyển đổi người dùng.

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 (bằng API CarUserManager.createUser()).

HAL phản hồi bằng SUCCESS hoặc FAILURE. Nếu HAL phản hồi với lỗi, hệ thống Android sẽ xoá Người dùng.

Ví dụ: Một người lái xe nhấn vào một biểu tượng giao diện người dùng thông tin giải trí để tạo Người dùng Android mới. Thao tác này sẽ gửi yêu cầu đến HAL và phần còn lại trong các hệ thống phụ về xe. ECU được thông báo về Người dùng mới tạo. Lý do khác hệ thống con và ECU sau đó liên kết mã nhận dạng người dùng nội bộ với dữ liệu Mã nhận dạng người dùng.

REMOVE_USER
(Chỉ VIẾT)
Hệ thống Android gọi thuộc tính này sau khi một Người dùng Android đã xoá (bằng phương thức CarUserManager.removeUser()).

Đây là cuộc gọi một chiều — dự kiến sẽ không có phản hồi từ HAL.

Ví dụ: Người lái xe nhấn để xoá một ô tô hiện có Người dùng Android trong giao diện người dùng thông tin giải trí. HAL được thông báo và các hệ thống phụ và ECU của xe được thông báo về việc Người dùng gỡ bỏ có thể xoá mã nhận dạng người dùng nội bộ của họ.

Các cơ sở lưu trú khác

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. Có thể triển khai từng lớp mà không cần hỗ trợ lớp trừu tượng phần cứng (HAL) cho 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 thông tin nhận dạng một cơ chế thiết bị, chẳng hạn như thiết bị điều khiển từ xa cầm tay hoặc điện thoại. Sử dụng cùng thuộc tính này để Liên kết get hoặc set.

Ví dụ: Một người lái xe nhấn vào một biểu tượng giao diện người dùng thông tin giải trí để liên kết chìa khoá điện tử dùng để mở xe (KEY_123) cho Người dùng Android đang hoạt động (USER_11).

Thư viện trợ giúp

Tất cả đối tượng được dùng trong yêu cầu và thông báo phản hồi (chẳng hạn như UserInfo, InitialUserInfoRequest InitialUSerInfoResponse, v.v.) có giá trị đại diện cao sử dụng C++ struct nhưng việc xoá phải được làm phẳng thành đối tượng VehiclePropValue chuẩn (xem ví dụ bên dưới). Dành cho dễ dàng của sự phát triển, một C++ thư viện trợ giúp được cung cấp trong AOSP để tự động chuyển đổi HAL của người dùng structs thành VehiclePropValue (và ngược lại).

Ví dụ

NGƯỜI DÙNG_THÔNG_ TIN_KHỞI CHẠY

Ví dụ về yêu cầu (trong lần khởi động đầu tiên)

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ị)

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
}

NGƯỜI DÙNG CHUYỂN ĐỔI

Tên thực tế của các lớp và thuộc tính có khác một chút, nhưng quy trình làm việc chung là giống nhau, như được minh hoạ dưới đây:

Luồng công việc

Hình 1. Quy trình thuộc tính HAL (Lớp trừu tượng phần cứng) cho 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 chuyển đổi 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 quá trình chuyển đổi Android không 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]   = 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 về 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 công việc cũ

Phản hồi này thường xảy ra khi chuyển đổi 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
}

NGƯỜI DÙNG LOẠI BỎ

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

Đặt ví dụ (khoá xác thực đượ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
}