Viele aktuelle Fahrzeugarchitekturen enthalten mehrere elektronische Steuergeräte (ECUs) außerhalb des Infotainmentsystems, die die Ergonomie steuern, z. B. die Sitzeinstellungen und Spiegelverstellungen. Aufgrund der aktuellen Hardware- und Stromversorgungsarchitektur werden viele ECUs eingeschaltet, bevor das Android-basierte Infotainmentsystem eingeschaltet wird. Diese Steuergeräte können über die Vehicle Hardware Abstraction Layer (VHAL) mit einem Android-basierten Infotainmentsystem kommunizieren.
Ab Android 11 wurden in Android Automotive OS (AAOS) neue Eigenschaften in der VHAL eingeführt, mit denen externes Zubehör zum Identifizieren von Nutzern erstellt, gewechselt, entfernt und verknüpft werden kann. Mit diesen neuen Properties kann ein Fahrer beispielsweise ein externes Zubehör wie einen Schlüsselanhänger mit seinem Android-Nutzer verknüpfen. Wenn der Fahrer sich dem Fahrzeug nähert, wird eine ECU aktiviert und erkennt den Schlüsselanhänger. Diese ECU gibt dem HAL an, von welchem Android-Nutzer das Infotainmentsystem gestartet werden soll. Dadurch verkürzt sich die Zeit, die ein Treiber auf das Laden des Android-Nutzers wartet.
User HAL aktivieren
Die Nutzer-HAL-Eigenschaften müssen explizit aktiviert werden. Dazu muss die Systemeigenschaft android.car.user_hal_enabled
auf true
gesetzt sein.
Sie können dies in der Datei car.mk
tun, damit es nicht manuell festgelegt werden muss. Prüfen Sie, ob user_hal_enabled=true
aktiviert ist, indem Sie UserHalService
ausgeben:
$ adb shell dumpsys car_service --hal UserHalService|grep enabled user_hal_enabled=true
Du kannst user_hal_enabled
auch mit adb shell
getprop android.car.user_hal_enabled
oder adb logcat
CarServiceHelper *:s
prüfen. Wenn die Property deaktiviert ist, wird beim Starten von system_server
eine Meldung wie die folgende angezeigt:
I CarServiceHelper: Not using User HAL
Wenn Sie user_hal_enabled
manuell aktivieren möchten, legen Sie die Systemeigenschaft android.car.user_hal_enabled
fest und starten Sie system_server
neu:
$ adb shell setprop android.car.user_hal_enabled true $ adb shell stop && adb shell start
Die Ausgabe von logcat
sieht so aus:
I CarServiceHelper: User HAL enabled with timeout of 5000ms D CarServiceHelper: Got result from HAL: OK I CarServiceHelper: User HAL returned DEFAULT behavior
HAL-Eigenschaften des Nutzers
Eigenschaften für den Nutzerlebenszyklus
Die folgenden Eigenschaften enthalten die HAL-Informationen für die Lebenszyklusstatus von Nutzern, die die Synchronisierung des Nutzerlebenszyklus zwischen dem Android-System und einer externen ECU ermöglichen. Für diese Properties wird ein Anfrage- und Antwortprotokoll verwendet, bei dem das Android-System eine Anfrage stellt, indem es einen Property-Wert festlegt, und die HAL antwortet, indem sie ein Property-Änderungsereignis ausgibt.
Hinweis:Wenn die User HAL unterstützt wird, müssen alle folgenden Properties implementiert werden.
HAL-Property | Beschreibung |
---|---|
INITIAL_USER_INFO (Lese-/Schreibzugriff) |
Diese Eigenschaft wird vom Android-System aufgerufen, um zu bestimmen, welchen Android-Nutzer das System startet, wenn das Gerät gestartet wird oder aus dem Suspend-to-RAM (STR) fortgesetzt wird. Bei einem Aufruf muss die HAL mit einer der folgenden Optionen antworten:
Hinweis:Wenn der HAL nicht reagiert, wird er standardmäßig nach einer Zeitüberschreitung (standardmäßig fünf Sekunden) ausgeführt. Dadurch wird der Start verzögert. Wenn die HAL antwortet, das Android-System die Aktion jedoch nicht ausführen kann (z. B. wenn die maximale Anzahl von Nutzern erreicht wurde), wird das Standardverhalten verwendet. Beispiel:Standardmäßig wird das Android-System beim Starten mit dem zuletzt aktiven Nutzer gestartet. Wenn ein Schlüsselanhänger für einen anderen Nutzer erkannt wird, überschreibt das Steuergerät die HAL-Eigenschaft und das Android-System wechselt beim Starten zum Starten mit dem angegebenen Nutzer. |
SWITCH_USER (Lese-/Schreibzugriff) |
Diese Property wird aufgerufen, wenn der aktive Android-Nutzer im Vordergrund wechselt.
Die Property kann entweder vom Android-System oder von der HAL aufgerufen werden, um einen Nutzerwechsel anzufordern. Die drei Workflows sind:
Der moderne Workflow verwendet einen zweiphasigen Commit-Ansatz, um sicherzustellen, dass das Android-System und die externe ECU synchronisiert werden. Wenn Android den Wechsel initiiert:
Der HAL sollte bis nach der Beispiel:Ein Fahrer versucht während der Fahrt, über die Infotainment-Benutzeroberfläche zwischen Android-Nutzern zu wechseln. Da die Einstellungen für den Autositz jedoch mit dem Android-Nutzer verknüpft sind, bewegt sich der Sitz beim Wechseln des Nutzers. Daher bestätigt die ECU, die die Sitze steuert, den Wechsel nicht, der HAL antwortet mit einem Fehler und der Android-Nutzer wird nicht gewechselt.
Der Legacy-Workflow ist ein Einwegaufruf, der nach dem Wechsel des Nutzers gesendet wird. Der HAL kann den Wechsel also nicht blockieren. Sie wird nur beim Starten (nach dem ersten Nutzerwechsel) oder für Apps aufgerufen, die
Beispiel:Wenn eine App Der Fahrzeug-Workflow stammt aus der HAL, nicht aus dem Android-System:
Beispiel:Bob hat Alices Schlüsselanhänger verwendet, um das Auto zu öffnen, und der HAL hat auf die |
CREATE_USER (Lese-/Schreibzugriff) |
Diese Property wird vom Android-System aufgerufen, wenn ein neuer Android-Nutzer über die CarUserManager.createUser() API erstellt wird.
Die HAL antwortet mit Beispiel:Ein Fahrer tippt auf ein Symbol in der Infotainment-Benutzeroberfläche, um einen neuen Android-Nutzer zu erstellen. Dadurch wird eine Anfrage an den HAL und die restlichen Fahrzeug-Subsysteme gesendet. ECUs werden über den neu erstellten Nutzer informiert. Andere Subsysteme und Steuergeräte ordnen dann ihre interne Nutzer-ID der Android-Nutzer-ID zu. |
REMOVE_USER (nur SCHREIBEN) |
Das Android-System ruft diese Property auf, nachdem ein Android-Nutzer (mit der Methode CarUserManager.removeUser() ) entfernt wurde.
Dies ist ein Einwegaufruf. Es wird keine Antwort von der HAL erwartet. Beispiel:Ein Fahrer tippt, um einen vorhandenen Android-Nutzer in der Infotainment-UI zu entfernen. Der HAL und andere Fahrzeugsubsysteme und ECUs werden über die Entfernung des Nutzers informiert, damit sie ihre interne Nutzer-ID entfernen können. |
Zusätzliche Attribute
Die folgenden zusätzlichen Properties haben keinen Bezug zum Nutzerlebenszyklus. Jede kann ohne Unterstützung der User HAL implementiert werden.
HAL-Property | Beschreibung |
---|---|
USER_IDENTIFICATION_ASSOCIATION (Lese-/Schreibzugriff) |
Verwenden Sie dieses Attribut, um jeden Android-Nutzer einem Identifikationsmechanismus wie einem Schlüsselanhänger oder einem Smartphone zuzuordnen. Verwenden Sie dieselbe Property für get - oder set -Verknüpfungen.
Beispiel:Ein Fahrer tippt auf ein Symbol der Infotainment-Benutzeroberfläche, um den Schlüsselanhänger, mit dem das Fahrzeug geöffnet wird ( |
Hilfsbibliotheken
Alle in den Anfrage- und Antwortnachrichten verwendeten Objekte (z. B. UserInfo
, InitialUserInfoRequest
, InitialUSerInfoResponse
usw.) haben eine hohe Darstellungsebene mit C++ struct
. Für die Entfernung müssen sie jedoch auf Standard-VehiclePropValue
-Objekte abgeflacht werden (siehe Beispiele unten). Zur Vereinfachung der Entwicklung wird in AOSP eine C++-Hilfsbibliothek bereitgestellt, mit der die User HAL structs
automatisch in eine VehiclePropValue
umgewandelt wird (und umgekehrt).
Beispiele
INITIAL_USER_INFO
Beispielanfrage (beim ersten Start)
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 }
Antwortbeispiel (Administrator erstellen)
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
Der tatsächliche Name der Klassen und Eigenschaften unterscheidet sich geringfügig, der Gesamtablauf ist jedoch derselbe, wie in der Abbildung dargestellt:
Abbildung 1: Workflow für HAL-Nutzereigenschaften
Beispiel für eine moderne Workflow-Anfrage
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) }
Beispiel für eine Antwort eines modernen Workflows
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 }
Beispiel für eine Antwort nach dem Wechsel zu einem modernen Workflow
Diese Antwort wird in der Regel ausgegeben, wenn eine Android-Umstellung erfolgreich war:
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) }
Reaktion auf moderne Workflows nach dem Wechsel
Diese Antwort wird in der Regel ausgegeben, wenn ein Android-Schalter fehlschlägt:
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) }
Beispiel für eine Anfrage für einen Legacy-Workflow
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) }
Beispiel für eine Anfrage für einen Fahrzeug-Workflow
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 }
Antwort nach der Umstellung auf den Legacy-Workflow
Diese Antwort wird in der Regel ausgegeben, wenn eine Android-Umstellung erfolgreich war:
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
Beispielanfrage
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) }
Antwortbeispiel
VehiclePropValue { // flattened from CreateUserResponse prop: 299896585 // CREATE_USER prop.values.int32Values: [0] = 42 // Request ID (must match request) [1] = 3 // CreateUserStatus::SUCCESS }
REMOVE_USER
Beispielanfrage
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
Beispiel festlegen (Schlüsselanhänger, der mit Nutzer 10 verknüpft ist)
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 }