ユーザー HAL プロパティ

現在の車両アーキテクチャの多くには、シート設定やミラー調整などの人間工学を制御する、インフォテインメント システムの外側に複数の電子制御ユニット (ECU) が含まれています。現在のハードウェアおよび電源アーキテクチャに基づいて、Android ベースのインフォテインメント システムの電源が投入される前に、多くの ECU が電源投入されます。これらの 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
(読み書き)
このプロパティは、デバイスが起動するとき、または 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 によって呼び出されます。

最新のワークフローでは、2 フェーズ コミット アプローチを使用して、Android システムと外部 ECU が確実に同期されます。 Android が切り替えを開始すると、次のようになります。

  1. HAL をチェックして、ユーザーを切り替えることができるかどうかを判断します。

    HAL はSUCCESSまたはFAILUREで応答するため、Android は続行するかどうかを認識します。

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

    Android は、切り替えの成功または失敗を示すために、 ANDROID_POST_SWITCH応答を HAL に送信します。

HAL は、ECU を同期したり、他の HAL プロパティを更新したりするために、 ANDROID_POST_SWITCH応答が完了するまで待機して状態を更新する必要があります。

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

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

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

Vehicle ワークフローは、Android システムではなく HAL から発生します。

  1. HAL はユーザーの切り替えを要求します。
  2. システムが Android ユーザーの切り替えを完了しました。
  3. Android は、切り替えの成功または失敗を示すために、 ANDROID_POST_SWITCH応答を HAL に送信します。

例:ボブはアリスのキーホルダーを使用して車を開け、HAL はアリスのユーザー ID を使用してINITIAL_USER_INFOリクエストに応答しました。次に、生体認証センサー ECU がドライバーをボブとして識別したため、ユーザー 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 ユーザーが ( CarUserManager.removeUser()メソッドで) 削除された後、Android システムはこのプロパティを呼び出します。

これは一方向の呼び出しであり、HAL からの応答は期待されません。

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

追加のプロパティ

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

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

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

ヘルパー ライブラリ

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

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)
}

ユーザーを作成

リクエスト例

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

セット例 (User 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
}