Verificação de compatibilidade com versões anteriores da estrutura HIDL

Os HIDL HALs garantem que o sistema central do Android (também conhecido como system.img ou o framework) seja compatível com versões anteriores. Embora os testes do Vendor Test Suite (VTS) garantam que os HALs funcionem conforme o esperado (por exemplo, os testes de HAL 1.1 são executados em todas as implementações 1.2), o teste de estrutura é necessário para garantir que, quando um HAL compatível (1.0, 1.1 ou 1.2) for fornecido, o framework funciona corretamente com esse HAL.

Para obter detalhes sobre a linguagem de definição de interface HAL (HIDL), consulte HIDL , versionamento HIDL e HIDL HAL Deprecation .

Sobre atualizações HAL

Existem dois tipos de atualizações de HAL: principais e secundárias . A maioria dos sistemas inclui apenas uma implementação de HAL, mas várias implementações são suportadas. Por exemplo:

android.hardware.teleport@1.0 # initial interface
android.hardware.teleport@1.1 # minor version upgrade
android.hardware.teleport@1.2 # another minor version upgrade
...
android.hardware.teleport@2.0 # major version upgrade
...

A partição do sistema normalmente inclui um daemon de estrutura (como teleportd ) que gerencia a comunicação com um grupo específico de implementações de HAL. Alternativamente, os sistemas podem incluir uma biblioteca de sistema (como android.hardware.configstore-utils ) que implementa um comportamento de cliente conveniente. No exemplo acima, o teleportd deve funcionar independentemente da versão do HAL instalada no dispositivo.

Versões mantidas pelo Google

Se houver atualizações de versão principal (1.0, 2.0, 3.0 etc.), pelo menos um dispositivo mantido pelo Google deverá manter uma implementação de cada versão principal até que essa versão seja suspensa. Se nenhum dispositivo mantido pelo Google for fornecido com uma versão principal específica, o Google continuará a manter uma implementação antiga dessa versão principal.

Essa manutenção adiciona uma pequena sobrecarga adicional porque a implementação antiga (por exemplo, 1.2) pode ser mantida e não usada por padrão quando uma nova implementação (por exemplo, 2.0) é criada.

Testando atualizações de versões secundárias

Testar a compatibilidade com versões anteriores de versões secundárias na estrutura requer uma maneira de gerar automaticamente implementações de versões secundárias. Dadas as restrições em torno das versões mantidas pelo Google, hidl-gen só (e só pode) gerar adaptadores que aceitam uma implementação 1.(x+n) e fornecem uma implementação 1.x; ele não pode gerar uma implementação 1.0 de uma implementação 2.0 (por definição de uma versão principal).

Por exemplo, para executar testes 1.1 em uma implementação 1.2, você deve ser capaz de simular uma implementação 1.1. As interfaces 1.2 podem ser usadas automaticamente como implementação 1.1 com algumas pequenas diferenças de comportamento (como o framework verificando manualmente qual versão algo é ou chamando castFrom nele).

A ideia básica é esta:

  1. Instale uma interface x.(y+n) em um dispositivo móvel Android.
  2. Instale e ative um adaptador de destino xy.
  3. Teste o dispositivo para verificar se ele funciona conforme o esperado ao executar uma versão secundária mais antiga.

Esses adaptadores ocultam completamente o fato de que a implementação é realmente suportada por uma interface 1.2 e fornece apenas a interface 1.1 (o adaptador usa uma interface 1.2 e faz com que pareça uma interface 1.1).

Fluxo de trabalho de exemplo

Neste exemplo, o dispositivo Android executa android.hardware.foo@1.1::IFoo/default . Para garantir que um cliente funcione corretamente com android.hardware.foo@1.0::IFoo/default :

  1. Em um terminal, execute o seguinte:
    $ PACKAGE=android.hidl.allocator@1.0-adapter
    $ INTERFACE=IAllocator
    $ INSTANCE=ashmem
    $ THREAD_COUNT=1 # can see current thread use on `lshal -i -e`
    $ m -j $PACKAGE
    $ /data/nativetest64/$PACKAGE/$PACKAGE $INTERFACE $INSTANCE $THREAD_COUNT
    Trying to adapt down android.hidl.allocator@1.0-adapter/default
    Press any key to disassociate adapter.
  2. Reinicie o cliente usando adb shell stop (ou start ) ou simplesmente mate o processo.
  3. Após a conclusão do teste, desassocie o adaptador.
  4. Restaure o estado do sistema reiniciando o dispositivo OU reiniciando o cliente.

Destinos adicionais

hidl-gen adiciona automaticamente destinos de compilação adicionais para os adaptadores para cada interface especificada com hidl_interface no sistema de compilação. Para o pacote abc@xy , há um destino C++ adicional abc@xy-adapter .

Um adaptador para abc@xy recebe como entrada alguma implementação, abc@x.(y+n)::ISomething/instance-name , e deve registrar abc@xy::ISomething/instance-name que também deve cancelar o registro do y+n implementação.

Dada a seguinte interface de amostra:

// IFoo.hal
package a.b.c@1.0;
interface IFoo {
    doFoo(int32_t a) generates (int64_t b);
    doSubInterface() generates (IFoo a);
};

O código fornecido por abc@1.0-adapter é semelhante ao exemplo abaixo:

// autogenerated code
// in namespace a::b::c::V1_0::IFoo
struct MockFoo {
    // takes some subclass of V1_0. May be V1_1, V1_2, etc...
    MockFoo(V1_0::IFoo impl) mImpl(impl) {}

    Return<int64_t> doFoo(int32_t a) {
        return this->mImpl->doFoo(a);
    }

    Return<V1_0::ICallback> doSubInterface() {
        // getMockForBinder returns MockCallback instance
        // that corresponds to a particular binder object
        // It can't return a new object every time or
        // clients using interfacesSame will have
        // divergent behavior when using the mock.
        auto _hidl_out = this->mImpl->doSubInterface();
        return getMockForBinder(_hidl_out);
    }
};

Os valores de dados são encaminhados exatamente para dentro e para fora da classe simulada gerada automaticamente, exceto para subinterfaces, que são retornadas. Essas interfaces devem ser agrupadas no objeto de retorno de chamada mais recente correspondente.