Esta página descreve as mudanças adicionadas ao AOSP para reduzir alterações desnecessárias de arquivos entre builds. Os implementadores de dispositivos que mantêm os próprios sistemas de build podem usar essas informações como um guia para reduzir o tamanho das atualizações over-the-air (OTA).
As atualizações OTA do Android ocasionalmente contêm arquivos alterados que não correspondem a mudanças de código. Na verdade, eles são artefatos do sistema de build. Isso pode ocorrer quando o mesmo código, criado em momentos diferentes, de diretórios diferentes ou em máquinas diferentes, produz um grande número de arquivos alterados. Esses arquivos em excesso aumentam o tamanho de um patch OTA e dificultam a determinação de qual código foi alterado.
Para tornar o conteúdo de uma OTA mais transparente, o AOSP inclui mudanças no sistema de build projetadas para reduzir o tamanho dos patches OTA. As mudanças desnecessárias de arquivos entre builds foram eliminadas, e apenas os arquivos relacionados a patches estão contidos nas atualizações OTA. O AOSP também inclui uma ferramenta de diff de build, que filtra mudanças comuns de arquivos relacionados a builds para fornecer um diff de arquivo de build mais limpo, e uma ferramenta de mapeamento de blocos, que ajuda a manter a alocação de blocos consistente.
Um sistema de build pode criar patches desnecessariamente grandes de várias maneiras. Para atenuar isso, no Android 8.0 e mais recentes, novos recursos foram implementados para reduzir o tamanho do patch para cada diff de arquivo. As melhorias que reduziram os tamanhos dos pacotes de atualização OTA incluem o seguinte:
-
Uso do ZSTD, um algoritmo de compactação sem perdas de uso geral para imagens completas
em atualizações de dispositivos não A/B. O ZSTD pode ser personalizado para taxas de compactação mais altas, aumentando o nível de compactação. O nível de compactação é definido durante o tempo de geração da OTA
e pode ser definido transmitindo a flag
--vabc_compression_param=zstd,$COMPRESSION_LEVEL -
Aumento do tamanho da janela de compactação usada durante a OTA. O tamanho máximo da janela de compactação
pode ser definido personalizando o parâmetro de build no arquivo
.mkde um dispositivo. Esta variável é definida comoPRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR := 262144 - Uso da recompilação Puffin, uma ferramenta de aplicação de patch determinística para fluxos de descompactação, que processa as funções de compactação e diff para a geração de atualização OTA A/B.
-
Mudanças no uso da ferramenta de geração delta, como a forma como a
bsdiffbiblioteca é usada para compactar patches. No Android 9 e mais recentes, absdiffferramenta seleciona o algoritmo de compactação que oferece os melhores resultados de compactação para um patch. -
As melhorias no
update_engineresultaram em menos memória consumida quando os patches são aplicados para atualizações de dispositivos A/B.
As seções a seguir discutem vários problemas que afetam os tamanhos de atualização OTA, as soluções, e exemplos de implementação no AOSP.
Ordem dos arquivos
Problema: os sistemas de arquivos não garantem uma ordem de arquivos quando solicitam uma lista de
arquivos em um diretório, embora seja comum que seja a mesma para o mesmo checkout. Ferramentas como
ls classificam os resultados por padrão, mas a função de caractere curinga usada por comandos such
as find e make não classificam. Antes de usar essas ferramentas, é necessário classificar
as saídas.
Solução: ao usar ferramentas como find e
make com a função de caractere curinga, classifique a saída desses comandos antes de usá
-los. Ao usar $(wildcard) ou $(shell find) em
Android.mk arquivos, classifique-os também. Algumas ferramentas, como o Java, classificam as entradas. Portanto, antes de classificar os arquivos, verifique se a ferramenta que você está usando já fez isso.
Exemplos: muitas instâncias foram corrigidas no sistema de build principal usando a macro
integrada all-*-files-under, que inclui
all-cpp-files-under (já que várias definições foram distribuídas em outros makefiles).
Para mais detalhes, consulte o seguinte:
- https://android.googlesource.com/platform/build/+/4d66adfd0e6d599d8502007e4ea9aaf82e95569f
- https://android.googlesource.com/platform/build/+/379f9f9cec4fe1c66b6d60a6c19fecb81b9eb410
- https://android.googlesource.com/platform/build/+/7c3e3f8314eec2c053012dd97d2ae649ebeb5653
- https://android.googlesource.com/platform/build/+/5c64b4e81c1331cab56d8a8c201f26bb263b630c
Diretório de build
Problema: mudar o diretório em que as coisas são criadas pode fazer com que os
binários sejam diferentes. A maioria dos caminhos no build do Android são relativos, então
__FILE__ em C/C++ não é um problema. No entanto, os símbolos de depuração codificam o nome do caminho completo
por padrão, e o .note.gnu.build-id é gerado a partir da hash do
binário pré-removido. Portanto, ele vai mudar se os símbolos de depuração mudarem.
Solução:o AOSP agora torna os caminhos de depuração relativos. Para mais detalhes, consulte CL: https://android.googlesource.com/platform/build/+/6a66a887baadc9eb3d0d60e26f748b8453e27a02.
Carimbos de data/hora
Problema:os carimbos de data/hora na saída do build resultam em mudanças desnecessárias de arquivos. É provável que isso aconteça nos seguintes locais:
- Macros
__DATE__/__TIME__/__TIMESTAMP__em código C ou C++. - Carimbos de data/hora incorporados em arquivos baseados em zip.
Soluções/exemplos: para remover carimbos de data/hora da saída do build, use as instruções fornecidas abaixo em __DATE__/__TIME__/__TIMESTAMP__ em C/C++. e Carimbos de data/hora incorporados em arquivos.
__DATE__/__TIME__/__TIMESTAMP__ em C/C++
Essas macros sempre produzem saídas diferentes para builds diferentes. Portanto, não as use. Confira algumas opções para eliminar essas macros:
- Remova-as. Para um exemplo, consulte https://android.googlesource.com/platform/system/core/+/30622bbb209db187f6851e4cf0cdaa147c2fca9f.
- Para identificar exclusivamente o binário em execução, leia o build-id do cabeçalho ELF.
-
Para saber quando o SO foi criado, leia
ro.build.date. Isso funciona para tudo, exceto builds incrementais, que podem não atualizar essa data. Para um exemplo, consulte https://android.googlesource.com/platform/external/libchrome/+/8b7977eccc94f6b3a3896cd13b4aeacbfa1e0f84.
Carimbos de data/hora incorporados em arquivos (zip, jar)
O Android 7.0 corrigiu o problema de carimbos de data/hora incorporados em arquivos zip adicionando
-X a todos os usos do zip comando. Isso removeu o UID/GID do
builder e o carimbo de data/hora Unix estendido do arquivo zip.
Uma nova ferramenta, ziptime (localizada em
/platform/build/+/android17-release/tools/ziptime/) redefine os carimbos de data/hora normais nos cabeçalhos zip. Para mais detalhes, consulte o
arquivo README.
A ferramenta signapk define carimbos de data/hora para os arquivos APK que podem variar dependendo do
fuso horário do servidor. Para mais detalhes, consulte o CL
https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028.
A ferramenta signapk define carimbos de data/hora para os arquivos APK que podem variar dependendo do
fuso horário do servidor. Para mais detalhes, consulte o CL
https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028.
Strings de versão
Problema:as strings de versão do APK geralmente tinham o BUILD_NUMBER anexado
às versões codificadas. Mesmo que nada mais mudasse em um APK, ele
ainda seria diferente.
Solução:remova o número da versão da string de versão do APK.
Exemplos :
- https://android.googlesource.com/platform/packages/apps/Camera2/+/5e0f4cf699a4c7c95e2c38ae3babe6f20c258d27
- https://android.googlesource.com/platform/build/+/d75d893da8f97a5c7781142aaa7a16cf1dbb669c
Ativar a computação de veracidade no dispositivo
Se o dm-verity estiver ativado no dispositivo, as ferramentas OTA vão detectar automaticamente a configuração de veracidade e ativar a computação de veracidade no dispositivo. Isso permite que os blocos de veracidade sejam computados em dispositivos Android, em vez de serem armazenados como bytes brutos no pacote OTA. Os blocos de veracidade podem usar aproximadamente 16 MB para uma partição de 2 GB.
No entanto, a computação de veracidade no dispositivo pode levar muito tempo. Especificamente, o código de correção de erros direta
pode levar muito tempo. Em dispositivos Pixel, geralmente leva até 10
minutos. Em dispositivos de baixa qualidade, pode levar mais tempo. Se você quiser desativar a computação de veracidade no dispositivo, mas ainda ativar o dm-verity, transmita --disable_fec_computation para a ferramenta ota_from_target_files ao gerar uma atualização OTA. Essa flag desativa a computação de veracidade no dispositivo durante as atualizações OTA.
Ela diminui o tempo de instalação da OTA, mas aumenta o tamanho do pacote. Se o dispositivo não tiver o dm-verity ativado, a transmissão dessa flag não terá efeito.
Ferramentas de build consistentes
Problema: as ferramentas que geram arquivos instalados precisam ser consistentes (uma determinada entrada sempre precisa produzir a mesma saída).
Soluções/exemplos:as mudanças foram necessárias nas seguintes ferramentas de build:
- Criador de arquivos NOTICE. O criador de arquivos NOTICE foi alterado para criar coleções NOTICE reproduzíveis. Consulte CL: https://android.googlesource.com/platform/build/+/8ae4984c2c8009e7a08e2a76b1762c2837ad4f64.
- Kit de compilador Java Android (Jack). O conjunto de ferramentas Jack exigiu uma atualização para processar mudanças ocasionais na ordem do construtor gerado. Os acessadores determinísticos para construtores foram adicionados ao conjunto de ferramentas: https://android.googlesource.com/toolchain/jack/+/056a5425b3ef57935206c19ecb198a89221ca64b.
- Compilador ART AOT (dex2oat). O binário do compilador ART recebeu uma atualização que adicionou uma opção para criar uma imagem determinística: https://android.googlesource.com/platform/art/+/ace0dc1dd5480ad458e622085e51583653853fb9.
-
O arquivo libpac.so (V8). Cada build cria um arquivo
/system/lib/libpac.sodiferente porque o snapshot do V8 muda para cada build. A solução foi remover o snapshot: https://android.googlesource.com/platform/external/v8/+/e537f38c36600fd0f3026adba6b3f4cbcee1fb29. - Arquivos de pré-dexopt do aplicativo (.odex). Os arquivos de pré-dexopt (.odex) continham preenchimento não inicializado em sistemas de 64 bits. Isso foi corrigido: https://android.googlesource.com/platform/art/+/34ed3afc41820c72a3c0ab9770be66b6668aa029.
Usar a ferramenta de diff de build
Para casos em que não é possível eliminar mudanças de arquivos relacionados a builds, o AOSP inclui uma
ferramenta de diff de build,
target_files_diff.py
para uso na comparação de dois pacotes de arquivos. Essa ferramenta executa um diff recursivo entre dois
builds, excluindo mudanças comuns de arquivos relacionados a builds, como
- Mudanças esperadas na saída do build (por exemplo, devido a uma mudança no número da versão).
- Mudanças devido a problemas conhecidos no sistema de build atual.
Para usar a ferramenta de diff de build, execute o seguinte comando:
target_files_diff.py dir1 dir2
dir1 e dir2 são diretórios de base que contêm os arquivos de destino extraídos para cada build.
Manter a alocação de blocos consistente
Para um determinado arquivo, embora o conteúdo permaneça o mesmo entre dois builds, os blocos reais que contêm os dados podem ter mudado. Como resultado, o atualizador precisa executar E/S desnecessárias para mover os blocos para uma atualização OTA.
Em uma atualização OTA A/B virtual, a E/S desnecessária pode aumentar muito o espaço de armazenamento necessário para armazenar o snapshot de cópia na gravação. Em uma atualização OTA não A/B, mover os blocos para um atualização OTA contribui para o tempo de atualização, já que há mais E/S devido a movimentos de blocos.
Para resolver esse problema, no Android 7.0, o Google estendeu a ferramenta make_ext4fs para
manter a alocação de blocos consistente em builds. A ferramenta make_ext4fs aceita
uma flag opcional -d base_fs que tenta alocar arquivos para os mesmos blocos
ao gerar uma imagem ext4. É possível extrair os arquivos de mapeamento de blocos (como os arquivos de mapa
base_fs) do arquivo zip dos arquivos de destino de um build anterior. Para cada
ext4 partição, há um .map arquivo no
IMAGES diretório (por exemplo, IMAGES/system.map corresponde à
system partição). Esses base_fs arquivos podem ser registrados e
especificados usando PRODUCT_<partition>_BASE_FS_PATH, como neste exemplo:
PRODUCT_SYSTEM_BASE_FS_PATH := path/to/base_fs_files/base_system.map PRODUCT_SYSTEM_EXT_BASE_FS_PATH := path/to/base_fs_files/base_system_ext.map PRODUCT_VENDOR_BASE_FS_PATH := path/to/base_fs_files/base_vendor.map PRODUCT_PRODUCT_BASE_FS_PATH := path/to/base_fs_files/base_product.map PRODUCT_ODM_BASE_FS_PATH := path/to/base_fs_files/base_odm.map
Embora isso não ajude a reduzir o tamanho geral do pacote OTA, ele melhora a performance da atualização OTA reduzindo a quantidade de E/S. Para atualizações A/B virtuais, ele reduz drasticamente a quantidade de espaço de armazenamento necessário para aplicar a OTA.
Evitar atualizar apps
Além de minimizar os diffs de build, é possível reduzir os tamanhos de atualização OTA excluindo atualizações para apps que recebem atualizações pelas lojas de apps. Os APKs geralmente compreendem uma parte significativa de várias partições em um dispositivo. Incluir as versões mais recentes de apps que são atualizados pelas lojas de apps em uma atualização OTA pode ter um grande impacto no tamanho dos pacotes OTA e oferecer pouco benefício ao usuário. Quando os usuários recebem um pacote OTA, eles já podem ter o app atualizado ou uma versão ainda mais recente, recebida diretamente das lojas de apps.