Proprietà HAL dell'utente

Molte architetture di veicoli attuali contengono più unità di controllo elettronico (ECU) al di fuori del sistema di infotainment che controllano l'ergonomia, come le impostazioni dei sedili e le regolazioni degli specchietti. In base all'hardware e alle architetture di alimentazione attuali, molte centraline 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 Vehicle Hardware Abstraction Layer (VHAL) .

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

Abilita l'HAL utente

Le proprietà dell'HAL utente devono essere abilitate in modo esplicito 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.) Verifica 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 usando 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 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 una 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 l'HAL utente è supportato, è 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 il sistema avvierà 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 si tratta del primo avvio).
  • Passa a un utente esistente.
  • Crea un nuovo utente (con le proprietà facoltative di nome, flag, locale 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 (5) 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.

Ad esempio, per impostazione predefinita, il sistema Android si avvia con l'ultimo utente attivo all'avvio. Se viene rilevato un portachiavi 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à. Switch avviato da ActivityManager .
  • Veicolo. Chiamato dall'HAL per richiedere un cambio utente.

Il flusso di lavoro moderno 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 l'utente può essere cambiato.

    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 suo stato per sincronizzare le centraline o aggiornare altre proprietà HAL.

Ad 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 sposterà durante il cambio utente. Pertanto, l'ECU che controlla i sedili non conferma il passaggio, l'HAL risponde con un errore e l'utente Android non viene commutato.

Il flusso di lavoro legacy è una chiamata unidirezionale inviata dopo che l'utente è stato cambiato (quindi l'HAL non può bloccare il passaggio). 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 e SystemUI di riferimento utilizzano già quest'ultima, ma se un OEM fornisce le proprie app Impostazioni per cambiare utente, gli OEM dovrebbero modificare l'utilizzo.

Ad esempio, se un'app utilizza ActivityManager.switchUser() per cambiare utente, viene inviata una chiamata unidirezionale all'HAL per informare che è avvenuto un cambio 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.

Ad 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, una ECU del sensore biometrico ha identificato il conducente come Bob, quindi l'HAL 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.

Ad esempio, un conducente tocca un'icona dell'interfaccia utente di infotainment per creare un nuovo utente Android. Questo invia una richiesta all'HAL e al resto dei sottosistemi del veicolo. Le centraline vengono informate dell'utente appena creato. Altri sottosistemi e ECU associano quindi il proprio ID utente interno all'ID utente Android.

REMOVE_USER
(solo SCRIVI)
Il sistema Android chiama questa proprietà dopo la rimozione di un utente Android (con l'API CarUserManager.removeUser() ).

Questa è una chiamata unidirezionale: non è prevista alcuna risposta dall'HAL.

Ad esempio, un conducente tocca per rimuovere un utente Android esistente nell'interfaccia utente dell'infotainment. L'HAL viene informato e altri sottosistemi e centraline del veicolo vengono informati della rimozione dell'utente in modo che possano rimuovere il proprio ID utente interno.

Ulteriori proprietà

Le seguenti sono proprietà aggiuntive, non correlate agli stati del ciclo di vita dell'utente. Ognuno può essere implementato senza supportare l'HAL utente.

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

Ad esempio, un conducente tocca un'icona dell'interfaccia utente di infotainment per associare il portachiavi utilizzato per aprire il veicolo (KEY_123) all'utente Android attivo corrente (USER_11).

Librerie ausiliarie

Tutti gli oggetti usati nei messaggi di richiesta e risposta (come UserInfo , InitialUserInfoRequest , InitialUSerInfoResponse e così via) hanno una rappresentazione di alto livello usando C++ struct , ma la rimozione deve essere appiattita in oggetti VehiclePropValue standard (vedere gli esempi seguenti). Per facilità di sviluppo, in AOSP viene fornita una libreria helper C++ per convertire automaticamente structs HAL dell'utente 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
}

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 uno switch 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 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 post-switch 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

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
}

RIMUOVERE_UTENTE

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

IDENTIFICAZIONE_UTENTE_ASSOCIAZIONE

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
}