Aplicando interfaces de partição do produto

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

Como aplicar interfaces nativas

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

  • Módulos nativos na partição do product para vincular:
    • Estaticamente ou dinamicamente para outros módulos na partição do product que incluem bibliotecas estáticas, compartilhadas ou de cabeçalho.
    • Dinamicamente para bibliotecas VNDK na partição do system .
  • Bibliotecas JNI em APKs desagregados na partição do product para vincular a bibliotecas em /product/lib ou /product/lib64 (além das bibliotecas do NDK).

A imposição não permite outros links para partições além da partição do product .

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

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

  • Os módulos nativos na partição do product estão na variante do produto em vez da variante principal.

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

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

  • As bibliotecas do VNDK devem ter vendor_available: true em seus arquivos Android.bp para que os binários do product possam ser vinculados às bibliotecas do 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) testemunho

(inclui /system , /system_ext e /product )

testemunho

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

system_ext_specific: true testemunho testemunho
product_specific: true testemunho produtos
vendor: true fornecedor fornecedor
vendor_available: true núcleo, fornecedor núcleo, produto, fornecedor
system_ext_specific: true AND vendor_available: true núcleo, fornecedor núcleo, produto, fornecedor
product_specific: true AND vendor_available: true núcleo, fornecedor produto, vendedor

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

Quando a imposição de interface nativa está ativada, os módulos nativos instalados na partição do product possuem 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 qualquer módulo diferente 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 imposição de interface nativa está habilitada, a configuração do vinculador para o vinculador biônico não permite que os processos do sistema usem bibliotecas de product , criando uma seção de product para os processos de product que não podem vincular a bibliotecas fora da partição do product (no entanto, esses 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 .

Como aplicar interfaces Java

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

API /sistema /system_ext /produtos /fornecedor /dados
API pública
@SystemApi
@hide API

Assim como na partição do vendor , um aplicativo ou uma biblioteca Java na partição do 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 compilação e reflexão em tempo de execução.

Execução do tempo de construção

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

Aplicação de tempo de execução

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

Como ativar a aplicação da interface do produto

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

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

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

Nesta etapa, você define o makefile do system .

  1. Crie um makefile que defina os pacotes para a partição do 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 do system e ative a verificação de requisitos de caminho de 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 impede que pacotes definidos em outros makefiles sejam instalados nos caminhos definidos em require-artifacts-in-path e impede 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 oem_system.mk não podem incluir módulos instalados na partição root ou do 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 quebras de compilação. Para corrigir quebras, siga um destes procedimentos:

  • Opção 1: inclua 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 do conjunto de caminhos em `require-artifacts-in-path.

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

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

Etapa 2: esvazie a lista de permitidos

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

Etapa 3: aplicar interfaces nativas

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

  1. Defina PRODUCT_PRODUCT_VNDK_VERSION := current .

  2. Compile o dispositivo e procure por erros de compilação. É provável que você veja algumas quebras de compilação para variantes de produtos ausentes ou variantes principais. 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 os módulos de produto. Para corrigir, disponibilize esse módulo para a partição do product configurando vendor_available: true ou mova o módulo para a partição do product configurando product_specific: true .
  3. Resolva os erros de compilação e assegure-se de que o dispositivo seja compilado com êxito.

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

    • Se a tag do linker de um log de caso de teste mostrar uma mensagem CANNOT LINK EXECUTABLE , o arquivo make não possui uma dependência (e não foi capturado no momento da compilação).
    • Para verificá-lo no sistema de compilação, inclua a biblioteca necessária no 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 e, 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. Exemplo de erro:

    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ímbolo. 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. Exemplo de erro:

    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: verificar 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 que são depuráveis, você pode monitorar o uso de API oculta registrando usando StrictMode.detectNonSdkApiUsage (que gera um log quando o aplicativo usa uma API oculta). Como alternativa, 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 do Veridex:

    ./art/tools/veridex/appcompat.sh --dex-file={apk file}
    
  • Exemplo de resultado do 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 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