現在の多くの車両アーキテクチャには、インフォテインメント システムの外部に、シート設定やミラー調整など、エルゴノミクスを制御するための電子制御ユニット(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() API で Android ユーザーが削除された後、Android システムはこのプロパティを呼び出します。これは一方向の呼び出しであり、HAL からのレスポンスは想定されていません。 例: ドライバーが、インフォテインメント UI で既存の Android ユーザーをタップして削除します。ユーザーの削除が HAL に通知されます。内部ユーザー ID が削除されるように、他の車両サブシステムと ECU にもこの削除が通知されます。 |
追加のプロパティ
以下は、ユーザーのライフサイクルの状態とは関係のない追加のプロパティです。 それぞれは、ユーザー HAL をサポートせずに実装できます。
HAL プロパティ | 説明 |
---|---|
USER_IDENTIFICATION_ASSOCIATION (読み取りと書き込み) |
このプロパティを使用して、Android ユーザーをキーフォブやスマートフォンなどの識別メカニズムに関連付けます。get または set の関連付けにも、同じプロパティを使用します。
例: ドライバーがインフォテインメント UI アイコンをタップして、車両を開錠するために使用するキーフォブ(KEY_123)を現在のアクティブな Android ユーザー(USER_11)に関連付けます。 |
ヘルパー ライブラリ
リクエスト メッセージとレスポンス メッセージで使用されるすべてのオブジェクト(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 }