Proprietà HAL dell'utente

Molte architetture di veicoli attuali contengono più unità di controllo elettroniche (ECU) al di fuori del sistema di infotainment che controllano l'ergonomia, come le impostazioni del sedile e le regolazioni degli specchietti. Basate sull'hardware e sulle architetture di alimentazione attuali, molte centraline si accendono prima che il sistema di infotainment basato su Android venga acceso. Queste centraline possono interfacciarsi con un sistema di infotainment basato su Android tramite il Vehicle Hardware Abstraction Layer (VHAL) .

A partire da Android 11, Android Automotive OS (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 accoppiare un accessorio esterno, come un portachiavi, al proprio utente Android. Quindi, quando il conducente si avvicina al veicolo, una ECU si riattiva e rileva il portachiavi. Questa ECU indica all'HAL quale utente Android l'infotainment deve avviare un avvio, il che riduce il tempo di attesa del conducente per il caricamento del proprio utente Android.

Abilita l'HAL utente

Le proprietà User HAL 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 come il seguente:

I CarServiceHelper: Not using User HAL

Per abilitare manualmente user_hal_enabled , impostare la proprietà di sistema android.car.user_hal_enabled e riavviare 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 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 verrà avviato dal sistema all'avvio o al ripristino del dispositivo 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, locale di 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 viene avviato nell'ultimo Utente attivo all'avvio. Se viene rilevato un telecomando per un utente diverso, la 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 in primo piano attivo. La proprietà può essere chiamata sia dal sistema Android che 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 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 passaggio dell'utente Android.

    Android invia una risposta ANDROID_POST_SWITCH 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 ECU o aggiornare altre proprietà HAL.

Ad esempio, mentre è in movimento, un conducente tenta di cambiare gli utenti Android nell'interfaccia utente di infotainment. Tuttavia, poiché le impostazioni del seggiolino per auto sono legate all'utente Android, il sedile si sposterà durante il passaggio dell'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 il passaggio dell'utente (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 di riferimento Settings e SystemUI utilizzano già quest'ultimo, 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 passaggio dell'utente Android.
  3. Android invia una risposta ANDROID_POST_SWITCH per indicare l'esito positivo o negativo del passaggio.

Ad esempio , Bob ha utilizzato il telecomando 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'utente HAL 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 ECU vengono informate dell'Utente appena creato. Altri sottosistemi ed ECU associano quindi 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 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 di 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.

Ulteriori proprietà

Le seguenti sono 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
(LEGGERE SCRIVERE)
Utilizzare questa proprietà per associare qualsiasi Utente Android a un meccanismo di identificazione, ad esempio un telecomando o un telefono. Utilizzare questa stessa proprietà per get o set associazioni.

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

Librerie di supporto

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 VehiclePropValue standard (vedere gli esempi seguenti). Per facilitare lo sviluppo, in AOSP viene fornita una libreria di supporto C++ per convertire automaticamente le strutture HAL VehiclePropValue structs 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à è leggermente diverso, ma il flusso di lavoro generale è lo stesso, come illustrato di seguito:

Flusso di lavoro

Figura 1. Flusso di lavoro delle proprietà HAL dell'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 uno switch Android 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]   = 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-cambio 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-cambio del flusso di lavoro legacy

Questa risposta si verifica in genere quando uno switch Android riesce:

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
}

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

USER_IDENTIFICATION_ASSOCIATION

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