사용자 HAL 속성

현재의 많은 차량 아키텍처에는 인포테인먼트 시스템 외부에 좌석 설정, 미러 조정 등 인체공학적 기능을 제어하는 ​​여러 전자 제어 장치(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은 다음 옵션 중 하나로 응답해야 합니다.
  • Android에서 설정한 기본 동작입니다(마지막으로 사용한 사용자로 전환하거나 처음 부팅하는 경우 새 사용자 생성).
  • 기존 사용자로 전환합니다.
  • 이름, 플래그, 시스템 로캘 등의 선택적 속성을 사용하여 새 사용자를 만들고 해당 새 사용자로 전환합니다.

참고: HAL이 응답하지 않는 경우 기본 동작은 시간 초과 기간(기본적으로 5초) 후에 실행되어 부팅이 지연되는 것입니다. HAL이 응답하지만 Android 시스템이 작업을 실행하지 못하는 경우(예: 최대 사용자 수에 도달한 경우) 기본 동작이 사용됩니다.

예: 기본적으로 Android 시스템은 부팅 시 마지막 활성 사용자에서 시작됩니다. 다른 사용자의 전자열쇠가 감지되면 ECU는 HAL 속성을 무시하고 시작 중에 Android 시스템은 지정된 사용자에서 시작되도록 전환합니다.

SWITCH_USER
(읽기/쓰기)
이 속성은 활성 전경 Android 사용자를 전환할 때 호출됩니다. 이 속성은 Android 시스템이나 HAL에서 호출하여 사용자 전환을 요청할 수 있습니다. 세 가지 워크플로는 다음과 같습니다.
  • 현대의. CarUserManager 에서 스위치가 시작되었습니다.
  • 유산. ActivityManager 에서 스위치가 시작되었습니다.
  • 차량. 사용자 전환을 요청하기 위해 HAL에서 호출됩니다.

최신 워크플로는 2단계 커밋 접근 방식을 사용하여 Android 시스템과 외부 ECU가 동기화되도록 합니다. Android가 스위치를 시작하면 다음이 수행됩니다.

  1. HAL을 확인하여 사용자를 전환할 수 있는지 확인하세요.

    HAL은 SUCCESS 또는 FAILURE 로 응답하므로 Android는 계속 진행할지 여부를 알 수 있습니다.

  2. Android 사용자 전환을 완료합니다.

    Android는 전환 성공 또는 실패를 나타내기 위해 ANDROID_POST_SWITCH 응답을 HAL에 보냅니다.

HAL은 ANDROID_POST_SWITCH 응답이 끝날 때까지 기다려야 상태를 업데이트하여 ECU를 동기화하거나 다른 HAL 속성을 업데이트해야 합니다.

예: 이동 중에 운전자가 인포테인먼트 UI에서 Android 사용자 전환을 시도합니다. 하지만 카시트 설정은 Android User와 연결되어 있기 때문에 User 전환 중에 시트가 움직입니다. 따라서 좌석을 제어하는 ​​ECU는 스위치를 확인하지 않고 HAL은 실패로 응답하며 Android 사용자는 전환되지 않습니다.

레거시 워크플로는 사용자가 전환된 후에 전송되는 단방향 호출입니다(따라서 HAL이 전환을 차단할 수 없음). 부팅 시(초기 사용자 전환 후) 또는 CarUserManager.switchUser ActivityManager.switchUser() CarUserManager.switchUser() 호출하는 앱에 대해서만 호출됩니다. 참조 SettingsSystemUI 앱은 이미 후자를 사용하고 있지만 OEM이 사용자 전환을 위해 자체 설정 앱을 제공하는 경우 OEM은 사용법을 변경해야 합니다.

예: 앱이 ActivityManager.switchUser() 사용하여 사용자를 전환하는 경우 사용자 전환이 발생했음을 알리기 위해 단방향 호출이 HAL로 전송됩니다.

차량 워크플로는 Android 시스템이 아닌 HAL에서 시작됩니다.

  1. HAL이 사용자 전환을 요청합니다.
  2. 시스템이 Android 사용자 전환을 완료합니다.
  3. Android는 전환 성공 또는 실패를 나타내기 위해 ANDROID_POST_SWITCH 응답을 HAL에 보냅니다.

예: Bob은 Alice의 전자열쇠를 사용하여 차를 열었고 HAL은 Alice의 사용자 ID로 INITIAL_USER_INFO 요청에 응답했습니다. 다음으로 생체인식 센서 ECU가 운전자를 Bob으로 식별했기 때문에 사용자 HAL은 사용자 전환을 위해 SWITCH_USER 요청을 보냈습니다.

CREATE_USER
(읽기/쓰기)
이 속성은 새로운 Android 사용자가 생성될 때( CarUserManager.createUser() API 사용) Android 시스템에서 호출됩니다.

HAL은 SUCCESS 또는 FAILURE 로 응답합니다. HAL이 실패로 응답하면 Android 시스템은 사용자를 제거합니다.

예: 운전자가 인포테인먼트 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 아이콘을 탭하여 차량을 여는 데 사용되는 전자열쇠( KEY_123 )를 현재 활성 Android 사용자( USER_11 )에 연결합니다.

도우미 라이브러리

요청 및 응답 메시지에 사용된 모든 개체(예: 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
}