現在の多くの車両アーキテクチャには、インフォテインメント システムの外部に、シート設定やミラー調整など、エルゴノミクスを制御するための電子制御ユニット(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_enabled を true に設定して、ユーザー 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 は次のいずれかのオプションで応答する必要があります。 
 注: HAL が応答しない場合、デフォルトの動作はタイムアウト期間(デフォルトでは 5 秒)後に実行されるため、起動が遅れます。 HAL が応答しても、Android システムがアクションの実行に失敗した場合(ユーザーが最大数に達している場合など)、デフォルトの動作が使用されます。 例: デフォルトでは、Android システムは起動時に最後にアクティブだったユーザーで起動します。別のユーザーのキーフォブが検出されると、ECU は HAL プロパティをオーバーライドします。Android システムは起動時に、その指定されたユーザーで起動するように切り替わります。 | 
| SWITCH_USER(読み取りと書き込み) | このプロパティは、アクティブなフォアグラウンド Android ユーザーを切り替える際に呼び出されます。
このプロパティを Android システムまたは HAL のいずれかから呼び出して、ユーザーの切り替えをリクエストできます。次の 3 つのワークフローがあります。 
 モダン ワークフローでは、Android システムと外部 ECU が確実に同期されるように、2 相コミット アプローチが使用されています。Android が切り替えを開始すると、 
 
      HAL は、 例: ドライバーが走行中に、インフォテインメント UI で Android ユーザーを切り替えようとします。しかし、車両のシート設定は Android ユーザーに関連付けられているため、ユーザーの切り替え中にシートが移動します。そのため、シートを制御する ECU はユーザーの切り替えを確認できません。HAL は失敗を返し、Android ユーザーの切り替えは行われません。 
      レガシー ワークフローは、ユーザーの切り替えが行われた後に送信される一方向の呼び出しです(HAL が切り替えをブロックすることはできません)。起動時(最初のユーザー切り替え後)、または  
      例: アプリが  車両ワークフローは、Android システムではなく HAL によって開始されます。 
 例: 太郎が花子のキーフォブを使用して車を開錠したため、HAL は花子のユーザー ID で  | 
| CREATE_USER(読み取りと書き込み) | このプロパティは、 CarUserManager.createUser()API を使用して新しい Android ユーザーが作成されたときに Android システムによって呼び出されます。
  HAL は  例: ドライバーが、インフォテインメント UI アイコンをタップして、新しい Android ユーザーを作成します。これにより、HAL と残りの車両サブシステムにリクエストが送信されます。ECU に新しく作成されたユーザーが通知されます。その後、他のサブシステムと ECU が、内部ユーザー ID を Android ユーザー ID に関連付けます。 | 
| REMOVE_USER(書き込みのみ) | CarUserManager.removeUser()メソッドで Android ユーザーが削除された後、Android システムはこのプロパティを呼び出します。これは一方向の呼び出しであり、HAL からのレスポンスは想定されていません。 例: ドライバーが、インフォテインメント UI で既存の Android ユーザーをタップして削除します。ユーザーの削除が HAL に通知されます。内部ユーザー ID が削除されるように、他の車両サブシステムと ECU にもこの削除が通知されます。 | 
追加のプロパティ
以下は、ユーザーのライフサイクルの状態とは関係のない追加のプロパティです。 それぞれは、ユーザー HAL をサポートせずに実装できます。
| HAL プロパティ | 説明 | 
|---|---|
| USER_IDENTIFICATION_ASSOCIATION(読み取りと書き込み) | このプロパティを使用して、Android ユーザーをキーフォブやスマートフォンなどの識別メカニズムに関連付けます。 getまたはsetの関連付けにも、同じプロパティを使用します。
  例: ドライバーがインフォテインメント UI アイコンをタップして、車両を開錠するために使用するキーフォブ( | 
ヘルパー ライブラリ
  リクエスト メッセージとレスポンス メッセージで使用されるすべてのオブジェクト(UserInfo、InitialUserInfoRequest、InitialUSerInfoResponse など)には、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 }
