Formato de arquivo APEX

O formato de contêiner Android Pony EXpress (APEX) foi introduzido no Android 10 e é usada no fluxo de instalação para sistemas de nível inferior módulos. Esse formato facilita as atualizações de componentes do sistema que não se encaixam para o modelo de aplicativo Android padrão. Alguns exemplos de componentes são nativos serviços e bibliotecas, camadas de abstração de hardware (HALs), ambiente de execução (ART) e bibliotecas de classes.

O termo "APEX" também podem se referir a um arquivo APEX.

Contexto

Embora o Android ofereça suporte a atualizações de módulos que se encaixam no app padrão (por exemplo, serviços, atividades) por meio de aplicativos instaladores de pacote (como o app Google Play Store), usando um modelo semelhante para componentes de SO de nível inferior tem as seguintes desvantagens:

  • Módulos baseados em APK não podem ser usados no início da sequência de inicialização. O pacote é o repositório central de informações sobre aplicativos e só pode ser iniciado pelo gerenciador de atividades, que fica pronto em um estágio posterior do o procedimento de inicialização.
  • O formato APK (especialmente o manifesto) foi projetado para apps Android e os módulos do sistema nem sempre são adequados.

Design

Esta seção descreve o design de alto nível do formato de arquivo APEX e as Gerenciador APEX, que é um serviço que gerencia arquivos APEX.

Para mais informações sobre por que esse design para APEX foi selecionado, consulte Alternativas consideradas no desenvolvimento de APEX.

Formato APEX

Esse é o formato de um arquivo APEX.

Formato de arquivo APEX

Figura 1. Formato de arquivo APEX

No nível superior, um arquivo APEX é um arquivo zip no qual os arquivos são armazenados não compactado e localizado em limites de 4 KB.

Os quatro arquivos em um arquivo APEX são:

  • apex_manifest.json
  • AndroidManifest.xml
  • apex_payload.img
  • apex_pubkey

O arquivo apex_manifest.json contém o nome do pacote e a versão, que identificar um arquivo APEX. Esta é uma ApexManifest buffer de protocolo no formato JSON.

O arquivo AndroidManifest.xml permite que o arquivo APEX use ferramentas relacionadas ao APK e como ADB, PackageManager e aplicativos de instalação de pacotes (como Play Store). Por exemplo, o arquivo APEX pode usar uma ferramenta atual, como aapt para inspecionar metadados básicos do arquivo. O arquivo contém o nome do pacote e informações de versão. Essas informações geralmente também estão disponíveis em apex_manifest.json:

Recomendamos usar apex_manifest.json em vez de AndroidManifest.xml para novos códigos sistemas que usam APEX. AndroidManifest.xml pode conter informações adicionais informações de segmentação que podem ser usadas pelas ferramentas existentes de publicação de apps.

apex_payload.img é uma imagem do sistema de arquivos ext4 com suporte de dm-verity. A imagem é montado no ambiente de execução por um dispositivo de loopback. Especificamente, a árvore hash e bloco de metadados são criados usando a biblioteca libavb. O payload do sistema de arquivos não é analisado (porque a imagem deve ser montada no lugar). Arquivos regulares são incluído no arquivo apex_payload.img.

apex_pubkey é a chave pública usada para assinar a imagem do sistema de arquivos. No ambiente de execução, Essa chave garante que o APEX baixado seja assinado com a mesma entidade que assina o mesmo APEX nas partições integradas.

Diretrizes de nomenclatura APEX

Para ajudar a evitar conflitos de nomenclatura entre novos APEXs à medida que a plataforma avança, use as seguintes diretrizes de nomenclatura:

  • com.android.*
    • Reservado para APEXs do AOSP. Não é exclusivo de nenhuma empresa ou dispositivo.
  • com.<companyname>.*
    • Reservado para uma empresa. Potencialmente usado por vários dispositivos desse de uma empresa.
  • com.<companyname>.<devicename>.*
    • Reservado para APEXs exclusivos de um dispositivo específico (ou subconjunto de dispositivos).

Gerenciador APEX

O gerenciador APEX (ou apexd) é um processo nativo autônomo responsável por: verificar, instalar e desinstalar arquivos APEX. Esse processo é iniciado está pronta no início da sequência de inicialização. Os arquivos APEX normalmente são pré-instalados em o dispositivo em /system/apex. Por padrão, o gerenciador APEX usa essas pacotes se nenhuma atualização estiver disponível.

A sequência de atualização de um APEX usa o Classe PackageManager e é o seguinte.

  1. Um arquivo APEX é transferido por download por meio de um aplicativo instalador de pacote, ADB ou outro fonte.
  2. O gerenciador de pacotes inicia o procedimento de instalação. Ao reconhecer que o arquivo for um APEX, o gerenciador de pacotes transfere o controle para o APEX de projeto.
  3. O gerenciador APEX verifica o arquivo APEX.
  4. Se o arquivo APEX for verificado, o banco de dados interno do gerenciador APEX será atualizado para refletir que o arquivo APEX é ativado na próxima inicialização.
  5. O solicitante de instalação recebe uma transmissão após o pacote bem-sucedido verificação.
  6. Para continuar a instalação, reinicie o sistema.
  7. Na próxima inicialização, o gerenciador APEX inicia, lê o banco de dados interno e faz o seguinte para cada arquivo APEX listado:

    1. Verifica o arquivo APEX.
    2. Cria um dispositivo de loopback a partir do arquivo APEX.
    3. Cria um dispositivo de bloco mapeador de dispositivo sobre o dispositivo de loopback.
    4. Monta o dispositivo de bloco mapeador do dispositivo em um caminho exclusivo (por exemplo, /apex/name@ver).

Quando todos os arquivos APEX listados no banco de dados interno estiverem montados, o APEX O gerenciador oferece um serviço de vinculação para que outros componentes do sistema consultem informações sobre os arquivos APEX instalados. Por exemplo, o outro sistema podem consultar a lista de arquivos APEX instalados no dispositivo ou consultar caminho exato onde um APEX específico está montado, para que os arquivos possam ser acessados.

Arquivos APEX são arquivos APK

Os arquivos APEX são arquivos APK válidos porque são arquivos zip assinados (usando o esquema de assinatura de APK) contendo um arquivo AndroidManifest.xml. Isso permite que o APEX para usar a infraestrutura de arquivos APK, como um app instalador de pacote, o utilitário de assinatura e o gerenciador de pacotes.

O arquivo AndroidManifest.xml dentro de um arquivo APEX é mínimo, consistindo nos pacote name, versionCode e opcionais targetSdkVersion, minSdkVersion, e maxSdkVersion para uma segmentação refinada. Essas informações permitem que o APEX arquivos a serem enviados por canais existentes, como aplicativos de instalação de pacotes e ADB.

Tipos de arquivo compatíveis

O formato APEX oferece suporte aos seguintes tipos de arquivo:

  • Bibliotecas compartilhadas nativas
  • Executáveis nativos
  • Arquivos JAR
  • Arquivos de dados
  • Arquivos de configuração

Isso não significa que o APEX possa atualizar todos esses tipos de arquivo. Se um arquivo pode ser atualizado depende da plataforma e da estabilidade das definições quais são as interfaces para os tipos de arquivos.

Opções de assinatura

Os arquivos APEX são assinados de duas maneiras. Primeiro, o apex_payload.img (especificamente, (o descritor vbmeta anexado a apex_payload.img) é assinado com uma chave. Em seguida, todo o APEX é assinado usando o Esquema de assinatura de APK v3: Duas chaves diferentes são usadas nesse processo.

No lado do dispositivo, uma chave pública correspondente à chave privada usada para assinar o descritor vbmeta está instalado. O gerenciador APEX usa a chave pública para verificar os APEXs que precisam ser instalados. Cada APEX deve ser assinado com chaves diferentes e é aplicada tanto no build quanto no ambiente de execução.

APEX em partições integradas

Os arquivos APEX podem estar localizados em partições integradas, como /system. A já está acima de dm-verity, então os arquivos APEX são montados diretamente no dispositivo de loopback.

Se um APEX estiver presente em uma partição integrada, ele pode ser atualizado fornecendo um pacote APEX com o mesmo nome de pacote e um número maior ou igual ao código de versão. O novo APEX é armazenado em /data e, assim como os APKs, os a versão recém-instalada oculta a versão já presente no sistema partição. Mas, ao contrário dos APKs, a versão recém-instalada do APEX tem apenas ativado após a reinicialização.

Requisitos do kernel

Para oferecer suporte a módulos de linha principal APEX em um dispositivo Android, os recursos são necessários: o driver de loopback e o dm-verity. O retorno monta a imagem do sistema de arquivos em um módulo APEX e o dm-verity verifica módulo APEX.

O desempenho do driver de loopback e do dm-verity é importante para alcançar bom desempenho do sistema ao usar módulos APEX.

Versões compatíveis do kernel

Os módulos de linha principal APEX são compatíveis com dispositivos que usam as versões 4.4 ou 4.4 do kernel mais alto. Novos dispositivos lançados com o Android 10 ou mais recente precisa usar o kernel versão 4.9 ou superior para oferecer suporte a módulos APEX.

Patches de kernel necessários

Os patches de kernel necessários para oferecer suporte a módulos APEX estão incluídos no árvore comum do Android. Para que os patches sejam compatíveis com APEX, use a versão mais recente da árvore comum do Android.

Kernel versão 4.4

Esta versão só é compatível com dispositivos que fizeram upgrade do Android 9 para o Android 10 e querem oferecer suporte a módulos APEX. Para conseguir os patches necessários, uma mesclagem da ramificação android-4.4 é fortemente recomendado. Esta é uma lista dos patches individuais necessários para a versão 4.4 do kernel.

  • UPSTREAM: loop: adicione ioctl para alterar o tamanho lógico do bloco (4.4).
  • BACKPORT: bloco/loop: definir hw_sectors (4.4).
  • UPSTREAM: loop: adicione LOOP_SET_BLOCK_SIZE ao ioctl de compatibilidade (4.4).
  • ANDROID: mnt: corrigir next_descendent (4.4).
  • ANDROID: mnt: a remontagem deve ser propagada para escravos dos escravos (4.4).
  • ANDROID: mnt: propagar a remontagem corretamente (4.4).
  • Reverter "ANDROID: dm verity: adicionar tamanho mínimo de pré-busca" (4.4).
  • UPSTREAM: loop: descarta caches se offset ou block_size forem alterados (4.4).

Versões do kernel 4.9/4.14/4.19

Para conseguir os patches necessários para as versões 4.9/4.14/4.19 do kernel, faça a mesclagem da a ramificação android-common.

Opções de configuração do kernel necessárias

A lista a seguir mostra os requisitos de configuração básica para dar suporte Módulos APEX que foram introduzidos no Android 10. Os itens com um asterisco (*) são requisitos do Android 9 e versões anteriores.

(*) CONFIG_AIO=Y # AIO support (for direct I/O on loop devices)
CONFIG_BLK_DEV_LOOP=Y # for loop device support
CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 # pre-create 16 loop devices
(*) CONFIG_CRYPTO_SHA1=Y # SHA1 hash for DM-verity
(*) CONFIG_CRYPTO_SHA256=Y # SHA256 hash for DM-verity
CONFIG_DM_VERITY=Y # DM-verity support

Requisitos de parâmetro de linha de comando do kernel

Para oferecer suporte a APEX, garanta que os parâmetros de linha de comando do kernel atendam aos seguintes requisitos:

  • loop.max_loop NÃO pode ser definido
  • O valor de loop.max_part precisa ser menor ou igual a 8

Criar um APEX

Esta seção descreve como criar um APEX usando o sistema de build do Android. Veja a seguir um exemplo de Android.bp para um APEX chamado apex.test.

apex {
    name: "apex.test",
    manifest: "apex_manifest.json",
    file_contexts: "file_contexts",
    // libc.so and libcutils.so are included in the apex
    native_shared_libs: ["libc", "libcutils"],
    binaries: ["vold"],
    java_libs: ["core-all"],
    prebuilts: ["my_prebuilt"],
    compile_multilib: "both",
    key: "apex.test.key",
    certificate: "platform",
}

Exemplo de apex_manifest.json:

{
  "name": "com.android.example.apex",
  "version": 1
}

Exemplo de file_contexts:

(/.*)?           u:object_r:system_file:s0
/sub(/.*)?       u:object_r:sub_file:s0
/sub/file3       u:object_r:file3_file:s0

Tipos de arquivo e locais no APEX

Tipo de arquivo Local no APEX
Bibliotecas compartilhadas /lib e /lib64 (/lib/arm de grupo traduzido em x86)
Executáveis /bin
Bibliotecas Java /javalib
Pré-versões /etc

Dependências transitivas

Os arquivos APEX incluem automaticamente dependências transitivas de bibliotecas compartilhadas nativas ou executáveis. Por exemplo, se libFoo depender de libBar, as duas bibliotecas serão incluído quando apenas libFoo está listado na propriedade native_shared_libs.

Lidar com várias ABIs

Instalar a propriedade native_shared_libs para as contas primária e secundária Interfaces binárias de aplicativo (ABIs, na sigla em inglês) do dispositivo. Se um APEX segmentar dispositivos com uma única ABI (ou seja, somente 32 ou 64 bits), somente bibliotecas com a ABI correspondente estejam instaladas.

Instale a propriedade binaries apenas para a ABI principal do dispositivo, como descritas abaixo:

  • Se o dispositivo tiver apenas 32 bits, somente a variante de 32 bits do binário será instalado.
  • Se o dispositivo tiver somente 64 bits, somente a variante de 64 bits do binário será instalado.

Para adicionar um controle refinado sobre as ABIs de binários e bibliotecas nativos, use o método multilib.[first|lib32|lib64|prefer32|both].[native_shared_libs|binaries] propriedades.

  • first: corresponde à ABI principal do dispositivo. Esse é o padrão para binários.
  • lib32: corresponde à ABI de 32 bits do dispositivo, se compatível.
  • lib64: corresponde à ABI de 64 bits do dispositivo, com suporte.
  • prefer32: corresponde à ABI de 32 bits do dispositivo, se compatível. Se o ABI de 32 bits não é compatível, corresponde à ABI de 64 bits.
  • both: corresponde às duas ABIs. Esse é o padrão para native_shared_libraries:

As propriedades java, libraries e prebuilts não dependem da ABI.

Este exemplo é para um dispositivo que oferece suporte a 32/64 e não prefere 32:

apex {
    // other properties are omitted
    native_shared_libs: ["libFoo"], // installed for 32 and 64
    binaries: ["exec1"], // installed for 64, but not for 32
    multilib: {
        first: {
            native_shared_libs: ["libBar"], // installed for 64, but not for 32
            binaries: ["exec2"], // same as binaries without multilib.first
        },
        both: {
            native_shared_libs: ["libBaz"], // same as native_shared_libs without multilib
            binaries: ["exec3"], // installed for 32 and 64
        },
        prefer32: {
            native_shared_libs: ["libX"], // installed for 32, but not for 64
        },
        lib64: {
            native_shared_libs: ["libY"], // installed for 64, but not for 32
        },
    },
}

assinatura vbmeta

Assine cada APEX com chaves diferentes. Quando uma nova chave for necessária, crie uma par de chaves públicas/privadas e criar um módulo apex_key. Use a propriedade key para assinar o APEX usando a chave. A chave pública é incluída automaticamente APEX com o nome avb_pubkey.

# create an rsa key pair
openssl genrsa -out foo.pem 4096

# extract the public key from the key pair
avbtool extract_public_key --key foo.pem --output foo.avbpubkey

# in Android.bp
apex_key {
    name: "apex.test.key",
    public_key: "foo.avbpubkey",
    private_key: "foo.pem",
}

No exemplo acima, o nome da chave pública (foo) torna-se o ID da de dados. O ID da chave usada para assinar um APEX está escrito no APEX. No ambiente de execução, O apexd verifica o APEX usando uma chave pública com o mesmo ID no dispositivo.

Assinatura APEX

Assine APEXs da mesma forma que você assina APKs. assinar APEXs duas vezes; uma vez para minisistema de arquivos (arquivo apex_payload.img) e uma vez para o arquivo inteiro.

Para assinar um APEX no nível do arquivo, defina a propriedade certificate em um dos de três maneiras:

  • Não definido: se nenhum valor for definido, o APEX será assinado com o certificado localizado às PRODUCT_DEFAULT_DEV_CERTIFICATE. Se nenhuma flag for definida, o caminho padrão para build/target/product/security/testkey.
  • <name>: o APEX é assinado com o certificado <name> no mesmo como PRODUCT_DEFAULT_DEV_CERTIFICATE.
  • :<name>: o APEX é assinado com o certificado definido pelo Módulo Soong chamado <name>. O módulo de certificado pode ser definido como segue.
.
android_app_certificate {
    name: "my_key_name",
    certificate: "dir/cert",
    // this will use dir/cert.x509.pem (the cert) and dir/cert.pk8 (the private key)
}

Instalar um APEX

Para instalar um APEX, use o ADB.

adb install apex_file_name
adb reboot

Se supportsRebootlessUpdate estiver definido como true no apex_manifest.json e o o APEX instalado não é usado (por exemplo, os serviços for interrompido), um novo APEX poderá ser instalado sem precisar ser reiniciado com o --force-non-staged.

adb install --force-non-staged apex_file_name

Usar um APEX

Após a reinicialização, o APEX é montado no /apex/<apex_name>@<version> diretório. Várias versões do mesmo APEX podem ser montadas ao mesmo tempo. Entre os caminhos de montagem, aquele que corresponde à versão mais recente é montado na vinculação em /apex/<apex_name>.

Os clientes podem usar o caminho ativado de vinculação para ler ou executar arquivos do APEX.

Os APEXs normalmente são usados da seguinte forma:

  1. Um OEM ou ODM pré-carrega um APEX em /system/apex quando o dispositivo é enviados.
  2. Os arquivos no APEX são acessados pelo caminho /apex/<apex_name>/.
  3. Quando uma versão atualizada do APEX é instalada em /data/apex, o caminho aponta para o novo APEX após a reinicialização.

Atualizar um serviço com um APEX

Para atualizar um serviço usando um APEX:

  1. Marque o serviço na partição do sistema como atualizável. Adicionar a opção updatable à definição do serviço.

    /system/etc/init/myservice.rc:
    
    service myservice /system/bin/myservice
        class core
        user system
        ...
        updatable
    
  2. Crie um novo arquivo .rc para o serviço atualizado. Usar a opção override redefinir o serviço atual.

    /apex/my.apex/etc/init.rc:
    
    service myservice /apex/my.apex/bin/myservice
        class core
        user system
        ...
        override
    

As definições de serviço só podem ser definidas no arquivo .rc de um APEX. Ação não são suportados em APEXs.

Se um serviço marcado como atualizável começar antes da ativação dos APEXs, o é adiado até que a ativação dos APEXs seja concluída.

Configurar o sistema para oferecer suporte a atualizações APEX

Defina a propriedade do sistema a seguir como true para oferecer suporte a atualizações de arquivos APEX.

<device.mk>:

PRODUCT_PROPERTY_OVERRIDES += ro.apex.updatable=true

BoardConfig.mk:
TARGET_FLATTEN_APEX := false

ou apenas

<device.mk>:

$(call inherit-product, $(SRC_TARGET_DIR)/product/updatable_apex.mk)

APEX nivelado

Em dispositivos legados, às vezes é impossível ou inviável atualizar para dar suporte total ao APEX. Por exemplo, o kernel pode ter sido criado sem CONFIG_BLK_DEV_LOOP=Y, que é crucial para montar o sistema de arquivos imagem em um APEX.

APEX nivelado é um APEX especialmente criado que pode ser ativado em dispositivos com um kernel legado. Arquivos em um APEX nivelado são instalados diretamente em um diretório na partição integrada. Por exemplo, lib/libFoo.so em um APEX nivelado O app my.apex está instalado no /system/apex/my.apex/lib/libFoo.so.

A ativação de um APEX nivelado não envolve o dispositivo de loop. Toda a o diretório /system/apex/my.apex está diretamente vinculado a /apex/name@ver.

Não é possível atualizar APEXs nivelados com o download de versões atualizadas dos APEXs da rede porque os APEXs baixados não podem ser simplificados. APEXs nivelados só podem ser atualizados por um OTA normal.

O APEX nivelado é a configuração padrão. Isso significa que todos Por padrão, os APEXs são nivelados, a menos que você configure explicitamente seu dispositivo para construir APEXs não nivelados para suportar atualizações de APEX (como explicado acima).

Misturar APEXs achatados e não nivelados em um dispositivo NÃO é suporte. Os APEXs em um dispositivo precisam ser todos não nivelados ou todos nivelados. Isso é especialmente importante ao enviar modelos APEX pré-assinados para projetos como o Mainline. APEXs que não são pré-assinados (ou seja, criados a partir de a origem) também não devem ser nivelados e assinados com as chaves adequadas. A dispositivo deve herdar de updatable_apex.mk, conforme explicado em Como atualizar um serviço com um APEX

APEXs compactados

O Android 12 e versões mais recentes têm compactação APEX para reduzindo o impacto no armazenamento de pacotes APEX atualizáveis. Após a atualização O APEX está instalado, embora sua versão pré-instalada não seja mais usada, ele ainda ocupa a mesma quantidade de espaço. O espaço ocupado permanece indisponível.

A compactação APEX minimiza o impacto no armazenamento usando um conjunto altamente compactado dos arquivos APEX em partições somente leitura (como a partição /system). Android 12 e posteriores usam um algoritmo de compactação de zip DEFLATE.

A compactação não otimiza o seguinte:

  • Inicializar APEXs que precisam ser montados bem no início da inicialização sequência.

  • APEXs não atualizáveis. A compactação só é útil se uma versão atualizada de um APEX estiver instalada na partição /data. Uma lista completa de APEXs atualizáveis está disponível na Componentes modulares do sistema página.

  • APEXs de bibliotecas compartilhadas dinâmicas. Como o apexd sempre ativa as duas versões do esses APEXs (pré-instalados e atualizados), a compactação deles não agrega valor.

Formato de arquivo APEX compactado

Esse é o formato de um arquivo APEX compactado.

O diagrama mostra o formato de um arquivo APEX compactado

Figura 2. Formato de arquivo APEX compactado

No nível superior, um arquivo APEX compactado é um arquivo zip que contém o arquivo arquivo apex em forma desinfetada com um nível de compactação de 9, e com outros arquivos armazenados sem compactação.

Quatro arquivos compreendem um arquivo APEX:

  • original_apex: esvaziado com o nível de compactação de 9 Esse é o arquivo APEX original e descompactado.
  • apex_manifest.pb: somente armazenados
  • AndroidManifest.xml: somente armazenados
  • apex_pubkey: somente armazenados

Os arquivos apex_manifest.pb, AndroidManifest.xml e apex_pubkey são cópias dos arquivos correspondentes em original_apex.

Compilar APEX compactado

Um APEX compactado pode ser criado usando a ferramenta apex_compression_tool.py localizada em system/apex/tools.

Vários parâmetros relacionados à compactação APEX estão disponíveis no sistema de build.

No Android.bp, se um arquivo APEX é compactável ou não é controlado pelo Propriedade compressible:

apex {
    name: "apex.test",
    manifest: "apex_manifest.json",
    file_contexts: "file_contexts",
    compressible: true,
}

Uma flag de produto PRODUCT_COMPRESSED_APEX controla se uma imagem do sistema é criada da fonte deve conter arquivos APEX compactados.

Para experimentação local, você pode forçar um build a compactar APEXs configurando OVERRIDE_PRODUCT_COMPRESSED_APEX= para true.

Os arquivos APEX compactados gerados pelo sistema de build têm a extensão .capex. A extensão facilita a distinção entre compactado e descompactado de um arquivo APEX.

Algoritmos de compactação compatíveis

O Android 12 só oferece suporte à compactação deflate-zip.

Ativar um arquivo APEX compactado durante a inicialização

Antes que um APEX compactado possa ser ativado, o arquivo original_apex dentro dele descompactado no diretório /data/apex/decompressed. O resultado O arquivo APEX descompactado tem um link físico com o diretório /data/apex/active.

Considere o exemplo a seguir como uma ilustração do processo descrito acima.

Considere /system/apex/com.android.foo.capex como um APEX compactado ativado, com o versionCode 37.

  1. O arquivo original_apex dentro de /system/apex/com.android.foo.capex é descompactado em /data/apex/decompressed/com.android.foo@37.apex.
  2. restorecon /data/apex/decompressed/com.android.foo@37.apex é realizado para e verificar se ele tem um rótulo SELinux correto.
  3. As verificações são realizadas /data/apex/decompressed/com.android.foo@37.apex para garantir a validade: apexd verifica a chave pública agrupada /data/apex/decompressed/com.android.foo@37.apex para verificar se é igual ao empacotado em /system/apex/com.android.foo.capex.
  4. O arquivo /data/apex/decompressed/com.android.foo@37.apex tem um link físico para diretório /data/apex/active/com.android.foo@37.apex.
  5. A lógica de ativação normal para arquivos APEX descompactados é executada /data/apex/active/com.android.foo@37.apex:

Interação com OTA

Arquivos APEX compactados têm implicações na entrega e no aplicativo por OTA. Como uma atualização OTA pode conter um arquivo APEX compactado com um nível de versão superior do que o que está ativo em um dispositivo, uma certa quantidade de espaço livre deve ser reservada antes de reiniciar o dispositivo para aplicar uma atualização OTA.

Para oferecer suporte ao sistema OTA, o apexd expõe estas duas APIs de vinculação:

  • calculateSizeForCompressedApex: calcula o tamanho necessário para descompactar Arquivos APEX em um pacote OTA. Isso pode ser usado para verificar se um dispositivo espaço suficiente antes que um OTA seja baixado.
  • reserveSpaceForCompressedApex: reserva espaço no disco para uso futuro por apexd para descompactar arquivos APEX compactados dentro do pacote OTA.

No caso de uma atualização OTA A/B, o apexd tenta descompactar na em segundo plano como parte da rotina OTA pós-instalação. Se a descompactação falhar, O apexd executa a descompactação durante a inicialização que aplica a OTA atualizar.

Alternativas consideradas no desenvolvimento de APEX

Aqui estão algumas opções que o AOSP considerou ao projetar o arquivo APEX formato e por que eles foram incluídos ou excluídos.

Sistemas regulares de gerenciamento de pacotes

As distribuições do Linux têm sistemas de gerenciamento de pacotes, como dpkg e rpm, que são poderosas, maduras e robustas. No entanto, elas não estavam adotadas para APEX porque não podem proteger os pacotes após e instalação. A verificação é executada somente quando os pacotes estão sendo instalados. Os invasores podem violar a integridade dos pacotes instalados sem serem notados. Isso é uma regressão para Android em que todos os componentes do sistema foram armazenados em modo sistemas de arquivos cuja integridade é protegida por dm-verity para cada E/S. Qualquer um adulteração de componentes do sistema deve ser proibida ou ser detectável que a inicialização do dispositivo pode ser recusada se ele for comprometido.

dm-crypt para integridade

Os arquivos em um contêiner APEX são de partições incorporadas (por exemplo, a /system) que são protegidas por dm-verity, em que qualquer modificação os arquivos serão proibidos mesmo depois que as partições forem montadas. Para fornecer mesmo nível de segurança para os arquivos, todos os arquivos em um APEX são armazenados em um imagem do sistema pareada com uma árvore de hash e um descritor vbmeta. Sem dm-verity, um APEX na partição /data está vulnerável a ataques não intencionais modificações feitas depois que ele é verificado e instalado.

Na verdade, a partição /data também é protegida por camadas de criptografia, como: dm-crypt. Embora isso forneça certo nível de proteção contra adulterações, sua O objetivo principal é a privacidade, e não a integridade. Quando um invasor tem acesso /data, não pode haver mais proteções, e isso novamente é uma de regressão em comparação com todos os componentes do sistema na partição /system. A árvore de hash dentro de um arquivo APEX, junto com dm-verity, fornece os mesmos nível de proteção de conteúdo.

Redirecionar caminhos de /system para /apex

Arquivos de componentes do sistema empacotados em um APEX são acessíveis por novos caminhos, como /apex/<name>/lib/libfoo.so: Quando os arquivos faziam parte de /system elas eram acessíveis por caminhos como /system/lib/libfoo.so. Um de um arquivo APEX (outros arquivos APEX ou a plataforma) deve usar a nova caminhos de rede. Talvez seja necessário atualizar o código existente como resultado da mudança do caminho.

Embora uma forma de evitar a alteração do caminho seja sobrepor o conteúdo do arquivo em uma APEX na partição /system, a equipe do Android decidiu não sobrepor arquivos na partição /system, pois isso pode afetar o desempenho da número de arquivos sendo sobrepostos (possivelmente até mesmo empilhados um após o outro) aumentou.

Outra opção era invadir funções de acesso a arquivos, como open, stat e readlink, para que os caminhos que começassem com /system fossem redirecionados ao caminhos correspondentes em /apex. A equipe do Android descartou essa opção porque é inviável alterar todas as funções que aceitam caminhos. Por exemplo, alguns apps vinculam estaticamente o Bionic, que implementa as funções. Nesses casos, esses apps não são redirecionados.