O A/B virtual é o principal mecanismo de atualização do Android. O A/B virtual se baseia em atualizações A/B legadas (consulte Atualizações do sistema A/B) e não A/B, que foi descontinuado na versão 15 para reduzir a sobrecarga de espaço das atualizações.
O A/B virtual não tem um slot extra para partições dinâmicas. Consulte partições dinâmicas. Em vez disso, o delta é gravado em um snapshot e, em seguida, mesclado à partição de base após a confirmação de uma inicialização bem-sucedida. O A/B virtual usa um formato de snapshot específico do Android. Consulte Formato COW para snapshots compactados, que permite a compactação de snapshots e minimiza o uso de espaço em disco. Em uma OTA completa, o tamanho do snapshot é reduzido em cerca de 45% com a compactação, e o tamanho do snapshot da OTA incremental é reduzido em cerca de 55%.
O Android 12 oferece a opção de compactação A/B virtual para compactar snapshots de partições. O A/B virtual oferece o seguinte:
- As atualizações A/B virtuais são ininterruptas (a atualização acontece totalmente em segundo plano enquanto o dispositivo está operacional), assim como as atualizações A/B. As atualizações do A/B virtual minimizam o tempo em que um dispositivo fica off-line e inutilizável.
- As atualizações A/B virtuais podem ser revertidas. Se o novo SO não for inicializado, os dispositivos vão reverter automaticamente 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 instantâneas.
Contexto e terminologia
Esta seção define a terminologia e descreve a tecnologia que oferece suporte ao teste A/B virtual. Durante a instalação OTA, os novos dados do sistema operacional são gravados no novo slot para partições físicas ou em um dispositivo COW específico do Android. Depois que o dispositivo é reinicializado, os dados da partição dinâmica são mesclados novamente no dispositivo base usando o dm-user e o daemon snapuserd. Esse processo acontece inteiramente no espaço do usuário.
Device-mapper
O device-mapper é uma camada de bloco virtual do Linux usada com frequência no Android. Com as partições dinâmicas, partições como /system
são uma pilha de dispositivos em camadas:
- Na parte de baixo da pilha está a partição física super (por exemplo,
/dev/block/by-name/super
). - No meio, há um dispositivo
dm-linear
, especificando quais blocos na superpartição formam a partição dinâmica. Ele 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 de cima, há um dispositivo
dm-verity
, criado para partições verificadas. Esse dispositivo verifica se os blocos no dispositivodm-linear
estão assinados corretamente. Ele aparece como/dev/block/mapper/system-verity
e é a origem do ponto de montagem/system
.
A Figura 1 mostra como é a pilha no ponto de montagem /system
.
Figura 1. Pilha no ponto de montagem /system
Snapshots compactados
No Android 12 e versões mais recentes, como os requisitos de espaço na partição /data
podem ser altos, é possível ativar snapshots compactados no build para atender aos requisitos de espaço mais altos da partição /data
.
Os snapshots compactados A/B virtuais são criados com base nos seguintes componentes disponíveis no Android 12 e versões mais recentes:
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 do espaço do usuário para implementar um novo formato de snapshot.
Esses componentes ativam a compactação. As outras mudanças necessárias para implementar os recursos de snapshots compactados são apresentadas nas próximas seções: Formato COW para snapshots compactados, dm-user e snapuserd.
Formato COW para snapshots compactados
No Android 12 e em versões mais recentes, os snapshots compactados usam um formato COW específico do Android. O formato COW contém metadados sobre a OTA e tem buffers distintos com operações COW e novos dados do sistema operacional. Em comparação com o formato de snapshot do kernel, que só permitia operações de substituição (substituir o bloco X na imagem de base pelo conteúdo do bloco Y no snapshot), o formato COW de snapshots compactados do Android é mais expressivo e oferece suporte às seguintes operações:
- Copiar: o bloco X no dispositivo base precisa ser substituído pelo bloco Y no dispositivo base.
- Substituir: o bloco X no dispositivo de base precisa ser substituído pelo conteúdo do bloco Y no snapshot. Cada um desses blocos é compactado com gz.
- Zero: o bloco X no dispositivo base precisa ser substituído por todos os zeros.
- XOR: o dispositivo COW armazena bytes compactados por XOR entre o bloco X e o bloco Y. (Disponível no Android 13 e versões mais recentes.)
As atualizações OTA completas consistem apenas em operações de substituição e zero. As atualizações OTA incrementais também podem ter operações de cópia.
O layout completo do snapshot no disco é assim:
Figura 2. Formato COW do Android no disco
dm-user
O módulo do kernel dm-user permite que o userspace
implemente dispositivos de bloco
device-mapper. Uma entrada de tabela dm-user cria um dispositivo diverso em
/dev/dm-user/<control-name>
. Um processo userspace
pode consultar o dispositivo para
receber solicitações de leitura e gravação do kernel. Cada solicitação tem um buffer associado para que o espaço do usuário preencha (para uma leitura) ou propague (para uma gravação).
O módulo do kernel dm-user
oferece uma nova interface visível para o usuário do kernel
que não faz parte da base de código upstream do kernel.org. Até lá, o Google se reserva o direito de modificar a interface dm-user
no Android.
snapuserd
O componente de espaço do usuário snapuserd
para dm-user
implementa a compactação
A/B virtual. O snapuserd é um daemon de espaço do usuário responsável por gravar e ler
os dispositivos COW do Android. Toda E/S para o snapshot precisa passar por esse serviço.
Durante a instalação OTA, novos dados do sistema operacional são gravados no snapshot pelo
snapuserd (com compactação). O parsing dos metadados e a descompactação dos novos dados de bloco também são processados aqui.
Compactação XOR
Para dispositivos lançados com o Android 13 e versões mais recentes, o recurso de compactação XOR, que é ativado por padrão, permite que snapshots do espaço do usuário armazenem bytes compactados XOR entre blocos antigos e novos. Quando apenas alguns bytes em um bloco são alterados em uma atualização do Virtual A/B, o esquema de armazenamento de compressão XOR usa menos espaço do que o esquema de armazenamento padrão porque os snapshots não armazenam bytes de 4K completos. Essa redução no tamanho do snapshot é possível porque os dados XOR contêm muitos zeros e são mais fáceis de compactar do que os dados brutos de blocos. Em dispositivos Pixel, a compactação XOR reduz o tamanho do snapshot em 25% a 40%.
Para dispositivos que estão fazendo upgrade para o Android 13 e versões mais recentes, a compactação XOR precisa estar ativada. Para mais detalhes, consulte Compactação XOR.
Fusão de snapshots
Em dispositivos lançados com o Android 13 e versões mais recentes, os processos
de snapshot e mesclagem de snapshot na compactação A/B virtual são realizados
pelo componente de espaço do usuário snapuserd
. Para dispositivos que estão sendo atualizados para o Android 13 e versões mais recentes, esse recurso precisa ser ativado. Para
detalhes, consulte Mesclagem
do espaço do usuário.
A seguir, descrevemos o processo de compactação A/B virtual:
- O framework monta a partição
/system
em um dispositivodm-verity
, que é empilhado em cima de um dispositivodm-user
. Isso significa que todas as operações de E/S do sistema de arquivos raiz são encaminhadas paradm-user
. - O
dm-user
encaminha a E/S para o daemonsnapuserd
do espaço do usuário, que processa a solicitação de E/S. - Quando a operação de mesclagem é concluída, o framework recolhe
dm-verity
em cima dedm-linear
(system_base
) e removedm-user
.
Figura 3. Processo de compactação A/B virtual
O processo de mesclagem de snapshots pode ser interrompido. Se o dispositivo for reinicializado durante o processo de fusão, ele será retomado após a reinicialização.
Transições de inicialização
Ao inicializar com snapshots compactados, o init da primeira etapa precisa iniciar
snapuserd
para montar partições. Isso causa um problema: quando o sepolicy
é carregado
e aplicado, o snapuserd
é colocado no contexto errado, e as solicitações de leitura
falham, com negações do SELinux.
Para resolver isso, as transições de snapuserd
ocorrem em sincronia com init
, da seguinte maneira:
- O
init
de primeira etapa inicia osnapuserd
do ramdisk e salva um descritor de arquivo aberto nele em uma variável de ambiente. - O
init
da primeira etapa muda o sistema de arquivos raiz para a partição do sistema e 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 com suporte a ext4. Em seguida, ele desativa todas as tabelas de mapeamento de dispositivos para dispositivos de snapshot e interrompe osnapuserd
. Depois disso, é proibido ler das partições, porque isso causa um deadlock.- Usando o descritor aberto para a cópia do ramdisk de
snapuserd
,init
reinicia o daemon com o contexto selinux correto. As tabelas de mapeamento de dispositivos para dispositivos de snapshot são reativadas. - Init invoca
munlockall()
. É seguro realizar E/S novamente.
Uso de espaço
A tabela a seguir mostra uma comparação do uso de espaço para diferentes mecanismos de OTA usando o SO e os tamanhos de OTA do Pixel.
Impacto do tamanho | não A/B | A/B | A/B virtual | A/B virtual (compactado) |
---|---|---|---|---|
Imagem original da fábrica | 4,5 GB super (imagem de 3,8 G + 700 M reservados)1 | 9 GB super (3,8 G + 700 M reservados, para dois slots) | 4,5 GB super (imagem de 3,8 G + 700 M reservados) | 4,5 GB super (imagem de 3,8 G + 700 M reservados) |
Outras partições estáticas | /cache | Nenhum | Nenhum | Nenhum |
Armazenamento adicional durante a OTA (espaço retornado após a aplicação da OTA) | 1,4 GB em /data | 0 | 3,8 GB2 em /data | 2,1 GB2 em /data |
Armazenamento total necessário para aplicar a OTA | 5,9 GB3 (super e dados) | 9GB (super) | 8,3 GB3 (super e dados) | 6,6 GB3 (super e dados) |
1Indica o layout presumido com base no mapeamento de pixels.
2: presume que a nova imagem do sistema tem o mesmo tamanho da original.
3O requisito de espaço é temporário até a reinicialização.
A/B virtual do Android 11
O Android 11 do Virtual A/B gravou na partição dinâmica usando o formato Kernel COW. Ele foi descontinuado porque o formato COW do kernel não é compatível com compactação.
A/B virtual do Android 12
No Android 12, a compactação é compatível na forma de um formato COW
específico do Android. Essa versão do A/B virtual exigia uma tradução do COW específico do Android para o formato COW do kernel. Eventualmente, isso foi substituído no Android
13, que removeu a dependência do formato COW do kernel e também de dm-snapshot
.
Para implementar o A/B virtual ou usar recursos de snapshot compactado, consulte Como implementar o A/B virtual.