Implementar A/B Virtual

Para implementar A/B virtual em um novo dispositivo ou para modernizar um dispositivo iniciado, você deve fazer alterações no código específico do dispositivo.

Construir bandeiras

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

Para dispositivos iniciados com A/B virtual, configure-os para herdar a configuração básica do dispositivo A/B virtual:

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

Os dispositivos iniciados com A/B virtual precisam de apenas 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 deve ser maior ou igual a sum(size of update groups) + overhead , que, por sua vez, deve ser maior ou igual a sum(size of partitions) + overhead .

Para Android 13 e versões mais recentes, para ativar snapshots compactados com Virtual A/B, 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/android_t_baseline.mk)

Isso permite instantâneos do espaço do usuário com Virtual A/B ao usar um método de compactação não operacional. Você pode então configurar o método de compactação para um dos métodos suportados, gz , zstd e lz4 .

PRODUCT_VIRTUAL_AB_COMPRESSION_METHOD := lz4

No Android 12, para ativar snapshots compactados com Virtual A/B, 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)

Compressão XOR

Para dispositivos atualizados para Android 13 e versões posteriores, o recurso de compactação XOR não está 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 é habilitada por padrão para dispositivos que herdam de android_t_baseline.mk .

Mesclagem do espaço do usuário

Para dispositivos atualizados para o Android 13 e versões mais recentes, o processo de mesclagem do espaço do usuário, conforme descrito em Camadas do mapeador de dispositivos, não está ativado por padrão. Para ativar a mesclagem do espaço do usuário, adicione a seguinte linha ao arquivo .mk do dispositivo:

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

A mesclagem do espaço do usuário é habilitada por padrão em dispositivos lançados com 13 e superior.

Controle de inicialização HAL

O HAL de controle de inicialização fornece uma interface para clientes OTA controlarem slots de inicialização. O Virtual A/B requer uma atualização de versão secundária do HAL de controle de inicialização porque APIs adicionais são necessárias para garantir que o carregador de inicialização esteja protegido durante a atualização/redefinição de fábrica. Consulte IBootControl.hal e types.hal para obter 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, especialmente logo após a aplicação de uma atualização OTA. Portanto, a partição de metadados deve ser verificada antes de first_stage_init montá-la. Para garantir que isso aconteça, adicione o sinalizador check fs_mgr à entrada para /metadata . O seguinte fornece um exemplo:

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

Requisitos do kernel

Para ativar a captura instantânea, defina CONFIG_DM_SNAPSHOT como true .

Para dispositivos que usam F2FS, inclua o sinalizador f2fs: export FS_NOCOW_FL para o patch do kernel do usuário para corrigir a fixação de arquivos. Inclua também o f2fs: suporte ao patch do kernel de arquivo fixado alinhado .

O Virtual A/B depende de recursos adicionados na versão 4.3 do kernel: o bit de status de overflow nos destinos snapshot e snapshot-merge . Todos os dispositivos lançados com Android 9 e posterior já devem ter kernel versão 4.4 ou posterior.

Para ativar instantâneos compactados, a versão mínima do kernel suportada é 4.19. Defina CONFIG_DM_USER=m ou CONFIG_DM_USER=y . Se estiver usando o primeiro (um módulo), o módulo deve ser carregado no disco RAM do primeiro estágio. Isso pode ser conseguido adicionando a seguinte linha ao Makefile do dispositivo:

BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD := dm-user.ko

Retrofit em dispositivos atualizados para Android 11

Ao atualizar para o Android 11, os dispositivos iniciados com partições dinâmicas podem, opcionalmente, atualizar o A/B virtual. O processo de atualização é basicamente o mesmo dos dispositivos lançados com A/B virtual, com algumas pequenas diferenças:

  • Localização dos arquivos COW — Para dispositivos de inicialização, o cliente OTA usa todo o espaço vazio disponível na superpartição antes de usar o espaço em /data . Para dispositivos retroajustados, sempre há espaço suficiente na superpartição para que o arquivo COW nunca seja criado em /data .

  • Sinalizadores de recursos em tempo de construção — Para dispositivos que atualizam A/B virtual, tanto PRODUCT_VIRTUAL_AB_OTA quanto PRODUCT_VIRTUAL_AB_OTA_RETROFIT são definidos como true , conforme mostrado abaixo:

    (call inherit-product, \
        (SRC_TARGET_DIR)/product/virtual_ab_ota_retrofit.mk)
    
  • Tamanho da superpartição — Dispositivos iniciados com A/B virtual podem cortar BOARD_SUPER_PARTITION_SIZE pela metade porque os slots B não estão na superpartição. Os dispositivos que atualizam o A/B virtual mantêm o antigo tamanho da superpartição, então BOARD_SUPER_PARTITION_SIZE é maior ou igual a 2 * sum(size of update groups) + overhead , que por sua vez é maior ou igual a 2 * sum(size of partitions) + sobrecarga .

Mudanças no bootloader

Durante a etapa de mesclagem de uma atualização, /data contém a única instância completa do sistema operacional Android. Assim que a migração for iniciada, as partições nativas do system , vendor e product ficarão incompletas até que a cópia seja concluída. Se o dispositivo for redefinido para os padrões de fábrica durante esse processo, seja por recuperação ou por meio da caixa de diálogo Configurações do sistema, o dispositivo não será inicializável.

Antes de apagar /data , conclua a mesclagem na recuperação ou reversão dependendo do estado do dispositivo:

  • Se a nova compilação foi inicializada com sucesso antes, conclua a migração.
  • Caso contrário, reverta para o slot antigo:
    • Para partições dinâmicas, reverta para o estado anterior.
    • Para partições estáticas, configure o slot ativo para o slot antigo.

Tanto o bootloader quanto fastbootd podem apagar a partição /data se o dispositivo estiver desbloqueado. Embora fastbootd possa forçar a conclusão da migração, o bootloader não pode. O bootloader não sabe se uma mesclagem está em andamento ou quais blocos em /data constituem as partições do sistema operacional. Os dispositivos devem impedir que o usuário inadvertidamente torne o dispositivo inoperante (bricking), fazendo o seguinte:

  1. Implemente o HAL de controle de inicialização para que o bootloader possa ler o valor definido pelo método setSnapshotMergeStatus() .
  2. Se o status da mesclagem for MERGING ou se o status da mesclagem for SNAPSHOTTED e o slot tiver mudado para o slot recém-atualizado, as solicitações para limpar userdata , metadata ou a partição que armazena o status da mesclagem deverão ser rejeitadas no bootloader.
  3. Implemente o comando fastboot snapshot-update cancel para que os usuários possam sinalizar ao bootloader que desejam ignorar esse mecanismo de proteção.
  4. Modifique ferramentas ou scripts de atualização personalizados para emitir fastboot snapshot-update cancel ao atualizar o dispositivo inteiro. É seguro emitir isso porque atualizar todo o dispositivo remove o OTA. As ferramentas podem detectar esse comando em tempo de execução implementando fastboot getvar snapshot-update-status . Este comando ajuda a diferenciar as condições de erro.

Exemplo

struct VirtualAbState {
    uint8_t StructVersion;
    uint8_t MergeStatus;
    uint8_t SourceSlot;
};

bool ShouldPreventUserdataWipe() {
    VirtualAbState state;
    if (!ReadVirtualAbState(&state)) ...
    return state.MergeStatus == MergeStatus::MERGING ||
           (state.MergeStatus == MergeStatus::SNAPSHOTTED &&
            state.SourceSlot != CurrentSlot()));
}

Mudanças nas ferramentas do Fastboot

O Android 11 faz as seguintes alterações no protocolo fastboot:

  • getvar snapshot-update-status — Retorna o valor que o HAL de controle de inicialização comunicou ao bootloader:
    • Se o estado for MERGING , o bootloader deverá retornar merging .
    • Se o estado for SNAPSHOTTED , o bootloader deverá retornar snapshotted .
    • Caso contrário, o bootloader deverá retornar none .
  • snapshot-update merge — Conclui uma operação de mesclagem, inicializando em recovery/fastbootd se necessário. Este comando é válido apenas se snapshot-update-status estiver merging e só é compatível com fastbootd.
  • snapshot-update cancel — Define o status de mesclagem do HAL de controle de inicialização como CANCELLED . Este 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 para o HAL de controle de inicialização deve verificar o status de mesclagem do instantâneo. Se o status for MERGING ou SNAPSHOTTED , o dispositivo deverá abortar a operação.
  • set_active — Um comando set_active que altera o slot ativo deve verificar o status de mesclagem do instantâneo. Se o status for MERGING , o dispositivo deverá abortar a operação. O slot pode ser alterado com segurança no estado SNAPSHOTTED .

Essas alterações foram projetadas para evitar que um dispositivo não inicialize acidentalmente, mas podem prejudicar as ferramentas automatizadas. Quando os comandos são usados ​​como um componente de atualização de todas as partições, como executar fastboot flashall , é recomendado usar o seguinte fluxo:

  1. Consulte getvar snapshot-update-status .
  2. Se for merging ou snapshotted , emita snapshot-update cancel .
  3. Prossiga com as etapas intermitentes.

Reduza os requisitos de armazenamento

Dispositivos que não possuem armazenamento A/B completo alocado em super e esperam usar /data conforme necessário são altamente recomendados para usar a ferramenta de mapeamento de blocos. A ferramenta de mapeamento de blocos mantém a alocação de blocos consistente entre compilações, reduzindo gravações desnecessárias no instantâneo. Isso está documentado em Reduzindo o tamanho do OTA .

Métodos de compressão OTA

Os pacotes OTA podem ser ajustados para diferentes métricas de desempenho. O Android fornece vários métodos de compactação suportados ( gz , lz4 , zstd e none ) que têm compensações entre tempo de instalação, uso de espaço COW, tempo de inicialização e tempo de mesclagem de snapshot. A opção padrão habilitada para ab virtual com compactação é o gz compression method . (Observação: o desempenho relativo entre os métodos de compactação varia dependendo da velocidade da CPU e da taxa de transferência de armazenamento, que pode mudar dependendo do dispositivo. Todos os pacotes OTA gerados abaixo estão com o PostInstall desabilitado, o que diminuirá um pouco o tempo de inicialização. O tamanho total da partição dinâmica de um ota completo sem compactação é 4,81 GB ).

OTA incremental no Pixel 6 Pro

Tempo de instalação sem fase pós-instalação Uso de espaço COW Tempo de inicialização pós-OTA Tempo de mesclagem do instantâneo
gz 24 minutos 1,18 GB 40,2 segundos 45,5 segundos
lz4 13 minutos 1,49 GB 37,4 segundos 37,1 segundos
nenhum 13 minutos 2,90GB 37,6 segundos 40,7 segundos

OTA completo no Pixel 6 Pro

Tempo de instalação sem fase pós-instalação Uso do espaço COW Tempo de inicialização pós-OTA Tempo de mesclagem do instantâneo
gz 23 minutos 2,79GB 24,9 segundos 41,7 segundos
lz4 12 minutos 3,46GB 20,0 segundos 25,3 segundos
nenhum 10 minutos 4,85GB 20,6 segundos 29,8 segundos