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 dispositivodm-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
.
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.
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:
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.
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.
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:
- O
init
de primeiro estágio inicia osnapuserd
do ramdisk e salva um descritor de arquivo aberto nele em uma variável de ambiente. - 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 deinit
. - A cópia do sistema de
init
lê a sepolicy combinada em uma string. -
Init
invocamlock()
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 interrompesnapuserd
. Depois disso, é proibido ler partições, pois isso causa deadlock. - Usando o descritor aberto para a cópia do ramdisk do
snapuserd
, oinit
reinicia o daemon com o contexto selinux correto. As tabelas do mapeador de dispositivos para dispositivos de captura instantânea são reativadas. - 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