Reduza o tamanho OTA

Esta página descreve as alterações adicionadas ao AOSP para reduzir alterações desnecessárias de arquivos entre compilações. Os implementadores de dispositivos que mantêm seus próprios sistemas de compilação podem usar essas informações como um guia para reduzir o tamanho de suas atualizações over-the-air (OTA).

As atualizações do Android OTA ocasionalmente contêm arquivos alterados que não correspondem às alterações de código. Na verdade, eles são artefatos de sistema de construção. Isso pode ocorrer quando o mesmo código, construído em momentos diferentes, em 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 um OTA mais transparente, o AOSP inclui alterações no sistema de compilação projetadas para reduzir o tamanho dos patches OTA. Alterações desnecessárias de arquivos entre compilações foram eliminadas e apenas arquivos relacionados a patches estão contidos em atualizações OTA. O AOSP também inclui uma ferramenta de comparação de compilação , que filtra alterações comuns de arquivo relacionadas à compilação para fornecer uma comparação de arquivo de compilação mais limpa, e uma ferramenta de mapeamento de bloco , que ajuda a manter a alocação de bloco consistente.

Um sistema de compilação pode criar patches desnecessariamente grandes de diversas maneiras. Para atenuar isso, no Android 8.0 e superior, novos recursos foram implementados para reduzir o tamanho do patch para cada diferença de arquivo. As melhorias que reduziram os tamanhos dos pacotes de atualização OTA incluem o seguinte:

  • Uso de Brotli , um algoritmo de compactação sem perdas de propósito genérico para imagens completas em atualizações de dispositivos não A/B. Brotli pode ser personalizado para otimizar a compactação. Em atualizações maiores compostas por dois ou mais blocos no sistema de arquivos (por exemplo, system.img ), os fabricantes de dispositivos ou parceiros podem adicionar seus próprios algoritmos de compactação e podem usar algoritmos de compactação diferentes em blocos diferentes da mesma atualização.
  • Uso da recompactação Puffin , uma ferramenta de patch determinística para fluxos deflacionados, que lida com as funções de compactação e comparação para geração de atualização A/B OTA.
  • Mudanças no uso da ferramenta de geração delta, como a forma como a biblioteca bsdiff é usada para compactar patches. No Android 9 e versões posteriores, a ferramenta bsdiff seleciona o algoritmo de compactação que forneceria os melhores resultados de compactação para um patch.
  • Melhorias no update_engine resultaram em menos memória consumida quando patches são aplicados para atualizações de dispositivos A/B.
  • Melhorias na divisão de arquivos zip grandes para atualizações OTA baseadas em blocos. Um modo no imgdiff divide arquivos APK grandes, com base nos nomes das entradas. Isso produz um patch menor em comparação com a divisão linear de arquivos e o uso da ferramenta bsdiff para compactá-los.

As seções a seguir discutem vários problemas que afetam os tamanhos de atualização OTA, suas 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 solicitada uma lista de arquivos em um diretório, embora geralmente seja a mesma para o mesmo checkout. Ferramentas como ls classificam os resultados por padrão, mas a função curinga usada por comandos como find e make não classifica. Antes de usar essas ferramentas, você deve classificar as saídas.

Solução : Ao usar ferramentas como find e make com a função curinga, classifique a saída desses comandos antes de usá-los. Ao usar $(wildcard) ou $(shell find) em arquivos Android.mk , classifique-os também. Algumas ferramentas, como Java, classificam as entradas, portanto, antes de classificar os arquivos, verifique se a ferramenta que você está usando ainda não o fez.

Exemplos: Muitas instâncias foram corrigidas no sistema de compilação principal usando a macro integrada all-*-files-under , que inclui all-cpp-files-under (já que várias definições foram espalhadas em outros makefiles). Para obter detalhes, consulte o seguinte:

Diretório de construção

Problema: Alterar o diretório no qual as coisas são construídas pode fazer com que os binários sejam diferentes. A maioria dos caminhos na compilação do Android são caminhos relativos, portanto __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 do hash do binário pré-removido, portanto, ele mudará se os símbolos de depuração mudarem.

Solução: o AOSP agora torna os caminhos de depuração relativos. Para obter detalhes, consulte CL: https://android.googlesource.com/platform/build/+/6a66a887baadc9eb3d0d60e26f748b8453e27a02 .

Carimbos de data e hora

Problema: Os carimbos de data e hora na saída do build resultam em alterações desnecessárias no arquivo. É provável que isso aconteça nos seguintes locais:

  • Macros __DATE__/__TIME__/__TIMESTAMP__ em código C ou C++.
  • Carimbos de data e 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 resultados diferentes para compilações diferentes, portanto, não as utilize. Aqui estão algumas opções para eliminar essas macros:

Carimbos de data e 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 comando zip . Isso removeu o UID/GID do construtor e o carimbo de data/hora Unix estendido do arquivo zip.

Uma nova ferramenta, ziptime (localizada em /platform/build/+/main/tools/ziptime/ ) redefine os carimbos de data/hora normais nos cabeçalhos zip. Para obter 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 obter detalhes, consulte o CL https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028 .

Sequências de versão

Problema: as strings de versão do APK geralmente tinham BUILD_NUMBER anexado às suas versões codificadas. Mesmo que nada mais mudasse em um APK, o APK ainda seria diferente.

Solução: remova o número da compilação da string da versão do APK.

Exemplos:

Ativar cálculo de veracidade no dispositivo

Se o dm-verity estiver ativado no seu dispositivo, as ferramentas OTA selecionarão automaticamente sua configuração de veracidade e ativarão o cálculo de veracidade no dispositivo. Isso permite que os blocos de verdade sejam computados em dispositivos Android, em vez de serem armazenados como bytes brutos em seu pacote OTA. Os blocos Verity podem usar aproximadamente 16 MB para uma partição de 2 GB.

No entanto, a computação da verdade no dispositivo pode levar muito tempo. Especificamente, o código de correção de erro de encaminhamento pode demorar muito. Em dispositivos pixel, isso tende a levar até 10 minutos. Em dispositivos de baixo custo, pode demorar mais. Se você deseja desabilitar a computação de veridade no dispositivo, mas ainda habilitar o dm-verity, você pode fazer isso passando --disable_fec_computation para a ferramenta ota_from_target_files ao gerar uma atualização OTA. Este sinalizador desativa a computação de veracidade no dispositivo durante atualizações OTA. Diminui o tempo de instalação do OTA, mas aumenta o tamanho do pacote OTA. Se o seu dispositivo não tiver o dm-verity ativado, passar esse sinalizador não terá efeito.

Ferramentas de construção consistentes

Problema: As ferramentas que geram arquivos instalados devem ser consistentes (uma determinada entrada deve sempre produzir a mesma saída).

Soluções/Exemplos: Foram necessárias alterações nas seguintes ferramentas de construção:

Use a ferramenta de comparação de compilação

Para casos em que não é possível eliminar alterações de arquivos relacionadas à compilação, o AOSP inclui uma ferramenta de comparação de compilação, target_files_diff.py para uso na comparação de dois pacotes de arquivos. Esta ferramenta executa uma comparação recursiva entre duas compilações, excluindo alterações comuns de arquivos relacionadas à compilação, como

  • Mudanças esperadas na saída do build (por exemplo, devido a uma alteração no número do build).
  • Alterações devido a problemas conhecidos no sistema de compilação atual.

Para usar a ferramenta build diff, execute o seguinte comando:

target_files_diff.py dir1 dir2

dir1 e dir2 são diretórios base que contêm os arquivos de destino extraídos para cada compilação.

Mantenha a alocação de blocos consistente

Para um determinado arquivo, embora seu conteúdo permaneça o mesmo entre duas compilações, os blocos reais que contêm os dados podem ter sido alterados. Como resultado, o atualizador deve realizar E/S desnecessárias para mover os blocos para uma atualização OTA.

Em uma atualização Virtual A/B OTA, E/S desnecessária pode aumentar muito o espaço de armazenamento necessário para armazenar o instantâneo de cópia na gravação. Em uma atualização OTA não A/B, mover os blocos para uma atualização OTA contribui para o tempo de atualização, pois há mais E/S devido às movimentações de bloco.

Para resolver esse problema, no Android 7.0 o Google estendeu a ferramenta make_ext4fs para manter a alocação de blocos consistente entre as compilações. A ferramenta make_ext4fs aceita um sinalizador opcional -d base_fs que tenta alocar arquivos para os mesmos blocos ao gerar uma imagem ext4 . Você pode extrair os arquivos de mapeamento de bloco (como os arquivos de mapa base_fs ) do arquivo zip dos arquivos de destino de uma compilação anterior. Para cada partição ext4 , existe um arquivo .map no diretório IMAGES (por exemplo, IMAGES/system.map corresponde à partição system ). Esses arquivos base_fs podem então ser verificados e especificados via 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, melhora o desempenho da atualização OTA, reduzindo a quantidade de E/S. Para atualizações A/B virtuais, reduz drasticamente a quantidade de espaço de armazenamento necessário para aplicar o OTA.

Evite atualizar aplicativos

Além de minimizar as diferenças de compilação, você pode reduzir os tamanhos de atualização OTA excluindo atualizações para aplicativos que recebem atualizações por meio de lojas de aplicativos. Os APKs geralmente compreendem uma parte significativa de várias partições de um dispositivo. Incluir as versões mais recentes de aplicativos atualizados pelas lojas de aplicativos em uma atualização OTA pode ter um grande impacto nos pacotes OTA e fornecer poucos benefícios ao usuário. No momento em que os usuários recebem um pacote OTA, eles já podem ter o aplicativo atualizado, ou uma versão ainda mais recente, recebida diretamente das lojas de aplicativos.