Cache de APK

Este documento descreve o design de uma solução de armazenamento em cache de APK para instalação rápida de aplicativos pré-carregados em um dispositivo compatível com partições A/B.

Os OEMs podem colocar pré-carregamentos e aplicativos populares no cache do APK armazenado na partição B praticamente vazia em novos dispositivos particionados A/B sem afetar qualquer espaço de dados voltado para o usuário. Ao ter um cache APK disponível no dispositivo, os dispositivos novos ou redefinidos de fábrica estão prontos para uso quase que imediatamente, sem a necessidade de baixar arquivos APK do Google Play.

Casos de uso

  • Armazene aplicativos pré-carregados na partição B para uma configuração mais rápida
  • Armazene aplicativos populares na partição B para uma restauração mais rápida

Pré-requisitos

Para usar esse recurso, o dispositivo precisa:

  • Versão do Android 8.1 (O MR1) instalada
  • Partição A/B implementada

O conteúdo pré-carregado pode ser copiado apenas durante a primeira inicialização. Isso ocorre porque em dispositivos que suportam atualizações do sistema A/B, a partição B não armazena arquivos de imagem do sistema, mas conteúdo pré-carregado como recursos de demonstração de varejo, arquivos OAT e o cache APK. Depois que os recursos forem copiados para a partição /data (isso acontece na primeira inicialização), a partição B será usada por atualizações OTA (over-the-air) para baixar versões atualizadas da imagem do sistema.

Portanto, o cache do APK não pode ser atualizado por meio de OTA; ele pode ser pré-carregado apenas em uma fábrica. A redefinição de fábrica afeta apenas a partição /data. A partição do sistema B ainda tem o conteúdo pré-carregado até que a imagem OTA seja baixada. Após a redefinição de fábrica, o sistema passará pela primeira inicialização novamente. Isso significa que o cache do APK não estará disponível se a imagem OTA for baixada para a partição B e, em seguida, o dispositivo for redefinido de fábrica.

Implementação

Abordagem 1. Conteúdo na partição system_other

Pro : O conteúdo pré-carregado não é perdido após a redefinição de fábrica - ele será copiado da partição B após uma reinicialização.

Contra : Requer espaço na partição B. A inicialização após a redefinição de fábrica requer tempo adicional para copiar o conteúdo pré-carregado.

Para que os pré-carregamentos sejam copiados durante a primeira inicialização, o sistema chama um script em /system/bin/preloads_copy.sh . O script é chamado com um único argumento (caminho para o ponto de montagem somente leitura para a partição system_b ):

Para implementar esse recurso, faça essas alterações específicas do dispositivo. Aqui está um exemplo de Marlin:

  1. Adicione o script que faz a cópia ao arquivo device-common.mk (neste caso, device/google/marlin/device-common.mk ), assim:
    # Script that copies preloads directory from system_other to data partition
    PRODUCT_COPY_FILES += \
        device/google/marlin/preloads_copy.sh:system/bin/preloads_copy.sh
    
    Encontre a fonte do script de exemplo em: device/google/marlin /preloads_copy.sh
  2. Edite o arquivo init.common.rc para que ele crie o diretório /data/preloads preloads e os subdiretórios necessários:
    mkdir /data/preloads 0775 system system
    mkdir /data/preloads/media 0775 system system
    mkdir /data/preloads/demo 0775 system system
    
    Encontre a fonte do arquivo init de exemplo em: device/google/marlin/init.common.rc
  3. Defina um novo domínio SELinux no arquivo preloads_copy.te :
    type preloads_copy, domain, coredomain;
    type preloads_copy_exec, exec_type, vendor_file_type, file_type;
    
    init_daemon_domain(preloads_copy)
    
    allow preloads_copy shell_exec:file rx_file_perms;
    allow preloads_copy toolbox_exec:file rx_file_perms;
    allow preloads_copy preloads_data_file:dir create_dir_perms;
    allow preloads_copy preloads_data_file:file create_file_perms;
    allow preloads_copy preloads_media_file:dir create_dir_perms;
    allow preloads_copy preloads_media_file:file create_file_perms;
    
    # Allow to copy from /postinstall
    allow preloads_copy system_file:dir r_dir_perms;
    
    Encontre um exemplo de arquivo de domínio SELinux em: /device/google/marlin/+/master/sepolicy/preloads_copy.te
  4. Registre o domínio em um novo /sepolicy/file_contexts arquivo:
    /system/bin/preloads_copy\.sh     u:object_r:preloads_copy_exec:s0
    
    Encontre um exemplo de arquivo de contexto SELinux em: device/google/marlin/sepolicy/preloads_copy.te
  5. No momento da compilação, o diretório com conteúdo pré-carregado deve ser copiado para a partição system_other :
    # Copy contents of preloads directory to system_other partition
    PRODUCT_COPY_FILES += \
        $(call find-copy-subdir-files,*,vendor/google_devices/marlin/preloads,system_other/preloads)
    
    Este é um exemplo de alteração em um Makefile que permite copiar recursos de cache APK do repositório Git do fornecedor (no nosso caso foi vendor/google_devices/ marlin/preloads) para o local na partição system_other que mais tarde será copiada para /data/preloads quando o dispositivo for inicializado pela primeira vez. Este script é executado em tempo de compilação para preparar a imagem system_other. Ele espera que o conteúdo pré-carregado esteja disponível em vendor/google_devices/marlin/preloads. O OEM é livre para escolher o nome/caminho do repositório real.
  6. O cache do APK está localizado em /data/preloads/file_cache e tem o seguinte layout:
    /data/preloads/file_cache/
        app.package.name.1/
              file1
              fileN
        app.package.name.N/
    
    Esta é a estrutura de diretório final nos dispositivos. Os OEMs são livres para escolher qualquer abordagem de implementação, desde que a estrutura do arquivo final replique a descrita acima.

Abordagem 2. O conteúdo da imagem de dados do usuário foi atualizado na fábrica

Essa abordagem alternativa pressupõe que o conteúdo pré-carregado já esteja incluído no diretório /data/preloads na partição /data .

Pro : Funciona imediatamente - não há necessidade de fazer personalizações de dispositivos para copiar arquivos na primeira inicialização. O conteúdo já está na partição /data .

Contra : O conteúdo pré-carregado é perdido após uma redefinição de fábrica. Embora isso possa ser aceitável para alguns, nem sempre funciona para OEMs que redefiniram os dispositivos de fábrica depois de fazer inspeções de controle de qualidade.

Um novo método @SystemApi, getPreloadsFileCache() , foi adicionado ao android.content.Context . Ele retorna um caminho absoluto para um diretório específico do aplicativo no cache pré-carregado.

Foi adicionado um novo método, IPackageManager.deletePreloadsFileCache , que permite excluir o diretório de pré-carregamentos para recuperar todo o espaço. O método pode ser chamado apenas por aplicativos com SYSTEM_UID, ou seja, servidor do sistema ou Configurações.

Preparação do aplicativo

Somente aplicativos privilegiados podem acessar o diretório de cache de pré-carregamentos. Para esse acesso, os aplicativos devem ser instalados no diretório /system/priv-app .

Validação

  • Após a primeira inicialização, o dispositivo deve ter conteúdo no diretório /data/preloads/file_cache .
  • O conteúdo no diretório file_cache/ deve ser excluído se o dispositivo estiver com pouco armazenamento.

Use o aplicativo ApkCacheTest de exemplo para testar o cache do APK.

  1. Compile o aplicativo executando este comando no diretório raiz:
    make ApkCacheTest
    
  2. Instale o aplicativo como um aplicativo privilegiado. (Lembre-se, apenas aplicativos privilegiados podem acessar o cache do APK.) Isso requer um dispositivo com root:
    adb root && adb remount
    adb shell mkdir /system/priv-app/ApkCacheTest
    adb push $ANDROID_PRODUCT_OUT/data/app/ApkCacheTest/ApkCacheTest.apk /system/priv-app/ApkCacheTest/
    adb shell stop && adb shell start
    
  3. Simule o diretório de cache de arquivos e seu conteúdo, se necessário (também exigindo privilégios de root):
    adb shell mkdir -p /data/preloads/file_cache/com.android.apkcachetest
    adb shell restorecon -r /data/preloads
    adb shell "echo "Test File" > /data/preloads/file_cache/com.android.apkcachetest/test.txt"
    
  4. Teste o aplicativo. Após instalar o aplicativo e criar o diretório test file_cache , abra o aplicativo ApkCacheTest. Deve mostrar um arquivo test.txt e seu conteúdo. Veja esta captura de tela para ver como esses resultados aparecem na interface do usuário.

    Figura 1. Resultados do ApkCacheTest