Você deve usar HIDL para descrever todos os sinalizadores de construção usados para compilar condicionalmente a estrutura. Os sinalizadores de construção relevantes devem ser agrupados e incluídos em um único arquivo .hal
. Usar HIDL para especificar itens de configuração inclui os seguintes benefícios:
- Versionado (para adicionar novos itens de configuração, os fornecedores/OEMs devem estender explicitamente o HAL)
- Bem documentado
- Controle de acesso usando SELinux
- Verificação de integridade de itens de configuração por meio do Vendor Test Suite (verificação de intervalo, verificação de interdependência entre itens, etc.)
- APIs geradas automaticamente em C++ e Java
Identificando sinalizadores de build usados pela estrutura
Comece identificando as configurações de compilação usadas para compilar condicionalmente a estrutura e, em seguida, abandone as configurações obsoletas para diminuir o conjunto. Por exemplo, o seguinte conjunto de sinalizadores de construção é identificado para surfaceflinger
:
-
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
Criando uma interface HAL
As configurações de construção para um subsistema são acessadas por meio de uma interface HAL, enquanto as interfaces para fornecer valores de configuração são agrupadas no pacote HAL android.hardware.configstore
(atualmente na versão 1.0). Por exemplo, para criar um arquivo de interface HAL para surfaceflinger
, em hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal
:
package android.hardware.configstore@1.0; interface ISurfaceFlingerConfigs { // TO-BE-FILLED-BELOW };
Depois de criar o arquivo .hal
, execute hardware/interfaces/update-makefiles.sh
para adicionar o novo arquivo .hal
aos arquivos Android.bp
e Android.mk
.
Adicionando funções para sinalizadores de compilação
Para cada sinalizador de construção, adicione uma nova função à interface. Por exemplo, em 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); };
Ao adicionar uma função:
- Seja conciso com os nomes. Evite converter nomes de variáveis makefile em nomes de funções e tenha em mente que os prefixos
TARGET_
eBOARD_
não são mais necessários. - Adicione comentários. Ajude os desenvolvedores a entender a finalidade do item de configuração, como ele altera o comportamento da estrutura, os valores válidos e outras informações relevantes.
Os tipos de retorno de função podem ser Optional[Bool|String|Int32|UInt32|Int64|UInt64]
. Os tipos são definidos em types.hal
no mesmo diretório e agrupam os valores primitivos com um campo que indica se o valor é especificado pelo HAL; caso contrário, o valor padrão será usado.
struct OptionalString { bool specified; string value; };
Quando apropriado, defina o enum que melhor representa o tipo do item de configuração e use esse enum como tipo de retorno. No exemplo acima, o enum NumBuffers
é definido para limitar o número de valores válidos. Ao definir esses tipos de dados personalizados, adicione um campo ou um valor enum (por exemplo, USE_DEFAULT
) para indicar se o valor é/não é especificado pelo HAL.
Não é obrigatório que um único sinalizador de construção se torne uma única função no HIDL. Os proprietários do módulo podem, alternativamente, agregar sinalizadores de construção intimamente relacionados em uma estrutura e ter uma função que retorne essa estrutura (isso pode reduzir o número de chamadas de função).
Por exemplo, uma opção para agregar dois sinalizadores de construção em uma única estrutura em 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 };
Alternativas para uma única função HAL
Como alternativa ao uso de uma única função HAL para todos os sinalizadores de construção, a interface HAL também fornece funções simples, como getBoolean(string key)
e getInteger(string key)
. Os pares key=value
reais são armazenados em arquivos separados e o serviço HAL fornece valores lendo/analisando esses arquivos.
Embora esta abordagem seja fácil de definir, ela não inclui os benefícios fornecidos pelo HIDL (versão forçada, facilidade de documentação, controle de acesso) e, portanto, não é recomendada.
Interfaces únicas e múltiplas
O design da interface HAL para itens de configuração apresenta duas opções:
- Uma única interface que cobre todos os itens de configuração
- Múltiplas interfaces, cada uma cobrindo um conjunto de itens de configuração relacionados
Uma interface única é mais fácil, mas pode se tornar impossível de manter à medida que mais itens de configuração são adicionados ao arquivo único. Além disso, o controle de acesso não é refinado, portanto, um processo ao qual é concedido acesso à interface pode ler todos os itens de configuração (o acesso a um conjunto parcial de itens de configuração não pode ser concedido). Alternativamente, se o acesso não for concedido, os itens de configuração não poderão ser lidos.
Devido a esses problemas, o Android usa múltiplas interfaces com uma única interface HAL para um grupo de itens de configuração relacionados. Por exemplo, ISurfaceflingerConfigs
para itens de configuração relacionados surfaceflinger
e IBluetoothConfigs
para itens de configuração relacionados ao Bluetooth.