Implementar o A/B virtual

Para implementar o A/B virtual em um novo dispositivo ou para retrofitar um dispositivo lançado, é necessário fazer mudanças no código específico do dispositivo.

Sinalizações de compilação

Os dispositivos que usam o A/B virtual precisam ser configurados como um dispositivo A/B e iniciar com partições dinâmicas.

Para dispositivos lançados com o A/B virtual, defina-os para herdar a configuração base do dispositivo A/B virtual:

$(call inherit-product, \
    $(SRC_TARGET_DIR)/product/virtual_ab_ota.mk)

Os dispositivos lançados com o A/B virtual precisam apenas da metade do tamanho da placa para BOARD_SUPER_PARTITION_SIZE porque os slots B não estão mais em super. Ou seja, BOARD_SUPER_PARTITION_SIZE precisa ser maior ou igual a soma(tamanho dos grupos de atualização) + overhead, que, por sua vez, precisa ser maior ou igual a soma(tamanho das partições) + overhead.

Para ativar os snapshots compactados com o Virtual A/B no Android 13 e versões mais recentes, herde a seguinte configuração básica:

$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_ramdisk.mk)
$(call inherit-product, \
    $(SRC_TARGET_DIR)/product/virtual_ab_ota/vabc_features.mk)

Isso permite snapshots do espaço do usuário com o Virtual A/B usando um método de compressão sem operação. Em seguida, configure o método de compactação para um dos métodos com suporte, zstd e lz4. No Android 15, a compactação pode ser personalizada para atender às necessidades do dispositivo. Para mais informações, consulte Ajustar a compactação.

PRODUCT_VIRTUAL_AB_COMPRESSION_METHOD := lz4
PRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR := 65536

No Android 12, para ativar snapshots compactados com A/B virtual, herde a seguinte configuração básica:

$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_ramdisk.mk)
$(call inherit-product, \
    $(SRC_TARGET_DIR)/product/virtual_ab_ota/compression.mk)

Compactação XOR

Para dispositivos que estão fazendo upgrade para o Android 13 e versões mais recentes, o recurso de compactação XOR não é ativado por padrão. Para ativar a compactação XOR, adicione o seguinte ao arquivo .mk do dispositivo.

PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.compression.xor.enabled=true

A compactação XOR é ativada por padrão para dispositivos que herdam de android_t_baseline.mk.

Mesclagem do espaço do usuário

Na versão moderna do A/B virtual (Android T e versões mais recentes), o processo de mesclagem de snapshots acontece totalmente no espaço do usuário. Essa mudança é possível com o snapuserd e o dm-user. Os dispositivos lançados com o Android 13 e versões mais recentes têm a mesclagem do espaço do usuário ativada por padrão. Para dispositivos mais antigos que estão sendo atualizados, essa propriedade pode ser definida com o seguinte:

PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.userspace.snapshots.enabled=true

HAL de controle de inicialização

O HAL de controle de inicialização oferece uma interface para que os clientes OTA controlem os slots de inicialização. O A/B virtual requer um upgrade de versão menor do HAL de controle de inicialização, porque APIs adicionais são necessárias para garantir que o carregador de inicialização seja protegido durante a atualização ou redefinição para a configuração original. Consulte IBootControl.hal e types.hal para conferir a versão mais recente da definição HAL.

// hardware/interfaces/boot/1.1/types.hal
enum MergeStatus : uint8_t {
    NONE, UNKNOWN, SNAPSHOTTED, MERGING, CANCELLED };

// hardware/interfaces/boot/1.1/IBootControl.hal
package android.hardware.boot@1.1;
interface IBootControl extends @1.0::IBootControl {
    setSnapshotMergeStatus(MergeStatus status)
        generates (bool success);
    getSnapshotMergeStatus()
        generates (MergeStatus status);
}
// Recommended implementation

Return<bool> BootControl::setSnapshotMergeStatus(MergeStatus v) {
    // Write value to persistent storage
    // e.g. misc partition (using libbootloader_message)
    // bootloader rejects wipe when status is SNAPSHOTTED
    // or MERGING
}

Mudanças no fstab

A integridade da partição de metadados é essencial para o processo de inicialização, principalmente logo após a aplicação de uma atualização OTA. Portanto, a partição de metadados precisa ser verificada antes que first_stage_init a ative. Para garantir que isso aconteça, adicione a flag fs_mgr check à entrada de /metadata. Confira um exemplo a seguir:

/dev/block/by-name/metadata /metadata ext4 noatime,nosuid,nodev,discard,sync wait,formattable,first_stage_mount,check

Requisitos do kernel

Para ativar os snapshots, defina CONFIG_DM_SNAPSHOT como true.

Para dispositivos que usam F2FS, inclua a sinalização f2fs: export FS_NOCOW_FL to user do kernel para corrigir a fixação de arquivos. Inclua o patch do kernel f2fs: support aligned pinned file.

O A/B virtual depende de recursos adicionados na versão 4.3 do kernel: o bit de status overflow nas metas snapshot e snapshot-merge. Todos os dispositivos lançados com o Android 9 e versões mais recentes já precisam ter a versão 4.4 ou mais recente do kernel.

Para ativar os snapshots compactados, a versão mínima do kernel com suporte é a 4.19. Defina CONFIG_DM_USER=m ou CONFIG_DM_USER=y. Se você usar o primeiro (um módulo), ele precisará ser carregado no ramdisk da primeira etapa. Para isso, adicione a seguinte linha ao Makefile do dispositivo:

BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD := dm-user.ko

Mudanças nas ferramentas de fastboot

O Android 11 faz as seguintes mudanças no protocolo Fastboot:

  • getvar snapshot-update-status: retorna o valor que a HAL de controle de inicialização comunicou ao carregador de inicialização:
    • Se o estado for MERGING, o carregador de inicialização precisará retornar merging.
    • Se o estado for SNAPSHOTTED, o carregador de inicialização precisará retornar snapshotted.
    • Caso contrário, o carregador de inicialização precisa retornar none.
  • snapshot-update merge: conclui uma operação de mesclagem, inicializando para recuperação/fastbootd, se necessário. Esse comando só é válido se snapshot-update-status for merging e só é compatível com fastbootd.
  • snapshot-update cancel: define o status de mesclagem da HAL do controle de inicialização como CANCELLED. Esse comando é inválido quando o dispositivo está bloqueado.
  • erase ou wipe: um erase ou wipe de metadata, userdata ou uma partição que contém o status de mesclagem da HAL de controle de inicialização precisa verificar o status de mesclagem do snapshot. Se o status for MERGING ou SNAPSHOTTED, o dispositivo vai abortar a operação.
  • set_active: um comando set_active que muda o slot ativo precisa verificar o status de mesclagem do snapshot. Se o status for MERGING, o dispositivo vai abortar a operação. O slot pode ser alterado com segurança no estado SNAPSHOTTED.

Essas mudanças foram projetadas para evitar que um dispositivo seja inicializado acidentalmente, mas podem atrapalhar as ferramentas automatizadas. Quando os comandos são usados como componente para atualizar todas as partições, como executar fastboot flashall, é recomendado usar o seguinte fluxo:

  1. Consulta getvar snapshot-update-status.
  2. Se merging ou snapshotted, emita snapshot-update cancel.
  3. Siga as etapas de piscar.

Reduzir os requisitos de armazenamento

É altamente recomendável usar a ferramenta de mapeamento de blocos para dispositivos que não têm armazenamento A/B total alocado em "Super" e que esperam usar /data conforme necessário. A ferramenta de mapeamento de blocos mantém a alocação de blocos consistente entre os builds, reduzindo gravações desnecessárias no snapshot. Isso está documentado em Reduzir o tamanho do OTA.

Algoritmos de compactação OTA

Os pacotes OTA podem ser ajustados para diferentes métricas de desempenho. O Android oferece vários métodos de compactação com suporte (lz4, zstd e none) que têm equilíbrios entre o tempo de instalação, o uso do espaço COW, o tempo de inicialização e o tempo de mesclagem do snapshot. A opção padrão ativada para ab virtual com compactação é lz4 compression method.

Ajuste fino da compactação

Os algoritmos de compactação podem ser personalizados usando dois métodos: (nível de compactação) (a quantidade de compactação alcançada em detrimento da velocidade) e (fator de compactação) (o tamanho máximo de janela compactável). O nível de compactação está disponível para determinados algoritmos, como zstd, e a mudança do nível resulta em uma troca entre velocidade e taxa de compactação. O fator de compressão descreve o tamanho máximo da janela de compressão usada durante a instalação OTA. O padrão é definido como 64k, mas pode ser substituído personalizando o parâmetro de build PRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR. Fatores de compressão compatíveis: 4k, 8k, 16k, 32k, 64k, 128k e 256k.

PRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR := 65536

OTA incremental no Pixel 8 Pro

Tempo de instalação sem a fase pós-instalação Uso do espaço COW Tempo de inicialização pós-OTA Tempo de mesclagem de snapshots
lz4 18 min 15s 2,5 GB 32,7s 98,6 s
zstd (link em inglês) 24 min e 49 seg 2,05 GB 36,3 segundos 133,2 s
none 16 min 42s 4,76 GB 28,7s 76,6 segundos

OTA completo no Pixel 8 Pro

Tempo de instalação sem a fase pós-instalação Uso do espaço COW Tempo de inicialização pós-OTA Tempo de mesclagem de snapshots
lz4 15 min 11s 4,16 GB 17,6 segundos 82,2 segundos
zstd (link em inglês) 16 min 19s 3,46 GB 21,0 segundos 106,3 s
none 13 min 33s 6,39 GB 18,5 segundos 92,5 segundos