Molte architetture dei veicoli attuali contengono più unità di controllo elettronico (ECU) al di fuori del sistema di infotainment che controllano l'ergonomia, ad esempio le impostazioni dei sedili e la regolazione degli specchietti. In base alle attuali architetture hardware e di alimentazione, molte ECU si accendono prima del sistema di infotainment basato su Android. Queste ECU possono interfacciarsi con un sistema di infotainment basato su Android tramite il Vehicle Hardware Abstraction Layer (VHAL).
A partire da Android 11, il sistema operativo Android Automotive (AAOS) ha introdotto un nuovo insieme di proprietà nel VHAL per creare, cambiare, rimuovere e associare accessori esterni per identificare gli utenti. Ad esempio, queste nuove proprietà consentono a un conducente di accoppiare un accessorio esterno, come un telecomando, al proprio utente Android. Quando il conducente si avvicina al veicolo, un'ECU si riattiva e rileva il telecomando. Questa ECU indica all'HAL quale utente Android deve avviare il infotainment, il che riduce il tempo di attesa del conducente per il caricamento dell'utente Android.
Attivare l'HAL utente
Le proprietà HAL utente devono essere attivate esplicitamente assicurandosi che la proprietà android.car.user_hal_enabled
del sistema sia impostata su true
.
Puoi eseguire questa operazione nel file car.mk
, in modo che non sia necessario
impostarla manualmente. Verifica che user_hal_enabled=true
sia attivato dumpando UserHalService
:
$ adb shell dumpsys car_service --hal UserHalService|grep enabled user_hal_enabled=true
Puoi anche controllare user_hal_enabled
utilizzando adb shell
getprop android.car.user_hal_enabled
o adb logcat
CarServiceHelper *:s
. Se la proprietà è disattivata, viene visualizzato un messaggio simile al seguente quando viene avviato system_server
:
I CarServiceHelper: Not using User HAL
Per attivare manualmente user_hal_enabled
, imposta la proprietà di sistema android.car.user_hal_enabled
e riavvia system_server
:
$ adb shell setprop android.car.user_hal_enabled true $ adb shell stop && adb shell start
L'output logcat
viene visualizzato come segue:
I CarServiceHelper: User HAL enabled with timeout of 5000ms D CarServiceHelper: Got result from HAL: OK I CarServiceHelper: User HAL returned DEFAULT behavior
Proprietà HAL utente
Proprietà del ciclo di vita dell'utente
Le seguenti proprietà forniscono le informazioni HAL per gli stati del ciclo di vita dell'utente, che consentono la sincronizzazione del ciclo di vita dell'utente tra il sistema Android e un'ECU esterna. Queste proprietà utilizzano un protocollo di richiesta e risposta, in cui il sistema Android effettua una richiesta impostando un valore della proprietà e l'HAL risponde emettendo un evento di modifica della proprietà.
Nota: se l'HAL utente è supportato, è necessario implementare tutte le seguenti proprietà.
proprietà HAL | Descrizione |
---|---|
INITIAL_USER_INFO (lettura/scrittura) |
Questa proprietà viene chiamata dal sistema Android per determinare quale utente Android viene avviato dal sistema all'avvio del dispositivo o al riavvio da Sospensione in RAM (STR). Quando viene chiamato, l'HAL deve rispondere con una di queste opzioni:
Nota: se l'HAL non risponde, il comportamento predefinito è eseguire l'operazione dopo un periodo di timeout (cinque secondi per impostazione predefinita), il che ritarda l'avvio. Se l'HAL risponde, ma il sistema Android non riesce a eseguire l'azione (ad esempio se è stato raggiunto il numero massimo di utenti), viene utilizzato il comportamento predefinito. Esempio: per impostazione predefinita, il sistema Android si avvia nell'ultimo utente attivo all'avvio. Se viene rilevato un telecomando per un altro utente, l'ECU sostituisce la proprietà HAL e, durante l'avvio, il sistema Android passa all'avvio nell'utente specificato. |
SWITCH_USER (lettura/scrittura) |
Questa proprietà viene chiamata quando si cambia l'utente Android attivo in primo piano.
La proprietà può essere chiamata dal sistema Android o dall'HAL per
richiedere il passaggio di un utente. I tre flussi di lavoro sono:
Il flusso di lavoro moderno utilizza un approccio di commit in due fasi per garantire la sincronizzazione del sistema Android e dell'ECU esterna. Quando Android avvia il trasferimento:
L'HAL deve attendere la risposta Esempio: durante la guida, un conducente tenta di cambiare utente Android nell'interfaccia utente dell'infotainment. Tuttavia, poiché le impostazioni del sedile dell'auto sono legate all'utente Android, il sedile si sposta durante il cambio dell'utente. Di conseguenza, la ECU che controlla i posti non conferma il cambio, l'HAL risponde con un errore e l'utente Android non viene commutato.
Il flusso di lavoro Legacy è una chiamata unidirezionale inviata dopo il trasferimento dell'utente
(quindi l'HAL non può bloccare il trasferimento). Viene chiamato solo all'avvio (dopo il cambio iniziale dell'utente) o per le app che chiamano
Esempio: se un'app utilizza
Il flusso di lavoro del veicolo ha origine dall'HAL, non dal sistema Android:
Esempio: Bob ha usato il telecomando di Alice per aprire l'auto
e l'HAL ha risposto alla richiesta |
CREATE_USER (lettura/scrittura) |
Questa proprietà viene chiamata dal sistema Android quando viene creato un nuovo utente Android (utilizzando l'API CarUserManager.createUser() ).
L'HAL risponde con Esempio: un conducente tocca un'icona dell'interfaccia utente dell'infotainment per creare un nuovo utente Android. Viene inviata una richiesta all'HAL e al resto dei sottosistemi del veicolo. Le ECU vengono informate dell'utente appena creato. Altri sottosistemi e ECU associano il proprio ID utente interno all'ID utente Android. |
REMOVE_USER (solo SCRITTURA) |
Il sistema Android chiama questa proprietà dopo la rimozione di un utente Android (con il metodo CarUserManager.removeUser() ).
Si tratta di una chiamata unidirezionale, non è prevista alcuna risposta dall'HAL. Esempio: un conducente tocca per rimuovere un utente Android esistente nell'interfaccia utente del sistema di infotainment. L'HAL viene informato e gli altri sottosistemi e le ECU del veicolo vengono informati della rimozione dell'utente in modo da poter rimuovere il proprio ID utente interno. |
Proprietà aggiuntive
Di seguito sono riportate proprietà aggiuntive non correlate agli stati del ciclo di vita dell'utente. Ciascuno può essere implementato senza supportare l'HAL utente.
proprietà HAL | Descrizione |
---|---|
USER_IDENTIFICATION_ASSOCIATION (lettura/scrittura) |
Utilizza questa proprietà per associare qualsiasi utente Android a un meccanismo di identificazione, ad esempio un telecomando o uno smartphone. Utilizza la stessa proprietà per le associazioni get o set .
Esempio: un conducente tocca un'icona dell'interfaccia utente di infotainment per associare il telecomando usato per aprire il veicolo ( |
Librerie helper
Tutti gli oggetti utilizzati nei messaggi di richiesta e risposta (ad esempio
UserInfo
, InitialUserInfoRequest
,
InitialUSerInfoResponse
e così via) hanno una rappresentazione di alto livello
che utilizza struct
C++, ma la rimozione deve essere appiattata in
oggetti struct
standard (vedi gli esempi di seguito).VehiclePropValue
Per facilità di sviluppo, in AOSP viene fornita una libreria helper C++ per convertire automaticamente l'HAL dell'utente structs
in un VehiclePropValue
(e viceversa).
Esempi
INITIAL_USER_INFO
Esempio di richiesta (al primo avvio)
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 }
Esempio di risposta (crea utente amministratore)
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
Il nome effettivo delle classi e delle proprietà è leggermente diverso, ma il flusso di lavoro complessivo è lo stesso, come illustrato nella figura:
Figura 1. Flusso di lavoro delle proprietà HAL utente.
Esempio di richiesta di flusso di lavoro 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) }
Esempio di risposta moderna per un flusso di lavoro
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 }
Esempio di risposta post-cambio di un flusso di lavoro moderno
Questa risposta si verifica in genere quando il trasferimento da Android ha esito positivo:
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) }
Risposta del flusso di lavoro moderno dopo il passaggio
Questa risposta si verifica in genere quando si verifica un errore di trasferimento su 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) }
Esempio di richiesta di flusso di lavoro precedente
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) }
Esempio di richiesta del flusso di lavoro del veicolo
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 }
Risposta al flusso di lavoro precedente dopo il passaggio
Questa risposta si verifica in genere quando il trasferimento da Android ha esito positivo:
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
Esempio di richiesta
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) }
Esempio di risposta
VehiclePropValue { // flattened from CreateUserResponse prop: 299896585 // CREATE_USER prop.values.int32Values: [0] = 42 // Request ID (must match request) [1] = 3 // CreateUserStatus::SUCCESS }
REMOVE_USER
Esempio di richiesta
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
Esempio di set (telecomando associato all'utente 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 }