Proprietà HAL dell'utente

Molte attuali architetture di veicoli contengono più unità di controllo elettronico (ECU) esterne al sistema di infotainment che controllano l'ergonomia, come le impostazioni del sedile e la regolazione degli specchietti. Sulla base delle attuali architetture hardware e di alimentazione, molte ECU si accendono prima che venga acceso il sistema di infotainment basato su Android. Queste ECU possono interfacciarsi con un sistema di infotainment basato su Android attraverso il livello di astrazione dell'hardware del veicolo (VHAL) .

A partire da Android 11, il sistema operativo Android Automotive (AAOS) ha introdotto un nuovo set di proprietà sul VHAL per creare, cambiare, rimuovere e associare accessori esterni per identificare gli utenti. Ad esempio, queste nuove proprietà consentono a un conducente di associare un accessorio esterno, come un portachiavi, al proprio utente Android. Quindi, quando il conducente si avvicina al veicolo, una ECU si attiva e rileva la chiave. Questa ECU indica all'HAL quale utente Android l'infotainment dovrebbe avviare l'avvio, riducendo il tempo di attesa del conducente per il caricamento del proprio utente Android.

Abilita l'HAL utente

Le proprietà HAL utente devono essere abilitate esplicitamente assicurandosi che la proprietà di sistema android.car.user_hal_enabled sia impostata su true . (Questo può essere fatto anche nel file car.mk , in modo che non sia necessario impostarlo manualmente.) Controlla che user_hal_enabled=true sia abilitato scaricando 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à è disabilitata, all'avvio system_server viene visualizzato un messaggio simile al seguente:

I CarServiceHelper: Not using User HAL

Per abilitare 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 appare 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 dell'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 abilitano 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 di proprietà e l'HAL risponde emettendo un evento di modifica della proprietà.

Nota: quando è supportato l'HAL utente, è necessario implementare tutte le seguenti proprietà.

Proprietà HAL Descrizione
INITIAL_USER_INFO
(LEGGERE SCRIVERE)
Questa proprietà viene chiamata dal sistema Android per determinare quale utente Android viene avviato dal sistema quando il dispositivo si avvia o riprende da Suspend-to-RAM (STR). Quando viene chiamato, l'HAL deve rispondere con una di queste opzioni:
  • Il comportamento predefinito impostato da Android (passaggio all'ultimo utente utilizzato o creazione di un nuovo utente se questo è il primo avvio).
  • Passa a un utente esistente.
  • Crea un nuovo Utente (con le proprietà facoltative di nome, flag, impostazioni locali del sistema e così via) e passa a quel nuovo Utente.

Nota: se l'HAL non risponde, il comportamento predefinito prevede l'esecuzione dopo un periodo di timeout (cinque secondi per impostazione predefinita), 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 con l'ultimo utente attivo all'avvio. Se viene rilevato un telecomando per un utente diverso, l'ECU sovrascrive la proprietà HAL e, durante l'avvio, il sistema Android passa all'avvio in quell'utente specificato.

SWITCH_USER
(LEGGERE SCRIVERE)
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 un cambio utente. I tre flussi di lavoro sono:
  • Moderno. Passaggio avviato da CarUserManager .
  • Eredità. Passaggio avviato da ActivityManager .
  • Veicolo. Chiamato dall'HAL per richiedere un cambio utente.

Il flusso di lavoro Modern utilizza un approccio di commit in due fasi per garantire che il sistema Android e l'ECU esterna siano sincronizzati. Quando Android avvia il passaggio:

  1. Controllare l'HAL per determinare se è possibile cambiare utente.

    L'HAL risponde con SUCCESS o FAILURE , in modo che Android sappia se procedere o meno.

  2. Completa il cambio utente Android.

    Android invia una risposta ANDROID_POST_SWITCH all'HAL per indicare l'esito positivo o negativo del passaggio.

L'HAL dovrebbe attendere fino a dopo la risposta ANDROID_POST_SWITCH per aggiornare il proprio stato per sincronizzare le ECU o aggiornare altre proprietà HAL.

Esempio: mentre è in movimento, un conducente tenta di cambiare utente Android nell'interfaccia utente dell'infotainment. Tuttavia, poiché le impostazioni del seggiolino auto sono legate all'utente Android, il sedile si sposta durante il cambio utente. Pertanto, l'ECU che controlla i sedili non conferma il cambio, l'HAL risponde con un errore e l'utente Android non viene cambiato.

Il flusso di lavoro Legacy è una chiamata unidirezionale inviata dopo il cambio dell'utente (quindi l'HAL non può bloccare il cambio). Viene chiamato solo all'avvio (dopo il cambio utente iniziale) o per le app che chiamano ActivityManager.switchUser() invece di CarUserManager.switchUser() . Le app Settings di riferimento e SystemUI utilizzano già quest'ultima, ma se un OEM fornisce le proprie app Impostazioni per cambiare utente, gli OEM dovrebbero modificare l'utilizzo.

Esempio: se un'app utilizza ActivityManager.switchUser() per cambiare utente, viene inviata una chiamata unidirezionale all'HAL per informare che è avvenuto un cambio di utente.

Il flusso di lavoro del veicolo ha origine dall'HAL, non dal sistema Android:

  1. L'HAL richiede un cambio utente.
  2. Il sistema completa il cambio utente Android.
  3. Android invia una risposta ANDROID_POST_SWITCH all'HAL per indicare l'esito positivo o negativo del passaggio.

Esempio: Bob ha utilizzato il portachiavi di Alice per aprire l'auto e l'HAL ha risposto alla richiesta INITIAL_USER_INFO con l'ID utente di Alice. Successivamente, un sensore biometrico ECU ha identificato il conducente come Bob, quindi l'HAL dell'utente ha inviato una richiesta SWITCH_USER per cambiare utente.

CREATE_USER
(LEGGERE SCRIVERE)
Questa proprietà viene chiamata dal sistema Android quando viene creato un nuovo utente Android (utilizzando l'API CarUserManager.createUser() ).

L'HAL risponde con SUCCESS o FAILURE . Se l'HAL risponde con un errore, il sistema Android rimuove l'utente.

Esempio: un conducente tocca un'icona dell'interfaccia utente di infotainment per creare un nuovo utente Android. Ciò invia una richiesta all'HAL e al resto dei sottosistemi del veicolo. Le ECU vengono informate dell'Utente appena creato. Altri sottosistemi ed ECU associano quindi il loro ID utente interno all'ID utente Android.

REMOVE_USER
(Solo SCRITTURA)
Il sistema Android chiama questa proprietà dopo che un utente Android è stato rimosso (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 dell'infotainment. L'HAL viene informato e gli altri sottosistemi del veicolo e le ECU vengono informati della rimozione dell'utente in modo che possano 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 dell'utente.

Proprietà HAL Descrizione
USER_IDENTIFICATION_ASSOCIATION
(LEGGERE SCRIVERE)
Utilizza questa proprietà per associare qualsiasi utente Android a un meccanismo di identificazione, come un portachiavi o un telefono. Utilizzare questa stessa proprietà per get o set associazioni.

Esempio: un conducente tocca un'icona dell'interfaccia utente di infotainment per associare la chiave utilizzata per aprire il veicolo ( KEY_123 ) all'utente Android attualmente attivo ( USER_11 ).

Biblioteche di aiuto

Tutti gli oggetti utilizzati nei messaggi di richiesta e risposta (come UserInfo , InitialUserInfoRequest , InitialUSerInfoResponse e così via) hanno una rappresentazione di alto livello utilizzando C++ struct , ma la rimozione deve essere appiattita in oggetti VehiclePropValue standard (vedere gli esempi seguenti). Per facilitare lo sviluppo, in AOSP viene fornita una libreria helper C++ per convertire automaticamente structs HAL dell'utente in VehiclePropValue (e viceversa).

Esempi

INITIAL_USER_INFO

Richiedi esempio (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
}

CAMBIA UTENTE

Il nome effettivo delle classi e delle proprietà differisce leggermente ma il flusso di lavoro complessivo è lo stesso, come illustrato di seguito:

Flusso di lavoro

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 del flusso di lavoro 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
}

Esempio di risposta post-switch del flusso di lavoro moderno

Questa risposta si verifica in genere quando un passaggio ad 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 post-switch del flusso di lavoro moderno

Questa risposta si verifica in genere quando un passaggio ad Android non riesce:

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 legacy

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 di 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 post-passaggio del flusso di lavoro legacy

Questa risposta si verifica in genere quando un passaggio ad 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)
}

CREARE UN UTENTE

Richiedi esempio

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
}

RIMUOVI_UTENTE

Richiedi esempio

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 (portachiavi 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
}