Este documento descreve o design de uma solução de 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 APK armazenado na partição B quase vazia em novos dispositivos particionados A/B sem afetar qualquer espaço de dados voltado ao usuário. Por ter um cache APK disponível no dispositivo, dispositivos novos ou recentemente redefinidos para a configuração original ficam prontos para uso quase imediatamente, sem a necessidade de baixar arquivos APK do Google Play.
Casos de uso
- Armazene aplicativos pré-carregados na partição B para configuração mais rápida
- Armazene aplicativos populares na partição B para restauração mais rápida
Pré-requisitos
Para usar esse recurso, o dispositivo precisa de:
- Versão do Android 8.1 (O MR1) instalada
- Partição A/B implementada
O conteúdo pré-carregado só pode ser copiado durante a primeira inicialização. Isso ocorre porque em dispositivos que suportam atualizações de sistema A/B, a partição B não armazena realmente arquivos de imagem do sistema, mas sim conteúdo pré-carregado, como recursos de demonstração de varejo, arquivos OAT e 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 over-the-air (OTA) para baixar versões atualizadas da imagem do sistema.
Portanto, o cache do APK não pode ser atualizado via OTA; ele só pode ser pré-carregado na fábrica. A redefinição de fábrica afeta apenas a partição /data. A partição do sistema B ainda possui 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 para os padrões de fábrica.
Implementação
Abordagem 1. Conteúdo na partição system_other
Pró : 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 a reinicialização.
Con : Requer espaço na partição B. A inicialização após a redefinição de fábrica requer mais tempo 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 estas alterações específicas do dispositivo. Aqui está um exemplo de Marlin:
- 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 - Edite o arquivo
init.common.rc
para que ele crie o diretório/data/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
init
de exemplo em: device/google/marlin/init.common.rc - 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/+/main/sepolicy/preloads_copy.te - Registre o domínio em um novo
Arquivo /sepolicy/file_contexts
:/system/bin/preloads_copy\.sh u:object_r:preloads_copy_exec:s0
Encontre um exemplo de arquivo de contextos SELinux em: device/google/marlin/sepolicy/preloads_copy.te - 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 será posteriormente copiado para /data/preloads quando o dispositivo for inicializado pela primeira vez. Este script é executado em tempo de construçã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 real do repositório. - O cache 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 final do arquivo replique aquela descrita acima.
Abordagem 2. Conteúdo na imagem de dados do usuário 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
.
Con : O conteúdo pré-carregado é perdido após uma redefinição de fábrica. Embora isso possa ser aceitável para alguns, pode nem sempre funcionar para OEMs que redefinem os dispositivos de fábrica após fazerem inspeções de controle de qualidade.
Um novo método @SystemApi, getPreloadsFileCache()
, foi adicionado a 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 de aplicativos
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 deverá ter conteúdo no diretório
/data/preloads/file_cache
. - O conteúdo do diretório
file_cache/
deverá ser excluído se o dispositivo ficar com pouco armazenamento.
Use o aplicativo ApkCacheTest de exemplo para testar o cache do APK.
- Crie o aplicativo executando este comando no diretório raiz:
make ApkCacheTest
- Instale o aplicativo como um aplicativo privilegiado. (Lembre-se de que apenas aplicativos privilegiados podem acessar o cache do APK.) Isso requer um dispositivo com acesso 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
- 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"
- Teste o aplicativo. Depois de instalar o aplicativo e criar o diretório test
file_cache
, abra o aplicativo ApkCacheTest. Deve mostrar um arquivotest.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.