Propriétés HAL de l'utilisateur

De nombreuses architectures de véhicules actuelles contiennent plusieurs unités de contrôle électronique (ECU) en dehors du système d'infodivertissement qui contrôlent l'ergonomie, comme les réglages des sièges et les réglages des rétroviseurs. En fonction des architectures matérielles et d'alimentation actuelles, de nombreux ECU s'allument avant le système d'infodivertissement basé sur Android. Ces processeurs UC peuvent s'interfacer avec un système d'infoloisirs basé sur Android via la couche d'abstraction matérielle du véhicule (VHAL).

À partir d'Android 11, Android Automotive OS (AAOS) a introduit un nouvel ensemble de propriétés sur le VHAL pour créer, basculer, supprimer et associer des accessoires externes afin d'identifier les utilisateurs. Par exemple, ces nouvelles propriétés permettent au conducteur d'associer un accessoire externe, tel qu'une clé sans contact, à son utilisateur Android. Lorsque le conducteur s'approche du véhicule, un ECU se réveille et détecte la clé sans contact. Cet ECU indique au HAL l'utilisateur Android avec lequel l'infodivertissement doit démarrer, ce qui réduit le temps d'attente du pilote pour que son utilisateur Android se charge.

Activer le HAL utilisateur

Les propriétés HAL utilisateur doivent être explicitement activées en veillant à ce que la propriété système android.car.user_hal_enabled soit définie sur true. (Vous pouvez le faire dans le fichier car.mk, de sorte qu'il n'ait pas besoin d'être défini manuellement.) Vérifiez que user_hal_enabled=true est activé en vidant le UserHalService:

$ adb shell dumpsys car_service --hal UserHalService|grep enabled
user_hal_enabled=true

Vous pouvez également vérifier user_hal_enabled à l'aide de adb shell getprop android.car.user_hal_enabled ou adb logcat CarServiceHelper *:s. Si la propriété est désactivée, un message semblable au suivant s'affiche lorsque system_server démarre:

I CarServiceHelper: Not using User HAL

Pour activer manuellement user_hal_enabled, définissez la propriété système android.car.user_hal_enabled et redémarrez system_server:

$ adb shell setprop android.car.user_hal_enabled true
$ adb shell stop && adb shell start

Le résultat logcat s'affiche comme suit:

I CarServiceHelper: User HAL enabled with timeout of 5000ms
D CarServiceHelper: Got result from HAL: OK
I CarServiceHelper: User HAL returned DEFAULT behavior

Propriétés HAL de l'utilisateur

Propriétés du cycle de vie des utilisateurs

Les propriétés suivantes fournissent les informations HAL pour les états du cycle de vie de l'utilisateur, ce qui permet de synchroniser le cycle de vie des utilisateurs entre le système Android et un ECU externe. Ces propriétés utilisent un protocole de requête et de réponse, dans lequel le système Android envoie une requête en définissant une valeur de propriété et le HAL répond en émettant un événement de modification de propriété.

Remarque:Lorsque l'HAL utilisateur est pris en charge, toutes les propriétés suivantes doivent être implémentées.

Propriété HAL Description
INITIAL_USER_INFO
(lecture/écriture)
Cette propriété est appelée par le système Android pour déterminer quel utilisateur Android le système démarre lorsque l'appareil démarre ou reprend depuis la suspension vers la RAM (STR, Suspend-to-RAM). Lorsqu'il est appelé, le HAL doit répondre avec l'une des options suivantes :
  • Comportement par défaut défini par Android (passage à l'utilisateur le plus récemment utilisé ou création d'un nouvel utilisateur s'il s'agit du premier démarrage).
  • Passez à un utilisateur existant.
  • Créez un utilisateur (avec les propriétés facultatives de nom, d'indicateurs, de paramètres régionaux système, etc.) et passez à ce nouvel utilisateur.

Remarque:Si le HAL ne répond pas, le comportement par défaut consiste à s'exécuter après un délai d'inactivité (cinq secondes par défaut), ce qui retarde le démarrage. Si le HAL répond, mais que le système Android ne parvient pas à exécuter l'action (par exemple, si le nombre maximal d'utilisateurs a été atteint), le comportement par défaut est utilisé.

Exemple:Par défaut, le système Android démarre avec le dernier utilisateur actif au démarrage. Si une clé sans contact appartenant à un autre utilisateur est détectée, l'ECU remplace la propriété HAL et, au démarrage, le système Android passe au démarrage de cet utilisateur.

SWITCH_USER
(lecture/écriture)
Cette propriété est appelée lors du changement de l'utilisateur Android actif au premier plan. La propriété peut être appelée par le système Android ou par le HAL pour demander un changement d'utilisateur. Voici les trois flux de travail:
  • Moderne. Le changement a commencé à partir de CarUserManager.
  • Ancienne : Migration lancée à partir de ActivityManager.
  • Véhicule Appelé par le HAL pour demander un changement d'utilisateur.

Le workflow moderne utilise une approche de validation en deux phases pour garantir la synchronisation du système Android et de l'ECU externe. Lorsqu'Android lance le changement:

  1. Vérifiez le HAL pour déterminer s'il est possible de changer d'utilisateur.

    Le HAL répond avec SUCCESS ou FAILURE, afin qu'Android sache s'il doit continuer ou non.

  2. Effectuez le changement d'utilisateur Android.

    Android envoie une réponse ANDROID_POST_SWITCH au HAL pour indiquer la réussite ou l'échec du commutateur.

Le HAL doit attendre la réponse ANDROID_POST_SWITCH pour mettre à jour son état afin de synchroniser les ECU ou de mettre à jour d'autres propriétés HAL.

Exemple:En se déplaçant, un conducteur tente de changer d'utilisateur Android dans l'interface d'infoloisirs. Toutefois, comme les paramètres du siège de voiture sont associés à l'utilisateur Android, le siège bouge lors du changement d'utilisateur. Par conséquent, l'ECU qui contrôle les sièges ne confirme pas le changement, le HAL répond par une erreur et l'utilisateur Android n'est pas basculé.

L'ancien workflow est un appel à sens unique envoyé après le transfert de l'utilisateur (de sorte que le HAL ne puisse pas bloquer le transfert). Elle n'est appelée qu'au démarrage (après le changement d'utilisateur initial) ou pour les applications qui appellent ActivityManager.switchUser() au lieu de CarUserManager.switchUser(). Les applications de référence Settings et SystemUI utilisent déjà la première, mais si un OEM fournit ses propres applications de paramètres pour changer d'utilisateur, il doit modifier l'utilisation.

Exemple:Si une application utilise ActivityManager.switchUser() pour changer d'utilisateur, un appel à sens unique est envoyé au HAL pour l'informer qu'un changement d'utilisateur a eu lieu.

Le workflow du véhicule provient du HAL, et non du système Android:

  1. Le HAL demande un changement d'utilisateur.
  2. Le système termine le changement d'utilisateur Android.
  3. Android envoie une réponse ANDROID_POST_SWITCH au HAL pour indiquer le succès ou l'échec du commutateur.

Exemple:Bob a utilisé la télécommande d'Alice pour ouvrir la voiture, et le HAL a répondu à la requête INITIAL_USER_INFO avec l'ID utilisateur d'Alice. Ensuite, un ECU de capteur biométrique a identifié le conducteur comme étant Bob. Le HAL utilisateur a donc envoyé une requête SWITCH_USER pour changer d'utilisateur.

CREATE_USER
(lecture/écriture)
Cette propriété est appelée par le système Android lorsqu'un nouvel utilisateur Android est créé (à l'aide de l'API CarUserManager.createUser()).

Le HAL répond par SUCCESS ou FAILURE. Si le HAL répond avec un échec, le système Android supprime l'utilisateur.

Exemple:Un conducteur appuie sur une icône d'interface utilisateur d'infoloisirs pour créer un utilisateur Android. Une requête est alors envoyée au HAL et au reste des sous-systèmes du véhicule. Les ECU sont informés de l'utilisateur nouvellement créé. Les autres sous-systèmes et ECU associent ensuite leur ID utilisateur interne à l'ID utilisateur Android.

REMOVE_USER
(ÉCRITURE uniquement)
Le système Android appelle cette propriété après la suppression d'un utilisateur Android (avec la méthode CarUserManager.removeUser()).

Il s'agit d'un appel à sens unique. Aucune réponse n'est attendue de la part du HAL.

Exemple:Un conducteur appuie pour supprimer un utilisateur Android existant dans l'interface utilisateur du système d'infodivertissement. Le HAL est informé de la suppression de l'utilisateur, ainsi que les autres sous-systèmes du véhicule et les unités de calcul intensif afin qu'ils puissent supprimer leur ID utilisateur interne.

Propriétés supplémentaires

Les propriétés suivantes sont supplémentaires et n'ont aucun lien avec les états du cycle de vie des utilisateurs. Chacun d'eux peut être implémenté sans prendre en charge le HAL de l'utilisateur.

Propriété HAL Description
USER_IDENTIFICATION_ASSOCIATION
(lecture/écriture)
Utilisez cette propriété pour associer un utilisateur Android à un mécanisme d'identification, tel qu'une clé sans contact ou un téléphone. Utilisez cette même propriété pour les associations get ou set.

Exemple:Un conducteur appuie sur une icône d'interface utilisateur d'infoloisirs pour associer la clé sans contact utilisée pour ouvrir le véhicule (KEY_123) à l'utilisateur Android actif actuel (USER_11).

Bibliothèques d'aide

Tous les objets utilisés dans les messages de requête et de réponse (tels que UserInfo, InitialUserInfoRequest, InitialUSerInfoResponse, etc.) ont une représentation de haut niveau avec struct C++, mais la suppression doit être aplatie en objets VehiclePropValue standards (voir les exemples ci-dessous). Pour faciliter le développement, une bibliothèque d'assistance C++ est fournie dans AOSP pour convertir automatiquement l'structs HAL utilisateur en VehiclePropValue (et inversement).

Exemples

INITIAL_USER_INFO

Exemple de requête (au premier démarrage)

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
}

Exemple de réponse (création d'un utilisateur administrateur)

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

Le nom réel des classes et des propriétés diffère légèrement, mais le workflow global est le même, comme illustré dans la figure:

Workflow

Figure 1 : Workflow des propriétés HAL utilisateur.

Exemple de requête de workflow moderne

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

Exemple de réponse de workflow moderne

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
}

Exemple de réponse à un workflow moderne après un basculement

Cette réponse se produit généralement lorsqu'un bouton Android aboutit:

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

Réponse après le changement de workflow moderne

Cette réponse se produit généralement lorsqu'un bouton Android échoue:

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

Exemple de requête de workflow ancien

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

Exemple de demande de workflow de véhicule

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
}

Réponse de l'ancien workflow après le basculement

Cette réponse se produit généralement lorsqu'un bouton Android aboutit:

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

Exemple de requête

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

Exemple de réponse

VehiclePropValue { // flattened from CreateUserResponse
prop: 299896585 // CREATE_USER
prop.values.int32Values:
 [0] = 42        // Request ID (must match request)
 [1] = 3         // CreateUserStatus::SUCCESS
}

SUPPRIMER L'UTILISATEUR

Exemple de requête

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 (ASSOCIATION_UTILISATEUR)

Exemple de configuration (clé sans contact associée à l'utilisateur 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
}