Visão geral de A/B virtual

O Android tem dois mecanismos de atualização: atualizações A/B (sem interrupções) e atualizações não A/B. Para reduzir a complexidade do código e aprimorar o processo de atualização, no Android 11 os dois mecanismos são unificados por meio de A/B virtual para trazer atualizações perfeitas para todos os dispositivos com um custo de armazenamento minimizado. O Android 12 oferece a opção de compactação A/B virtual para compactar partições de instantâneos. Tanto no Android 11 quanto no Android 12, aplica-se o seguinte:

  • As atualizações A/B virtuais são perfeitas como as atualizações A/B. As atualizações A/B virtuais minimizam o tempo em que um dispositivo fica offline e inutilizável.
  • As atualizações virtuais A/B podem ser revertidas . Se o novo sistema operacional não inicializar, os dispositivos serão automaticamente revertidos para a versão anterior.
  • As atualizações A/B virtuais usam um mínimo de espaço extra duplicando apenas as partições usadas pelo carregador de inicialização. Outras partições atualizáveis ​​são capturadas por instantâneo .

Antecedentes e terminologia

Esta seção define a terminologia e descreve a tecnologia que suporta A/B virtual.

Mapeador de dispositivos

Device-mapper é uma camada de bloco virtual Linux usada frequentemente no Android. Com partições dinâmicas , partições como /system são uma pilha de dispositivos em camadas:

  • Na parte inferior da pilha está a superpartição física (por exemplo, /dev/block/by-name/super ) .
  • No meio está um dispositivo dm-linear , especificando quais blocos na superpartição formam a partição dada. Isso aparece como /dev/block/mapper/system_[a|b] em um dispositivo A/B ou /dev/block/mapper/system em um dispositivo não A/B.
  • Na parte superior reside um dispositivo dm-verity , criado para partições verificadas. Este dispositivo verifica se os blocos no dispositivo dm-linear estão assinados corretamente. Ele aparece como /dev/block/mapper/system-verity e é a fonte do ponto de montagem /system .

A Figura 1 mostra a aparência da pilha sob o ponto de montagem /system .

Partition stacking underneath system

Figura 1. Pilha sob o ponto de montagem /system

dm-snapshot

A/B virtual depende do dm-snapshot , um módulo mapeador de dispositivos para capturar o estado de um dispositivo de armazenamento. Ao usar dm-snapshot , há quatro dispositivos em jogo:

  • O dispositivo base é o dispositivo que foi capturado. Nesta página, o dispositivo base é sempre uma partição dinâmica, como sistema ou fornecedor.
  • O dispositivo copy-on-write (COW), para registrar alterações no dispositivo base. Pode ser de qualquer tamanho, mas deve ser grande o suficiente para acomodar todas as alterações no dispositivo base.
  • O dispositivo de instantâneo é criado usando o destino de snapshot . As gravações no dispositivo de instantâneo são gravadas no dispositivo COW. Lê do dispositivo de instantâneo lido do dispositivo base ou do dispositivo COW, dependendo se os dados acessados ​​foram alterados pelo instantâneo.
  • O dispositivo de origem é criado usando o destino snapshot-origin . Lê para o dispositivo de origem lido diretamente do dispositivo base. Grava no dispositivo de origem grava diretamente no dispositivo base, mas é feito backup dos dados originais gravando no dispositivo COW.

Device mapping for dm-snapshot

Figura 2. Mapeamento de dispositivos para dm-snapshot

Instantâneos compactados

No Android 12, como os requisitos de espaço na partição /data podem ser altos, você pode habilitar instantâneos compactados em sua compilação para atender aos requisitos de espaço mais altos da partição /data .

Os snapshots compactados A/B virtuais são criados com base em dois novos componentes disponíveis no Android 12:

  • dm-user , um módulo do kernel semelhante ao FUSE que permite que o espaço do usuário implemente dispositivos de bloco.
  • snapuserd , um daemon de espaço do usuário para implementar um novo formato de instantâneo.

Esses componentes permitem a compactação. As outras alterações necessárias feitas para implementar os recursos de instantâneos compactados são fornecidas nas próximas seções: Formato COW para instantâneos compactados , dm-user e Snapuserd .

Formato COW para instantâneos compactados

No Android 12, os instantâneos compactados usam um novo formato COW. Semelhante ao formato interno do kernel usado para instantâneos não compactados, o formato COW para os instantâneos compactados tem seções alternadas de metadados e dados. Os metadados do formato original só permitiam operações de "substituição": Substitua o bloco X na imagem base pelo conteúdo do bloco Y no instantâneo. O formato COW de instantâneos compactados é mais expressivo e suporta três operações:

  • Copiar - O bloco X no dispositivo básico deve ser substituído pelo bloco Y no dispositivo básico.
  • Substituir - O bloco X no dispositivo base deve ser substituído pelo conteúdo do bloco Y no instantâneo. Cada um desses blocos é compactado em gz.
  • Zero - O bloco X no dispositivo base deve ser substituído por todos os zeros.

As atualizações completas de OTA consistem apenas em operações de substituição e zero . Atualizações OTA incrementais também podem ter operações de cópia .

dm-usuário no Android 12

O módulo do kernel dm-user permite que o userspace do usuário implemente dispositivos de bloco mapeador de dispositivo. Uma entrada de tabela dm-user cria um dispositivo diverso em /dev/dm-user/<control-name> . Um processo de userspace de usuário pode pesquisar o dispositivo para receber solicitações de leitura e gravação do kernel. Cada solicitação tem um buffer associado para o espaço do usuário preencher (para uma leitura) ou propagar (para uma gravação).

O módulo do kernel dm-user fornece uma nova interface visível ao usuário para o kernel que não faz parte da base de código kernel.org upstream. Até que seja, o Google reserva-se o direito de modificar a interface dm-user no Android.

Snapuserd

O componente de espaço de usuário snapuserd para dm-user implementa a compactação A/B virtual.

Na versão não compactada do Virtual A/B (no Android 11 e inferior, ou no Android 12 sem a opção de instantâneo compactado), o dispositivo COW é um arquivo bruto. Quando a compactação está habilitada, o COW funciona como um dispositivo dm-user , que é conectado a uma instância do daemon snapuserd .

O kernel não usa o novo formato COW. Portanto, o componente snapuserd traduz solicitações entre o formato Android COW e o formato interno do kernel:

Snapuserd component translating requests between Android COW format and kernel built-in format

Figura 3. Diagrama de fluxo do snapuserd como tradutor entre os formatos Android e Kernel COW

Essa tradução e descompactação nunca ocorre no disco. O componente snapuserd intercepta as leituras e gravações COW que ocorrem no kernel e as implementa usando o formato Android COW.

Processos de compactação A/B virtual

Essas seções fornecem detalhes sobre os processos usados ​​na compactação A/B virtual: leitura de metadados, mesclagem e condução de transições de inicialização.

Lendo metadados

Os metadados são construídos por um daemon snapuserd . Os metadados são basicamente um mapeamento de 2 IDs, 8 bytes cada, que representam os setores a serem mesclados. Em dm-snapshot é chamado de disk_exception .

struct disk_exception {
    uint64_t old_chunk;
    uint64_t new_chunk;
};

Uma exceção de disco é usada quando um bloco de dados antigo é substituído por um novo.

Um daemon Snapuserd lê o arquivo COW interno por meio da biblioteca COW e constrói os metadados para cada uma das operações COW presentes no arquivo COW.

As leituras de metadados são iniciadas a partir do dm-snapshot no kernel quando o dispositivo dm- dm- snapshot é criado.

A figura abaixo fornece um diagrama de sequência para o caminho de E/S para construção de metadados.

Sequence diagram, IO path for metadata construction

Figura 4. Fluxo de sequência para o caminho de E/S na construção de metadados

Mesclando

Quando o processo de inicialização estiver concluído, o mecanismo de atualização marcará o slot como inicialização bem-sucedida e iniciará a mesclagem alternando o destino dm-snapshot para o destino dm-snapshot-merge .

dm-snapshot percorre os metadados e inicia uma E/S de mesclagem para cada exceção de disco. Uma visão geral de alto nível do caminho de E/S de mesclagem é mostrada abaixo.

Merge IO path

Figura 5. Visão geral do caminho de E/S de mesclagem

Se o dispositivo for reinicializado durante o processo de mesclagem, a mesclagem será retomada na próxima reinicialização e a mesclagem será concluída.

Iniciar transições

Ao inicializar com instantâneos compactados, o init de primeiro estágio deve iniciar o snapuserd para montar partições. Isso representa um problema: quando sepolicy é carregada e aplicada, snapuserd é colocado no contexto errado e suas solicitações de leitura falham, com negações do selinux.

Para resolver isso, o snapuserd a transição em lock-step com init , da seguinte maneira:

  1. O init de primeiro estágio inicia o snapuserd do ramdisk e salva um descritor de arquivo aberto nele em uma variável de ambiente.
  2. O init de primeiro estágio alterna o sistema de arquivos raiz para a partição do sistema e, em seguida, executa a cópia do sistema de init .
  3. A cópia do sistema de init lê a sepolicy combinada em uma string.
  4. Init invoca mlock() em todas as páginas suportadas por ext4. Em seguida, ele desativa todas as tabelas de mapeador de dispositivos para dispositivos de instantâneo e interrompe snapuserd . Depois disso, é proibido ler partições, pois isso causa deadlock.
  5. Usando o descritor aberto para a cópia do ramdisk do snapuserd , o init reinicia o daemon com o contexto selinux correto. As tabelas do mapeador de dispositivos para dispositivos de captura instantânea são reativadas.
  6. Init invoca munlockall() - é seguro executar IO novamente.

Uso do espaço

A tabela a seguir fornece uma comparação do uso de espaço para diferentes mecanismos OTA usando o SO do Pixel e os tamanhos OTA.

Impacto do tamanho não A/B A/B A/B virtual Virtual A/B (comprimido)
Imagem original de fábrica 4,5 GB super (imagem 3,8 G + 700 M reservados) 1 9 GB super (3,8 G + 700 M reservados, para dois slots) 4,5 GB super (imagem 3,8 G + 700 M reservados) 4,5 GB super (imagem 3,8 G + 700 M reservados)
Outras partições estáticas /cache Nenhum Nenhum Nenhum
Armazenamento adicional durante o OTA (espaço devolvido após a aplicação do OTA) 1,4 GB em /dados 0 3,8 GB 2 em /dados 2,1 GB 2 em /dados
Armazenamento total necessário para aplicar a OTA 5,9 GB 3 (super e dados) 9 GB (super) 8,3 GB 3 (super e dados) 6,6 GB 3 (super e dados)

1 Indica o layout assumido com base no mapeamento de Pixel.

2 Pressupõe que a nova imagem do sistema tenha o mesmo tamanho que a original.

3 O requisito de espaço é transitório até a reinicialização.

Para implementar o Virtual A/B ou usar recursos de instantâneo compactado, consulte Implementando o Virtual A/B