È necessario utilizzare HIDL per descrivere tutti i flag di build utilizzati per la compilazione condizionale del framework. I flag di build pertinenti devono essere raggruppati e inclusi in un unico file .hal
. L'utilizzo di HIDL per specificare gli elementi di configurazione include i seguenti vantaggi:
- Versionato (per aggiungere nuovi elementi di configurazione, i fornitori/OEM devono estendere esplicitamente l'HAL)
- Ben documentato
- Controllo accessi tramite SELinux
- Verifica dell'integrità degli elementi di configurazione tramite la Vendor Test Suite (controllo dell'intervallo, verifica dell'interdipendenza tra gli elementi, ecc.)
- API generate automaticamente sia in C++ che in Java
Identificazione dei flag di build utilizzati dal framework
Inizia identificando le configurazioni di build utilizzate per compilare condizionalmente il framework, quindi abbandona le configurazioni obsolete per ridurre il set. Ad esempio, per surfaceflinger
viene identificato il seguente set di flag di build:
-
TARGET_USES_HWC2
-
TARGET_BOARD_PLATFORM
-
TARGET_DISABLE_TRIPLE_BUFFERING
-
TARGET_FORCE_HWC_FOR_VIRTUAL_DISPLAYS
-
NUM_FRAMEBUFFER_SURFACE_BUFFERS
-
TARGET_RUNNING_WITHOUT_SYNC_FRAMEWORK
-
VSYNC_EVENT_PHASE_OFFSET_NS
-
SF_VSYNC_EVENT_PHASE_OFFSET_NS
-
PRESENT_TIME_OFFSET_FROM_VSYNC_NS
-
MAX_VIRTUAL_DISPLAY_DIMENSION
Creazione di un'interfaccia HAL
Le configurazioni di build per un sottosistema sono accessibili tramite un'interfaccia HAL, mentre le interfacce per fornire valori di configurazione sono raggruppate nel pacchetto HAL android.hardware.configstore
(attualmente alla versione 1.0). Ad esempio, per creare un file di interfaccia HAL per surfaceflinger
, in hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal
:
package android.hardware.configstore@1.0; interface ISurfaceFlingerConfigs { // TO-BE-FILLED-BELOW };
Dopo aver creato il file .hal
, esegui hardware/interfaces/update-makefiles.sh
per aggiungere il nuovo file .hal
ai file Android.bp
e Android.mk
.
Aggiunta di funzioni per build flag
Per ogni flag di build, aggiungi una nuova funzione all'interfaccia. Ad esempio, in hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal
:
interface ISurfaceFlingerConfigs { disableTripleBuffering() generates(OptionalBool ret); forceHwcForVirtualDisplays() generates(OptionalBool ret); enum NumBuffers: uint8_t { USE_DEFAULT = 0, TWO = 2, THREE = 3, }; numFramebufferSurfaceBuffers() generates(NumBuffers ret); runWithoutSyncFramework() generates(OptionalBool ret); vsyncEventPhaseOffsetNs generates (OptionalUInt64 ret); presentTimeOffsetFromSyncNs generates (OptionalUInt64 ret); maxVirtualDisplayDimension() generates(OptionalInt32 ret); };
Quando si aggiunge una funzione:
- Sii conciso con i nomi. Evita di convertire i nomi delle variabili makefile in nomi di funzioni e tieni presente che i prefissi
TARGET_
eBOARD_
non sono più necessari. - Aggiungi commenti. Aiuta gli sviluppatori a comprendere lo scopo dell'elemento di configurazione, come cambia il comportamento del framework, i valori validi e altre informazioni rilevanti.
I tipi restituiti dalla funzione possono essere Optional[Bool|String|Int32|UInt32|Int64|UInt64]
. I tipi sono definiti in types.hal
nella stessa directory e racchiudono i valori primitivi con un campo che indica se il valore è specificato dall'HAL; in caso contrario, viene utilizzato il valore predefinito.
struct OptionalString { bool specified; string value; };
Se appropriato, definire l'enumerazione che rappresenta meglio il tipo dell'elemento di configurazione e utilizzare tale enum come tipo restituito. Nell'esempio precedente, l' NumBuffers
è definita per limitare il numero di valori validi. Quando si definiscono tali tipi di dati personalizzati, aggiungere un campo o un valore enum (ad esempio, USE_DEFAULT
) per indicare se il valore è/non è specificato dall'HAL.
Non è obbligatorio che un singolo flag di build diventi una singola funzione in HIDL. I proprietari dei moduli possono in alternativa aggregare flag di build strettamente correlati in uno struct e avere una funzione che restituisce tale struct (in questo modo è possibile ridurre il numero di chiamate di funzione).
Ad esempio, un'opzione per aggregare due flag di build in un'unica struttura in hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal
è:
interface ISurfaceFlingerConfigs { // other functions here struct SyncConfigs { OptionalInt64 vsyncEventPhaseoffsetNs; OptionalInt64 presentTimeoffsetFromSyncNs; }; getSyncConfigs() generates (SyncConfigs ret); // other functions here };
Alternative a una singola funzione HAL
In alternativa all'utilizzo di una singola funzione HAL per tutti i flag di build, l'interfaccia HAL fornisce anche funzioni semplici come getBoolean(string key)
e getInteger(string key)
. Le coppie key=value
effettive sono archiviate in file separati e il servizio HAL fornisce valori leggendo/analizzando quei file.
Sebbene questo approccio sia facile da definire, non include i vantaggi forniti da HIDL (versione forzata, facilità di documentazione, controllo degli accessi) e pertanto non è raccomandato.
Interfacce singole e multiple
Il design dell'interfaccia HAL per gli elementi di configurazione presenta due scelte:
- Un'unica interfaccia che copre tutti gli elementi di configurazione
- Interfacce multiple, ognuna delle quali copre una serie di elementi di configurazione correlati
Un'unica interfaccia è più semplice ma può diventare ingestibile poiché più elementi di configurazione vengono aggiunti al singolo file. Inoltre, il controllo dell'accesso non è a grana fine, quindi un processo a cui è concesso l'accesso all'interfaccia può leggere tutti gli elementi di configurazione (non è possibile concedere l'accesso a un set parziale di elementi di configurazione). In alternativa, se l'accesso non è concesso, gli elementi di configurazione non possono essere letti.
A causa di questi problemi, Android utilizza più interfacce con un'unica interfaccia HAL per un gruppo di elementi di configurazione correlati. Ad esempio, ISurfaceflingerConfigs
per surfaceflinger
di configurazione relativi a Surfaceflinger e IBluetoothConfigs
per elementi di configurazione relativi a Bluetooth.