ユーザー HAL プロパティ

現在の多くの車両アーキテクチャには、インフォテインメント システムの外部に、シート設定やミラー調整など、エルゴノミクスを制御するための電子制御ユニット(ECU)が複数搭載されています。それら多くの ECU は、現在のハードウェア アーキテクチャと電源アーキテクチャに基づいて、Android ベースのインフォテインメント システムが起動する前に起動します。これらの ECU は、Vehicle Hardware Abstraction Layer(VHAL)を介して Android ベースのインフォテインメント システムとやり取りできます。

Android 11 以降、Android Automotive OS(AAOS)には、外部アクセサリの作成、切り替え、削除、関連付けを行い、ユーザーを識別するための新しいプロパティ セットを VHAL が導入されています。たとえば、これらの新しいプロパティにより、ドライバーはキーフォブなどの外部アクセサリを Android ユーザーにペア設定できます。ペア設定後、ドライバーが車両に近づくと、ECU が復帰してキーフォブが検出されます。この ECU は、どの Android ユーザーのインフォテインメントを起動するかを HAL に示します。これにより、ドライバーが Android ユーザーの読み込みを待つ時間が短縮されます。

ユーザー HAL を有効にする

システム プロパティの android.car.user_hal_enabledtrue に設定して、ユーザー HAL プロパティを明示的に有効にする必要があります(手動で設定する必要がないように、car.mk ファイルでこの設定を行うこともできます)。UserHalService をダンプして user_hal_enabled=true が有効になっていることを確認します。

$ adb shell dumpsys car_service --hal UserHalService|grep enabled
user_hal_enabled=true

user_hal_enabled を確認するには、adb shell getprop android.car.user_hal_enabled または adb logcat CarServiceHelper *:s を使用します。プロパティが無効になっている場合、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
(読み取りと書き込み)
このプロパティは、デバイスの起動時または Suspend-to-RAM(STR)からの再開時にシステムが起動する Android ユーザーを決定するために、Android システムによって呼び出されます。呼び出された場合、HAL は次のいずれかのオプションで応答する必要があります。
  • Android によって設定されたデフォルトの動作(最後に使用したユーザーに切り替えるか、これが最初の起動の場合は新しいユーザーを作成します)。
  • 既存のユーザーに切り替える。
  • 新しいユーザーを(名前、フラグ、システム ロケールなどのオプションのプロパティを指定して)作成し、その新しいユーザーに切り替える。

注: HAL が応答しない場合、デフォルトの動作はタイムアウト期間(デフォルトでは 5 秒)後に実行されるため、起動が遅れます。HAL が応答しても、Android システムがアクションの実行に失敗した場合(ユーザーが最大数に達している場合など)、デフォルトの動作が使用されます。

例: デフォルトでは、Android システムは起動時に最後にアクティブだったユーザーで起動します。別のユーザーのキーフォブが検出されると、ECU は HAL プロパティをオーバーライドします。Android システムは起動時に、その指定されたユーザーで起動するように切り替わります。

SWITCH_USER
(読み取りと書き込み)
このプロパティは、アクティブなフォアグラウンド Android ユーザーを切り替える際に呼び出されます。このプロパティを Android システムまたは HAL のいずれかから呼び出して、ユーザーの切り替えをリクエストできます。次の 3 つのワークフローがあります。
  • モダン。CarUserManager から切り替えが開始されます。
  • レガシー。ActivityManager から切り替えが開始されます。
  • 車両。ユーザーの切り替えをリクエストするために HAL によって呼び出されます。

モダン ワークフローでは、Android システムと外部 ECU が確実に同期されるように、2 相コミット アプローチが使用されています。Android が切り替えを開始すると、

  1. HAL をチェックしてユーザーの切り替えが可能かどうかを判断します。

    HAL は SUCCESS または FAILURE を返します。これにより、Android は続行の可否を確認できます。

  2. Android ユーザーの切り替えを完了します。

    Android は、ANDROID_POST_SWITCH レスポンスを HAL に送信し、切り替えの成功または失敗を示します。

HAL は、ANDROID_POST_SWITCH レスポンスの状態が ECU の同期を行えるように更新されるか、他の HAL プロパティが更新されるまで待機する必要があります。

例: ドライバーが走行中に、インフォテインメント UI で Android ユーザーの切り替えようとします。しかし、車両のシート設定は Android ユーザーに関連付けられているため、ユーザーの切り替え中にシートが移動しようとします。そのため、シートを制御する ECU はユーザーの切り替えを確認できません。HAL は失敗を返し、Android ユーザーの切り替えは行われません。

レガシー ワークフローは、ユーザーの切り替えが行われた後に送信される一方向の呼び出しです(HAL が切り替えをブロックすることはできません)。起動時(最初のユーザー切り替え後)、または CarUserManager.switchUser() ではなく ActivityManager.switchUser() を呼び出すアプリでのみ呼び出されます。リファレンスの SettingsSystemUI アプリはすでに後者を使用していますが、OEM がユーザーを切り替えるための独自の設定アプリを提供している場合、OEM は使用方法を変更する必要があります。

例: アプリが ActivityManager.switchUser() を使用してユーザーを切り替えた場合、一方向の呼び出しが HAL に送信され、ユーザーの切り替えが行われたことが通知されます。

車両ワークフローは、Android システムではなく HAL によって開始されます。

  1. HAL がユーザーの切り替えをリクエストします。
  2. システムが Android ユーザーの切り替えを完了します。
  3. Android は、ANDROID_POST_SWITCH レスポンスを HAL に送信し、切り替えの成功または失敗を示します。

例: 太郎が花子のキーフォブを使用して車を開錠したため、HAL は花子のユーザー ID で INITIAL_USER_INFO リクエストに応答します。次に、生体認証センサー ECU はドライバーを太郎と識別したため、ユーザー HAL はユーザーを切り替えるために SWITCH_USER リクエストを送信します。

CREATE_USER
(読み取りと書き込み)
このプロパティは、CarUserManager.createUser() API を使用して新しい Android ユーザーが作成されたときに Android システムによって呼び出されます。

HAL は SUCCESS または FAILURE を返します。HAL が失敗を返した場合、Android システムはユーザーを削除します。

例: ドライバーが、インフォテインメント UI アイコンをタップして、新しい Android ユーザーを作成します。これにより、HAL と残りの車両サブシステムにリクエストが送信されます。ECU に新しく作成されたユーザーが通知されます。その後、他のサブシステムと ECU が、内部ユーザー ID を Android ユーザー ID に関連付けます。

REMOVE_USER
(書き込みのみ)
CarUserManager.removeUser() API で Android ユーザーが削除された後、Android システムはこのプロパティを呼び出します。

これは一方向の呼び出しであり、HAL からのレスポンスは想定されていません。

例: ドライバーが、インフォテインメント UI で既存の Android ユーザーをタップして削除します。ユーザーの削除が HAL に通知されます。内部ユーザー ID が削除されるように、他の車両サブシステムと ECU にもこの削除が通知されます。

追加のプロパティ

以下は、ユーザーのライフサイクルの状態とは関係のない追加のプロパティです。 それぞれは、ユーザー HAL をサポートせずに実装できます。

HAL プロパティ 説明
USER_IDENTIFICATION_ASSOCIATION
(読み取りと書き込み)
このプロパティを使用して、Android ユーザーをキーフォブやスマートフォンなどの識別メカニズムに関連付けます。get または set の関連付けにも、同じプロパティを使用します。

例: ドライバーがインフォテインメント UI アイコンをタップして、車両を開錠するために使用するキーフォブ(KEY_123)を現在のアクティブな Android ユーザー(USER_11)に関連付けます。

ヘルパー ライブラリ

リクエスト メッセージとレスポンス メッセージで使用されるすべてのオブジェクト(UserInfoInitialUserInfoRequestInitialUSerInfoResponse など)には、C++ struct による高度な表現が使用されていますが、削除は標準の VehiclePropValue オブジェクトにフラット化する必要があります(以下の例を参照)。開発を容易にするため、AOSP では、ユーザー HAL の structs を自動的に VehiclePropValue に(またはその逆に)変換するための C++ ヘルパー ライブラリが提供されています。

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
}