Aplicando interfaces de partição do produto

O Android 11 desmembra a partição product , tornando-a independente das partições do system e vendor . Como parte dessas mudanças, agora é possível controlar o acesso da partição product às interfaces nativas e Java (que é semelhante ao modo como a imposição de interface funciona para partições vendor ).

Aplicando interfaces nativas

Para ativar a aplicação da interface nativa, defina PRODUCT_PRODUCT_VNDK_VERSION como current . (A versão é automaticamente definida como current quando o nível da API de envio para o destino é superior a 29.) A aplicação permite:

  • Módulos nativos na partição product para vincular:
    • Estática ou dinamicamente para outros módulos na partição product que incluem bibliotecas estáticas, compartilhadas ou de cabeçalho.
    • Dinamicamente para bibliotecas VNDK na partição system .
  • Bibliotecas JNI em APKs desagregados na partição product para vincular a bibliotecas em /product/lib ou /product/lib64 (isso é um acréscimo às bibliotecas NDK).

A aplicação não permite outros links para partições diferentes da partição product .

Aplicação do tempo de compilação (Android.bp)

No Android 11, os módulos do sistema podem criar uma variante de imagem do produto, além das variantes de imagem principal e do fornecedor. Quando a aplicação da interface nativa está habilitada ( PRODUCT_PRODUCT_VNDK_VERSION está definido como current ):

  • Os módulos nativos na partição product estão na variante do produto, e não na variante principal.

  • Módulos com product_available: true em seus arquivos Android.bp estão disponíveis para a variante do produto.

  • Bibliotecas ou binários que especificam product_specific: true podem ser vinculados a outras bibliotecas que especificam product_specific: true ou product_available: true em seus arquivos Android.bp .

  • As bibliotecas VNDK devem ter product_available: true em seus arquivos Android.bp para que os binários product possam ser vinculados às bibliotecas VNDK.

A tabela a seguir resume as propriedades Android.bp usadas para criar variantes de imagem.

Propriedades em Android.bp Variantes criadas
Antes da aplicação Após a aplicação
padrão (nenhum) essencial

(inclui /system , /system_ext e /product )

essencial

(inclui /system e /system_ext mas não /product )

system_ext_specific: true essencial essencial
product_specific: true essencial produtos
vendor: true fornecedor fornecedor
vendor_available: true núcleo, fornecedor núcleo, fornecedor
product_available: true N / D produto principal
vendor_available: true E product_available: true N / D núcleo, produto, fornecedor
system_ext_specific: true E vendor_available: true núcleo, fornecedor núcleo, fornecedor
product_specific: true E vendor_available: true núcleo, fornecedor produto, fornecedor

Aplicação do tempo de compilação (Android.mk)

Quando a aplicação da interface nativa está ativada, os módulos nativos instalados na partição product têm um tipo de link native:product que pode ser vinculado apenas a outros módulos native:product ou native:vndk . A tentativa de vincular a quaisquer módulos diferentes desses faz com que o sistema de compilação gere um erro de verificação de tipo de link.

Aplicação de tempo de execução

Quando a aplicação da interface nativa está habilitada, a configuração do vinculador para o vinculador biônico não permite que os processos do sistema usem bibliotecas product , criando uma seção product para os processos product que não podem se vincular a bibliotecas fora da partição product (no entanto, tais processos podem link para bibliotecas VNDK). As tentativas de violar a configuração do link de tempo de execução fazem com que o processo falhe e gere uma mensagem de erro CANNOT LINK EXECUTABLE .

Aplicando interfaces Java

Para ativar a aplicação da interface Java, configure PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE como true . (O valor é automaticamente definido como true quando o nível da API de envio para o destino é maior que 29.) Quando ativada, a imposição permite/desautoriza o seguinte acesso.

API /sistema /sistema_ext /produtos /fornecedor /dados
API pública
@SystemApi
@ocultar API

Assim como na partição vendor , um aplicativo ou biblioteca Java na partição product pode usar apenas APIs públicas e de sistema; não é permitido vincular a uma biblioteca que usa APIs ocultas. Essa restrição inclui vinculação em tempo de construção e reflexão em tempo de execução.

Aplicação do tempo de construção

No momento da construção, Make e Soong verificam se os módulos Java na partição product não usam APIs ocultas, verificando os campos platform_apis e sdk_version . O sdk_version dos aplicativos na partição product deve ser preenchido com a versão current , system_current ou numérica da API, e o campo platform_apis deve estar vazio.

Aplicação de tempo de execução

O ambiente de execução do Android verifica se os aplicativos na partição product não usam APIs ocultas, incluindo reflexão. Para obter detalhes, consulte Restrições em interfaces não SDK .

Habilitando a aplicação da interface do produto

Use as etapas nesta seção para ativar a aplicação da interface do produto.

Etapa Tarefa Obrigatório
1 Defina seu próprio makefile do sistema que especifica os pacotes para a partição system e, em seguida, defina a verificação de requisitos do caminho dos artefatos no device.mk (para evitar que módulos que não sejam do sistema sejam instalados na partição system ). N
2 Limpe a lista permitida. N
3 Aplique interfaces nativas e identifique falhas de link de tempo de execução (pode ser executado em paralelo com a aplicação de Java). S
4 Aplique interfaces Java e verifique o comportamento do tempo de execução (pode ser executado em paralelo com a aplicação nativa). S
5 Verifique os comportamentos de tempo de execução. S
6 Atualize device.mk com aplicação da interface do produto. S

Etapa 1: criar makefile e ativar a verificação do caminho do artefato

Nesta etapa, você define o makefile system .

  1. Crie um makefile que defina os pacotes para a partição system . Por exemplo, crie um arquivo oem_system.mk com o seguinte:

    $(call inherit-product, $(SRC_TARGET_DIR)/product/handheld_system.mk)
    $(call inherit-product, $(SRC_TARGET_DIR)/product/telephony_system.mk)
    
    # Applications
    PRODUCT_PACKAGES += \
        CommonSystemApp1 \
        CommonSystemApp2 \
        CommonSystemApp3 \
    
    # Binaries
    PRODUCT_PACKAGES += \
        CommonSystemBin1 \
        CommonSystemBin2 \
        CommonSystemBin3 \
    
    # Libraries
    PRODUCT_PACKAGES += \
        CommonSystemLib1 \
        CommonSystemLib2 \
        CommonSystemLib3 \
    
    PRODUCT_SYSTEM_NAME := oem_system
    PRODUCT_SYSTEM_BRAND := Android
    PRODUCT_SYSTEM_MANUFACTURER := Android
    PRODUCT_SYSTEM_MODEL := oem_system
    PRODUCT_SYSTEM_DEVICE := generic
    
    # For system-as-root devices, system.img should be mounted at /, so we
    # include ROOT here.
    _my_paths := \
     $(TARGET_COPY_OUT_ROOT)/ \
     $(TARGET_COPY_OUT_SYSTEM)/ \
    
    $(call require-artifacts-in-path, $(_my_paths),)
    
  2. No arquivo device.mk , herde o makefile comum para a partição system e ative a verificação de requisitos do caminho do artefato. Por exemplo:

    $(call inherit-product, $(SRC_TARGET_DIR)/product/oem_system.mk)
    
    # Enable artifact path requirements checking
    PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := strict
    

Sobre os requisitos do caminho do artefato

Quando PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS é definido como true ou strict , o sistema de compilação evita que pacotes definidos em outros makefiles sejam instalados nos caminhos definidos em require-artifacts-in-path e evita que pacotes definidos no makefile atual instalem artefatos fora dos caminhos definidos em require-artifacts-in-path .

No exemplo acima, com PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS definido como strict , makefiles fora de oem_system.mk não podem incluir módulos instalados na root ou na partição system . Para incluir esses módulos, você deve defini-los no próprio arquivo oem_system.mk ou em um makefile incluído. As tentativas de instalar módulos em caminhos não permitidos causam interrupções na compilação. Para corrigir quebras, siga um destes procedimentos:

  • Opção 1: Incluir o módulo do sistema nos makefiles incluídos em oem_system.mk . Isso faz com que o requisito do caminho do artefato seja atendido (já que os módulos agora existem em um makefile incluído) e, portanto, permite a instalação no conjunto de caminhos em `require-artifacts-in-path.

  • Opção 2: Instale módulos na partição system_ext ou product (e não instale módulos na partição system ).

  • Opção 3: adicione módulos ao PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST . Esta lista os módulos permitidos para serem instalados.

Passo 2: Esvazie a lista permitida

Nesta etapa, você deixa PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST vazio para que todos os dispositivos que compartilham oem_system.mk também possam compartilhar uma única imagem system . Para esvaziar a lista permitida, mova quaisquer módulos da lista para system_ext ou partição product ou adicione-os aos arquivos make system . Esta etapa é opcional porque a definição de uma imagem system comum não é necessária para permitir a aplicação da interface do produto. No entanto, esvaziar a lista permitida é útil para definir o limite system com system_ext .

Etapa 3: aplicar interfaces nativas

Nesta etapa, você define PRODUCT_PRODUCT_VNDK_VERSION := current e, em seguida, procura erros de compilação e de tempo de execução e os resolve. Para verificar a inicialização e os registros do dispositivo e localizar e corrigir falhas de link de tempo de execução:

  1. Definir PRODUCT_PRODUCT_VNDK_VERSION := current .

  2. Construa o dispositivo e procure erros de construção. É provável que você veja algumas quebras de compilação devido a variantes de produto ou variantes principais ausentes. As pausas comuns incluem:

    • Qualquer módulo hidl_interface que tenha product_specific: true não estará disponível para módulos do sistema. Para corrigir, substitua product_specific: true por system_ext_specfic: true .
    • Os módulos podem não ter a variante de produto necessária para módulos de produto. Para corrigir, disponibilize esse módulo para a partição product definindo product_available: true ou mova o módulo para a partição do product definindo product_specific: true .
  3. Resolva erros de compilação e garanta que o dispositivo seja compilado com sucesso.

  4. Atualize a imagem e procure erros de tempo de execução na inicialização e nos registros do dispositivo.

    • Se a tag do linker de um log de caso de teste mostrar uma mensagem CANNOT LINK EXECUTABLE , falta uma dependência no arquivo make (e não foi capturado no momento da construção).
    • Para verificá-lo no sistema de compilação, adicione a biblioteca necessária ao campo shared_libs: ou required:
  5. Resolva as dependências ausentes usando as orientações fornecidas acima.

Etapa 4: aplicar interfaces Java

Nesta etapa, você define PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true , em seguida, localiza e corrige os erros de compilação resultantes. Procure dois tipos específicos de erros:

  • Erros de tipo de link. Este erro indica que um aplicativo está vinculado a módulos Java que possuem um sdk_version mais amplo. Para corrigir, você pode ampliar o sdk_version do aplicativo ou restringir o sdk_version da biblioteca. Erro de exemplo:

    error: frameworks/base/packages/SystemUI/Android.bp:138:1: module "SystemUI" variant "android_common": compiles against system API, but dependency "telephony-common" is compiling against private API.Adjust sdk_version: property of the source or target module so that target module is built with the same or smaller API set than the source.
    
  • Erros de símbolos. Este erro indica que um símbolo não pode ser encontrado porque está em uma API oculta. Para corrigir, use uma API visível (não oculta) ou encontre uma alternativa. Erro de exemplo:

    frameworks/opt/net/voip/src/java/com/android/server/sip/SipSessionGroup.java:1051: error: cannot find symbol
                ProxyAuthenticate proxyAuth = (ProxyAuthenticate)response.getHeader(
                                               ^
      symbol:   class ProxyAuthenticate
      location: class SipSessionGroup.SipSessionImpl
    

Etapa 5: verifique os comportamentos de tempo de execução

Nesta etapa, você verifica se os comportamentos de tempo de execução estão conforme o esperado. Para aplicativos depuráveis, você pode monitorar o uso de API oculta por log usando StrictMode.detectNonSdkApiUsage (que gera um log quando o aplicativo usa uma API oculta). Alternativamente, você pode usar a ferramenta de análise estática veridex para obter o tipo de uso (vinculação ou reflexão), nível de restrição e pilha de chamadas.

  • Sintaxe Veridex:

    ./art/tools/veridex/appcompat.sh --dex-file={apk file}
    
  • Exemplo de resultado veridex:

    #1: Linking greylist-max-o Landroid/animation/AnimationHandler;-><init>()V use(s):
           Lcom/android/systemui/pip/phone/PipMotionHelper;-><init>(Landroid/content/Context;Landroid/app/IActivityManager;Landroid/app/IActivityTaskManager;Lcom/android/systemui/pip/phone/PipMenuActivityController;Lcom/android/internal/policy/PipSnapAlgorithm;Lcom/android/systemui/statusbar/FlingAnimationUtils;)V
    
    #1332: Reflection greylist Landroid/app/Activity;->mMainThread use(s):
           Landroidx/core/app/ActivityRecreator;->getMainThreadField()Ljava/lang/reflect/Field;
    

Para obter detalhes sobre o uso do veridex, consulte Testar usando a ferramenta veridex .

Etapa 6: atualizar device.mk

Depois de corrigir todas as falhas de compilação e de tempo de execução e verificar se os comportamentos de tempo de execução são os esperados, defina o seguinte em device.mk :

  • PRODUCT_PRODUCT_VNDK_VERSION := current
  • PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true