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