현재의 많은 차량 아키텍처에는 좌석 설정 및 미러 조정과 같은 인체공학을 제어하는 인포테인먼트 시스템 외부에 여러 전자 제어 장치(ECU)가 포함되어 있습니다. 현재 하드웨어 및 전원 아키텍처에 기반하여 많은 ECU는 Android 기반 인포테인먼트 시스템에 전원이 공급되기 전에 켜집니다. 이러한 ECU는 차량 하드웨어 추상화 계층(VHAL)을 통해 Android 기반 인포테인먼트 시스템과 상호작용할 수 있습니다.
Android 11부터 Android Automotive OS(AAOS)에서는 사용자를 식별하기 위해 외부 액세서리를 생성, 전환, 삭제, 연결하는 VHAL의 새 속성 세트를 도입했습니다. 예를 들어 이러한 새 속성을 사용하면 운전자가 전자 키와 같은 외부 액세서리를 Android 사용자와 페어링할 수 있습니다. 운전자가 차량에 접근하면 ECU의 절전 모드가 해제되고 전자 키를 감지합니다. 이 ECU는 인포테인먼트가 부팅되어야 하는 Android 사용자를 HAL에 알리므로 Android 사용자가 로드되도록 운전자가 기다리는 시간을 줄입니다.
사용자 HAL 사용 설정
사용자 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
사용자 HAL 속성
사용자 수명 주기 속성
다음 속성은 사용자 수명 주기 상태의 HAL 정보를 제공하여 Android 시스템과 외부 ECU 간에 사용자 수명 주기 동기화를 사용 설정합니다. 이러한 속성은 요청 및 응답 프로토콜을 사용하며 여기서 Android 시스템은 속성 값을 설정하여 요청하고 HAL은 속성 변경 이벤트를 실행하여 응답합니다.
참고: 사용자 HAL이 지원되는 경우 다음 모든 속성이 구현되어야 합니다.
HAL 속성 | 설명 |
---|---|
INITIAL_USER_INFO (읽기/쓰기) |
이 속성은 Android 시스템에서 호출하여 기기가 Suspend-to-RAM(STR)에서 부팅되거나 다시 시작될 때 시스템이 시작될 Android 사용자를 판단합니다. 속성이 호출되면 HAL은 다음 옵션 중 하나로 응답해야 합니다.
참고: HAL이 응답하지 않으면 기본 동작이 제한 시간(기본값 5초) 후에 실행되고 이로 인해 부팅이 지연됩니다. HAL이 응답하지만 Android 시스템에서 작업을 실행하지 못하는 경우(예: 최대 사용자 수에 도달한 경우) 기본 동작이 사용됩니다. 예를 들어 기본적으로 Android 시스템은 부팅 시 마지막 활성 사용자에서 시작됩니다. 다른 사용자의 전자 키가 감지되면 ECU는 HAL 속성을 재정의하고 시작할 때 Android 시스템은 지정된 사용자로 시작하도록 전환됩니다. |
SWITCH_USER (읽기/쓰기) |
이 속성은 활성 포그라운드 Android 사용자를 전환할 때 호출되고
Android 시스템이나 HAL에서 호출하여 사용자 전환을 요청할 수 있습니다. 3가지 워크플로는 다음과 같습니다.
Modern 워크플로는 2단계 커밋 접근 방식을 사용하여 Android 시스템과 외부 ECU가 동기화되도록 합니다. Android에서는 다음과 같이 전환을 시작합니다.
HAL은 ECU를 동기화하도록 상태를 업데이트하거나 다른 HAL 속성을 업데이트하는 예를 들어 이동 중에 운전자는 인포테인먼트 UI에서 Android 사용자를 전환하려고 합니다. 그러나 자동차 좌석 설정이 Android 사용자에 연결되어 있으므로 사용자를 전환하는 동안 좌석이 이동합니다. 따라서 좌석을 제어하는 ECU가 전환을 확인하지 않고 HAL은 실패로 응답하며 Android 사용자도 전환되지 않습니다.
Legacy 워크플로는 사용자가 전환된 후 전송된 단방향 호출입니다. 따라서 HAL이 전환을 차단할 수 없습니다. 초기 사용자 전환 후 부팅 시에만 또는
예를 들어 앱에서 Vehicle 워크플로는 Android 시스템이 아닌 HAL에서 시작됩니다.
예를 들어 정민은 윤아의 전자 키를 사용하여 자동차를 열었고 HAL은 윤아의 사용자 ID로 |
CREATE_USER (읽기/쓰기) |
이 속성은 CarUserManager.createUser() API를 사용하여 새 Android 사용자가 만들어질 때 Android 시스템에서 호출합니다.
HAL은 예를 들어 운전자가 인포테인먼트 UI 아이콘을 탭하여 새 Android 사용자를 만듭니다. 그러면 HAL과 나머지 차량 하위 시스템에 요청이 전송됩니다. 새로 만들어진 사용자를 ECU에 알립니다. 그러면 다른 하위 시스템과 ECU는 내부 사용자 ID를 Android 사용자 ID와 연결합니다. |
REMOVE_USER (쓰기 전용) |
이 속성은 CarUserManager.removeUser() API로 Android 사용자가 삭제된 후 Android 시스템에서 호출합니다.
단방향 호출로, HAL에서는 응답이 없습니다. 예를 들어 운전자가 인포테인먼트 UI에서 기존 Android 사용자를 삭제하려고 탭합니다. HAL에 삭제 정보가 전달되며 다른 차량 하위 시스템 및 ECU에도 사용자 삭제를 알려주므로 내부 사용자 ID를 삭제할 수 있습니다. |
추가 속성
다음은 사용자 수명 주기 상태와 관련이 없는 추가 속성입니다. 각 속성은 사용자 HAL을 지원하지 않고도 구현할 수 있습니다.
HAL 속성 | 설명 |
---|---|
USER_IDENTIFICATION_ASSOCIATION (읽기/쓰기) |
이 속성을 사용하여 Android 사용자를 전자 키나 전화와 같은 식별 메커니즘과 연결합니다. 동일한 이 속성을 사용하여 연결을 get 하거나 set 합니다.
예를 들어 운전자는 인포테인먼트 UI 아이콘을 탭하여 차량을 여는 데 사용된 전자 키(KEY_123)를 현재 활성 Android 사용자(USER_11)와 연결합니다. |
도우미 라이브러리
UserInfo
, InitialUserInfoRequest
, InitialUSerInfoResponse
와 같은 요청 및 응답 메시지에 사용된 모든 객체는 C++ struct
를 사용하여 높은 수준의 표현을 보유하지만 삭제는 표준 VehiclePropValue
객체로 평면화되어야 합니다(아래 예 참고). 쉽게 개발할 수 있도록 C++ 도우미 라이브러리가 AOSP에 제공되어 사용자 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. 사용자 HAL 속성 워크플로
Modern 워크플로 요청 예
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) }
Modern 워크플로 응답 예
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 }
Modern 워크플로 전환 후 응답 예
이 응답은 일반적으로 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) }
Modern 워크플로 전환 후 응답
이 응답은 일반적으로 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) }
Legacy 워크플로 요청 예
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) }
Vehicle 워크플로 요청 예
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 }
Legacy 워크플로 전환 후 응답
이 응답은 일반적으로 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 }