Este documento descreve o design de uma solução de armazenamento em cache de APK para a instalação rápida de apps pré-carregados em um dispositivo compatível com partições A/B.
Os OEMs podem alocar pré-carregamentos e os apps favoritos no cache do APK armazenado na partição B, que normalmente fica vazia, em novos dispositivos com particionamento A/B, sem afetar o espaço de dados do usuário. Com um cache de APK disponível no dispositivo, os aparelhos novos ou redefinidos para a configuração original recentemente ficam prontos para uso quase imediatamente, sem precisar baixar arquivos APK do Google Play.
Casos de uso
- Armazene apps pré-carregados na partição B para uma configuração mais rápida
- Armazene apps conhecidos na partição B para restauração mais rápida
Pré-requisitos
Para usar esse recurso, o dispositivo precisa:
- A versão do Android 8.1 (O MR1) está 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 compatíveis com atualizações do sistema A/B, a partição B não armazena arquivos de imagem do sistema, mas sim conteúdo pré-carregado, como recursos de demonstração no varejo, arquivos OAT e o cache de APKs. 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 de APK não pode ser atualizado por OTA. Ele só pode ser pré-carregado em uma fábrica. A redefinição de fábrica afeta apenas a partição /data. A partição B do sistema ainda tem o conteúdo pré-carregado até que a imagem OTA seja baixada. Depois da redefinição de fábrica, o sistema vai passar pela primeira inicialização de novo. Isso significa que o cache de APK não estará disponível se a imagem OTA for baixada para a partição B e o dispositivo for redefinido para a configuração original.
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 uma reinicialização.
Desvantagem: requer espaço na partição B. A inicialização após a redefinição de fábrica leva 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 da partição system_b
):
Para implementar esse recurso, faça as seguintes mudanças específicas do dispositivo. Confira um exemplo do Marlin:
- Adicione o script que faz a cópia ao arquivo
device-common.mk
(neste caso,device/google/marlin/device-common.mk
), assim: Encontre um exemplo de origem do script em: device/google/marlin/preloads_copy.sh# 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
- Edite o arquivo
init.common.rc
para que ele crie o diretório e os subdiretórios/data/preloads
necessários: Encontre um exemplo de fonte de arquivomkdir /data/preloads 0775 system system
mkdir /data/preloads/media 0775 system system
mkdir /data/preloads/demo 0775 system system
init
em: device/google/marlin/init.common.rc - Defina um novo domínio do SELinux no arquivo
preloads_copy.te
: Encontre um exemplo de arquivo de domínio do SELinux em: /device/google/marlin/+/android16-release/sepolicy/preloads_copy.tetype 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;
- Registre o domínio em um novo arquivo
:/sepolicy/file_contexts Encontre um exemplo de arquivo de contextos do SELinux em: device/google/marlin/sepolicy/preloads_copy.te/system/bin/preloads_copy\.sh u:object_r:preloads_copy_exec:s0
- No momento da build, o diretório com conteúdo pré-carregado precisa ser copiado para a partição
system_other
: Este é um exemplo de uma mudança em um Makefile que permite copiar recursos de cache de APK do repositório Git do fornecedor (no nosso caso, era vendor/google_devices/marlin/preloads) para o local na partição system_other que será copiado posteriormente para /data/preloads quando o dispositivo for inicializado pela primeira vez. Esse script é executado no momento da build 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 pode escolher o nome/caminho real do repositório.# 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)
- O cache de APKs está localizado em
/data/preloads/file_cache
e tem o seguinte layout: Esta é a estrutura de diretórios final nos dispositivos. Os OEMs podem escolher qualquer abordagem de implementação, desde que a estrutura de arquivos final replique a descrita acima./data/preloads/file_cache/ app.package.name.1/ file1 fileN app.package.name.N/
Abordagem 2. Conteúdo em dados do usuário imagem mostrada 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
.
Pró: funciona sem precisar fazer personalizações no dispositivo para copiar arquivos na primeira inicialização. O conteúdo já está na partição /data
.
Desvantagem: 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 redefinem os dispositivos para a configuração original após fazer 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 app no cache pré-carregado.
Um novo método, IPackageManager.deletePreloadsFileCache
, foi adicionado
para permitir a exclusão do diretório de pré-carregamentos e recuperar todo o espaço. O método só pode ser chamado por apps com SYSTEM_UID, ou seja, servidor do sistema ou Configurações.
Preparação do app
Somente apps privilegiados podem acessar o diretório de cache de pré-carregamentos. Para esse
acesso, os apps precisam 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 do diretório
file_cache/
precisa ser excluído se o dispositivo ficar com pouco espaço de armazenamento.
Use o exemplo de app ApkCacheTest para testar o cache de APKs.
- Crie o app executando este comando no diretório raiz:
make ApkCacheTest
- Instale o app como um app privilegiado. Lembre-se de que apenas apps privilegiados podem acessar o cache de APKs.
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 o conteúdo dele, se necessário (também exige 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 app. Depois de instalar o app e criar o diretório de teste
file_cache
, abra o app ApkCacheTest. Ele vai mostrar um arquivotest.txt
e o conteúdo dele. Confira esta captura de tela para ver como esses resultados aparecem na interface do usuário.
Figura 1. Resultados do ApkCacheTest.