É necessário usar o HIDL para descrever todos os flags de build usados para compilar
o framework condicionalmente. As sinalizações de criação relevantes precisam ser agrupadas e incluídas em um
único arquivo .hal
. O uso do HIDL para especificar itens de configuração
inclui os seguintes benefícios:
- Versão (para adicionar novos itens de configuração, os fornecedores/OEMs precisam estender explicitamente o HAL)
- Bem documentado
- Controle de acesso com o SELinux
- Verificação de integridade para itens de configuração por meio do Pacote de testes de fornecedor (verificação de intervalo, verificação de interdependência entre itens etc.)
- APIs geradas automaticamente em C++ e Java
Identificar as flags de build usadas pelo framework
Comece identificando as configurações de build usadas para compilar condicionalmente o
framework e, em seguida, abandone as configurações obsoletas para reduzir o conjunto. Por exemplo,
o seguinte conjunto de flags de build é 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
Criar uma interface HAL
As configurações da versão para um subsistema são acessadas por 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
.
Adicionar funções para flags de build
Para cada flag de build, 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:
- Use os nomes concisos. Evite converter nomes de variáveis
do makefile em nomes de função e tenha em mente que os prefixos
TARGET_
eBOARD_
não são mais necessários. - Adicionar comentários. Ajude os desenvolvedores a entender o propósito do item de configuração, como ele muda o comportamento do framework, valores válidos e outras informações relevantes.
Os tipos de retorno da 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 valores primitivos com um
campo que indica se o valor é especificado pelo HAL. Caso contrário, o valor
padrão é usado.
struct OptionalString { bool specified; string value; };
Quando apropriado, defina o tipo enumerado que melhor representa o tipo do
item de configuração e use-o como o tipo de retorno. No exemplo acima,
o tipo enumerado NumBuffers
é definido para limitar o número de valores
válidos. Ao definir esses tipos de dados personalizados, adicione um campo ou um valor de enumeração (por
exemplo, USE_DEFAULT
) para indicar se o valor é ou não especificado
pela HAL.
Não é obrigatório que uma única flag de build se torne uma única função no HIDL. Os proprietários de módulos podem agregar flags de build relacionadas em uma struct e ter uma função que retorna essa struct. Isso pode reduzir o número de chamadas de função.
Por exemplo, uma opção para agregar duas sinalizações de criaçã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 flags de build, a interface
HAL também oferece 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 da HAL
fornece valores lendo/analisando esses arquivos.
Embora essa abordagem seja fácil de definir, ela não inclui os benefícios fornecidos pelo HIDL (versionamento forçado, 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 abrange todos os itens de configuração
- Várias interfaces, cada uma cobrindo um conjunto de itens de configuração relacionados
Usar uma única interface é mais fácil, mas o uso de uma única interface pode se tornar ineficaz quando mais itens de configuração são adicionados a um único arquivo. Além disso, o controle de acesso não é granular, portanto, um processo que recebe 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. Se o acesso não for concedido, os itens de configuração não poderão ser lidos.
Por causa desses problemas, o Android usa várias interfaces com uma única interface
HAL para um grupo de itens de configuração relacionados. Por exemplo,
ISurfaceflingerConfigs
para itens de configuração
relacionados a surfaceflinger
e IBluetoothConfigs
para itens de configuração
relacionados a Bluetooth.