HAL-Nutzereigenschaften

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:
  • Das von Android festgelegte Standardverhalten (zum zuletzt verwendeten Nutzer wechseln oder bei der ersten Inbetriebnahme einen neuen Nutzer erstellen)
  • Wechseln Sie zu einem vorhandenen Nutzer.
  • Erstellen Sie einen neuen Nutzer (mit den optionalen Eigenschaften „Name“, „Flags“, „Systemlocale“ usw.) und wechseln Sie zu diesem neuen Nutzer.

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:
  • Modern Schalter wurde von CarUserManager aus gestartet.
  • Legacy Wechsel ab ActivityManager gestartet.
  • Fahrzeug. Wird vom HAL aufgerufen, um einen Nutzerwechsel anzufordern.

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:

  1. Prüfen Sie in der HAL, ob der Nutzer gewechselt werden kann.

    Der HAL antwortet mit SUCCESS oder FAILURE, damit Android weiß, ob fortgefahren werden soll oder nicht.

  2. Schließen Sie den Wechsel zum Android-Nutzer ab.

    Android sendet eine ANDROID_POST_SWITCH-Antwort an den HAL, um anzugeben, ob der Switch erfolgreich war oder nicht.

Der HAL sollte bis nach der ANDROID_POST_SWITCH-Antwort warten, um seinen Status zu aktualisieren, um ECUs zu synchronisieren oder andere HAL-Eigenschaften zu aktualisieren.

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 ActivityManager.switchUser() anstelle von CarUserManager.switchUser() aufrufen. In den Referenz-Apps Settings und SystemUI wird bereits die letztere Methode verwendet. Wenn ein OEM jedoch eigene Einstellungen-Apps zum Wechseln von Nutzern bereitstellt, sollte er die Verwendung ändern.

Beispiel:Wenn eine App ActivityManager.switchUser() verwendet, um den Nutzer zu wechseln, wird ein Einwegaufruf an die HAL gesendet, um sie darüber zu informieren, dass ein Nutzerwechsel stattgefunden hat.

Der Fahrzeug-Workflow stammt aus der HAL, nicht aus dem Android-System:

  1. Der HAL fordert einen Nutzerwechsel an.
  2. Das System führt den Wechsel des Android-Nutzers durch.
  3. Android sendet eine ANDROID_POST_SWITCH-Antwort an den HAL, um anzugeben, ob der Wechsel erfolgreich war oder fehlgeschlagen ist.

Beispiel:Bob hat Alices Schlüsselanhänger verwendet, um das Auto zu öffnen, und der HAL hat auf die INITIAL_USER_INFO-Anfrage mit der Nutzer-ID von Anne geantwortet. Als Nächstes identifizierte eine ECU mit biometrischen Sensoren den Fahrer als Bob. Daher sendete der Nutzer-HAL eine SWITCH_USER-Anfrage, um den Nutzer zu wechseln.

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 SUCCESS oder FAILURE. Wenn die HAL mit einem Fehler antwortet, entfernt das Android-System den Nutzer.

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 (KEY_123), mit dem aktuell aktiven Android-Nutzer (USER_11) zu verknüpfen.

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:

Workflow

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
}