Criando a interface HAL

Você deve usar HIDL para descrever todos os sinalizadores de compilação usados ​​para compilar condicionalmente a estrutura. Os sinalizadores de construção relevantes devem ser agrupados e incluídos em um único arquivo .hal . O uso de 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 para 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 compilação usados ​​pelo framework

Comece identificando as configurações de compilação usadas para compilar condicionalmente a estrutura e, em seguida, abandone as configurações obsoletas para tornar o conjunto menor. 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 compilaçã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
};

Após 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 compilaçã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_ e BOARD_ 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, 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; se não, o valor padrão é usado.

struct OptionalString {
    bool specified;
    string value;
};

Quando apropriado, defina a enumeração que melhor representa o tipo do item de configuração e use essa enumeração como o tipo de retorno. No exemplo acima, a enumeração NumBuffers é definida 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 é/não é especificado pelo HAL.

Não é obrigatório que um único sinalizador de compilação se torne uma única função em HIDL. Os proprietários do módulo podem, alternativamente, agregar sinalizadores de compilação intimamente relacionados em um struct e ter uma função que retorna esse struct (isso pode reduzir o número de chamadas de função).

Por exemplo, uma opção para agregar dois sinalizadores de compilaçã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 compilaçã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 essa abordagem seja fácil de definir, ela não inclui os benefícios fornecidos pelo HIDL (versão imposta, 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 das quais abrange um conjunto de itens de configuração relacionados

Uma única interface é mais fácil, mas pode se tornar insustentável à medida que mais itens de configuração são adicionados ao único arquivo. Além disso, o controle de acesso não é refinado, 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). Como alternativa, 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 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 ao surfaceflinger e IBluetoothConfigs para itens de configuração relacionados ao Bluetooth.