Propiedades de HAL del usuario

Muchas arquitecturas de vehículos actuales contienen varias unidades de control electrónico (ECU) fuera del sistema de infoentretenimiento que controlan la ergonomía, como la configuración de los asientos y los ajustes de los espejos. Según las arquitecturas actuales de hardware y energía, muchas ECU se encienden antes de que se encienda el sistema de infoentretenimiento basado en Android. Estas ECU pueden interactuar con un sistema de infoentretenimiento basado en Android a través de la capa de abstracción de hardware del vehículo (VHAL).

A partir de Android 11, el SO Android Automotive (AAOS) introdujo un nuevo conjunto de propiedades en el VHAL para crear, cambiar, quitar y asociar accesorios externos para identificar a los usuarios. Por ejemplo, estas propiedades nuevas permiten que un conductor vincule un accesorio externo, como un llavero electrónico, a su usuario de Android. Luego, cuando el conductor se acerca al vehículo, se activa una ECU y detecta el llavero electrónico. Esta ECU le indica al HAL qué usuario de Android debe iniciar el sistema de infoentretenimiento, lo que reduce el tiempo que un conductor espera a que se cargue su usuario de Android.

Habilita el sistema HAL del usuario

Las propiedades de HAL del usuario deben habilitarse de forma explícita. Para ello, asegúrate de que la propiedad del sistema android.car.user_hal_enabled esté configurada en true. (Puedes hacerlo en el archivo car.mk, de modo que no deba configurarse manualmente). Para verificar que user_hal_enabled=true esté habilitado, volca UserHalService:

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

También puedes verificar user_hal_enabled con adb shell getprop android.car.user_hal_enabled o adb logcat CarServiceHelper *:s. Si la propiedad está inhabilitada, se muestra un mensaje como el siguiente cuando se inicia system_server:

I CarServiceHelper: Not using User HAL

Para habilitar user_hal_enabled de forma manual, establece la propiedad del sistema android.car.user_hal_enabled y reinicia system_server:

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

El resultado de logcat aparece de la siguiente manera:

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

Propiedades del sistema HAL del usuario

Propiedades del ciclo de vida del usuario

Las siguientes propiedades proporcionan la información de HAL para los estados del ciclo de vida del usuario, que permiten la sincronización del ciclo de vida del usuario entre el sistema Android y una ECU externa. Estas propiedades usan un protocolo de solicitud y respuesta, en el que el sistema Android realiza una solicitud configurando un valor de propiedad y el HAL responde emitiendo un evento de cambio de propiedad.

Nota: Cuando se admite el sistema HAL del usuario, se deben implementar todas las siguientes propiedades.

Propiedad HAL Descripción
INITIAL_USER_INFO
(lectura/escritura)
El sistema Android llama a esta propiedad para determinar qué usuario de Android inicia el sistema cuando el dispositivo se inicia o se reanuda desde la suspensión en la RAM (STR). Cuando se la llama, la HAL debe responder con una de las siguientes opciones:
  • El comportamiento predeterminado que establece Android (cambiar al último usuario usado o crear uno nuevo si es el primer inicio).
  • Cambia a un usuario existente.
  • Crea un usuario nuevo (con las propiedades opcionales de nombre, marcas, configuración regional del sistema, etc.) y cambia a ese usuario nuevo.

Nota: Si el sistema HAL no responde, el comportamiento predeterminado es ejecutarse después de un período de tiempo de espera (cinco segundos de forma predeterminada), lo que retrasa el inicio. Si el HAL responde, pero el sistema Android no ejecuta la acción (por ejemplo, si se alcanzó la cantidad máxima de usuarios), se usa el comportamiento predeterminado.

Ejemplo: De forma predeterminada, el sistema Android se inicia en el último usuario activo durante el inicio. Si se detecta un llavero electrónico para un usuario diferente, la ECU anula la propiedad HAL y, durante el inicio, el sistema Android cambia para iniciarse en ese usuario especificado.

SWITCH_USER
(lectura/escritura)
Se llama a esta propiedad cuando se cambia el usuario activo en primer plano de Android. El sistema Android o el HAL pueden llamar a la propiedad para solicitar un cambio de usuario. Los tres flujos de trabajo son los siguientes:
  • Moderno. El interruptor se inició desde CarUserManager.
  • Heredado. Se inició el cambio desde ActivityManager.
  • Vehículo. La HAL lo llama para solicitar un cambio de usuario.

El flujo de trabajo moderno usa un enfoque de confirmación de dos fases para garantizar que el sistema Android y la ECU externa estén sincronizados. Cuando Android inicia el cambio, sucede lo siguiente:

  1. Verifica la HAL para determinar si se puede cambiar de usuario.

    El sistema HAL responde con SUCCESS o FAILURE, de modo que Android sepa si debe continuar o no.

  2. Completa el cambio de usuario de Android.

    Android envía una respuesta ANDROID_POST_SWITCH al HAL para indicar si el cambio se realizó correctamente o falló.

El sistema HAL debe esperar hasta después de la respuesta ANDROID_POST_SWITCH para actualizar su estado y sincronizar las ECU o actualizar otras propiedades del sistema HAL.

Ejemplo: Mientras el vehículo está en movimiento, el conductor intenta cambiar de usuario de Android en la IU de infoentretenimiento. Sin embargo, como la configuración del asiento del automóvil está vinculada al usuario de Android, el asiento se mueve durante el cambio de usuario. Por lo tanto, la ECU que controla los asientos no confirma el cambio, la HAL responde con una falla y el usuario de Android no se cambia.

El flujo de trabajo heredado es una llamada unidireccional que se envía después de que se cambia el usuario (por lo que el HAL no puede bloquear el cambio). Solo se llama durante el inicio (después del cambio de usuario inicial) o para las apps que llaman a ActivityManager.switchUser() en lugar de CarUserManager.switchUser(). Las apps de referencia Settings y SystemUI ya usan la última, pero si un OEM proporciona sus propias apps de Configuración para cambiar de usuario, los OEMs deben cambiar el uso.

Ejemplo: Si una app usa ActivityManager.switchUser() para cambiar de usuario, se envía una llamada unidireccional a la HAL para informar que se realizó un cambio de usuario.

El flujo de trabajo del vehículo se origina en el HAL, no en el sistema Android:

  1. La HAL solicita un cambio de usuario.
  2. El sistema completa el cambio de usuario de Android.
  3. Android envía una respuesta ANDROID_POST_SWITCH al HAL para indicar si el cambio se realizó correctamente o falló.

Ejemplo: Roberto usó el llavero de Alice para abrir el vehículo y la HAL respondió a la solicitud de INITIAL_USER_INFO con el ID de usuario de Alice. A continuación, una ECU del sensor biométrico identificó al conductor como Roberto, por lo que el HAL del usuario envió una solicitud SWITCH_USER para cambiar de usuario.

CREATE_USER
(lectura/escritura)
El sistema Android llama a esta propiedad cuando se crea un usuario nuevo de Android (con la API de CarUserManager.createUser()).

El sistema HAL responde con SUCCESS o FAILURE. Si el HAL responde con una falla, el sistema Android quita al usuario.

Ejemplo: Un conductor presiona un ícono de la IU de infoentretenimiento para crear un usuario nuevo de Android. Esto envía una solicitud al sistema HAL y al resto de los subsistemas del vehículo. Se informa a las ECU sobre el usuario recién creado. Luego, otros subsistemas y ECUs asocian su ID de usuario interno con el ID de usuario de Android.

REMOVE_USER
(solo ESCRITURA)
El sistema Android llama a esta propiedad después de que se quita un usuario de Android (con el método CarUserManager.removeUser()).

Esta es una llamada unidireccional, por lo que no se espera una respuesta del HAL.

Ejemplo: Un conductor presiona para quitar un usuario de Android existente en la IU de infoentretenimiento. Se informa al sistema HAL y a otros subsistemas y ECU del vehículo sobre la eliminación del usuario para que puedan quitar su ID de usuario interno.

Propiedades adicionales

Las siguientes son propiedades adicionales que no están relacionadas con los estados del ciclo de vida del usuario. Cada uno se puede implementar sin admitir el HAL del usuario.

Propiedad de HAL Descripción
USER_IDENTIFICATION_ASSOCIATION
(lectura/escritura)
Usa esta propiedad para asociar cualquier usuario de Android con un mecanismo de identificación, como un llavero electrónico o un teléfono. Usa esta misma propiedad para las asociaciones get o set.

Ejemplo: Un conductor presiona un ícono de la IU de infoentretenimiento para asociar el llavero electrónico que se usa para abrir el vehículo (KEY_123) al usuario activo de Android actual (USER_11).

Bibliotecas auxiliares

Todos los objetos usados en los mensajes de solicitud y respuesta (como UserInfo, InitialUserInfoRequest, InitialUSerInfoResponse, etc.) tienen una representación de alto nivel con struct de C++, pero la eliminación debe acoplarse a objetos VehiclePropValue estándar (consulta los ejemplos a continuación). Para facilitar el desarrollo, se proporciona una biblioteca de ayuda de C++ en AOSP para convertir automáticamente el structs de HAL del usuario en un VehiclePropValue (y viceversa).

Ejemplos

INITIAL_USER_INFO

Ejemplo de solicitud (en el primer inicio)

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
}

Ejemplo de respuesta (crear usuario administrador)

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

El nombre real de las clases y las propiedades difiere ligeramente, pero el flujo de trabajo general es el mismo, como se ilustra en la siguiente imagen:

Flujo de trabajo

Figura 1: Flujo de trabajo de las propiedades del HAL del usuario.

Ejemplo de solicitud de flujo de trabajo moderno

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

Ejemplo de respuesta de flujo de trabajo moderno

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
}

Ejemplo de respuesta posterior al cambio de flujo de trabajo moderno

Por lo general, esta respuesta ocurre cuando un interruptor de Android se realiza correctamente:

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

Respuesta posterior al cambio del flujo de trabajo moderno

Por lo general, esta respuesta ocurre cuando falla un interruptor de 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)
}

Ejemplo de solicitud de flujo de trabajo heredado

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

Ejemplo de solicitud de flujo de trabajo de vehículos

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
}

Respuesta después del cambio de flujo de trabajo heredado

Por lo general, esta respuesta ocurre cuando un cambio de Android se realiza correctamente:

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

Ejemplo de solicitud

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

Ejemplo de respuesta

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

REMOVE_USER

Ejemplo de solicitud

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

Establecer ejemplo (llavero de seguridad asociado con el Usuario 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
}