Implementar o A/B virtual

Para implementar o A/B virtual em um novo dispositivo ou para adaptar um dispositivo já lançado, precisam fazer alterações no código específico do dispositivo.

Sinalizações de compilação

Dispositivos que usam o A/B virtual precisam ser configurados como A/B dispositivo e deve ser iniciado com dinâmicas partições diferentes.

Configure dispositivos que serão lançados com o A/B virtual para herdar o A/B virtual configuração base do dispositivo:

$(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 no super. Ou seja, BOARD_SUPER_PARTITION_SIZE precisa ser maior ou igual a sum(size of update groups) + overhead, que, por sua vez, precisa ser maior que ou igual a sum(size of partições) + overhead.

No Android 13 e versões mais recentes, para ativar os recursos snapshots com o A/B virtual, herdam a seguinte configuração base:

$(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 snapshots do espaço do usuário com o A/B virtual enquanto usa um ambiente autônomo . Em seguida, você pode configurar o método de compactação para um dos métodos com suporte, gz, zstd e lz4.

PRODUCT_VIRTUAL_AB_COMPRESSION_METHOD := lz4

No Android 12, para ativar snapshots compactados com O A/B virtual herda a seguinte configuração base:

$(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 fizeram upgrade para o Android 13 e versões mais recentes, a O recurso de compactação XOR não está. ativada por padrão. Para ativar a compactação XOR, adicione o seguinte ao código do .mk.

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

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

Mesclagem de espaço do usuário

Para dispositivos que fizeram upgrade para o Android 13 e versões mais recentes, a processo de mesclagem do espaço do usuário conforme descrito em Device-mapper a criação de camadas não é ativada ao padrão. Para ativar a mesclagem do espaço do usuário, adicione a linha abaixo ao .mk do dispositivo arquivo:

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

A mesclagem de espaço do usuário é ativada por padrão em dispositivos que são iniciados com 13 e superior.

HAL de controle de inicialização

O controle de inicialização HAL (link em inglês) fornece uma interface para clientes OTA controlarem os slots de inicialização. A/B virtual requer uma atualização da versão secundária da HAL de controle de inicialização porque outras APIs são necessários para garantir que o carregador de inicialização esteja protegido durante a atualização de fábrica ou a redefinição de fábrica. Consulte IBootControl.hal (em inglês) e types.hal para a versão mais recente da definição da 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 uma atualização OTA ser aplicada. Portanto, a partição de metadados precisa ser verificado antes de first_stage_init montá-lo. Para garantir que isso aconteça, adicione o Sinalização fs_mgr check para a entrada de /metadata. Confira a seguir 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 criação de snapshots, defina CONFIG_DM_SNAPSHOT como true.

Para dispositivos que usam F2FS, inclua a flag f2fs: export FS_NOCOW_FL para user do kernel para corrigir a fixação de arquivos. Inclua f2fs: suporte alinhado fixado file do kernel.

O A/B virtual depende dos recursos adicionados à versão 4.3 do kernel: o overflow. nos destinos snapshot e snapshot-merge. Lançamento de todos os dispositivos com o Android 9 e versões posteriores já devem ter a versão 4.4 ou posterior do kernel.

Para ativar snapshots compactados, a versão mínima compatível do kernel é a 4.19. Defina CONFIG_DM_USER=m ou CONFIG_DM_USER=y. Se você usar a versão anterior (um módulo), o módulo precisa ser carregado no ramdisk do primeiro estágio. Para isso, adicionando a seguinte linha ao Makefile do dispositivo:

BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD := dm-user.ko

Retrofit em dispositivos que passam por upgrade para o Android 11

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

  • Local 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 da Retrofit, sempre há espaço suficiente no para que o arquivo COW nunca seja criado em /data.

  • Sinalizações de recurso do tempo de build: para dispositivos que adaptam o A/B virtual, PRODUCT_VIRTUAL_AB_OTA e PRODUCT_VIRTUAL_AB_OTA_RETROFIT estão definidos como true, conforme mostrado abaixo:

    (call inherit-product, \
      (SRC_TARGET_DIR)/product/virtual_ab_ota_retrofit.mk)
    
  • Tamanho de superpartição: os dispositivos lançados com A/B virtual podem ser cortados. BOARD_SUPER_PARTITION_SIZE pela metade porque os slots B não estão no super partição. Os dispositivos que fazem o retroajuste do A/B virtual mantêm a superpartição antiga tamanho, então BOARD_SUPER_PARTITION_SIZE é maior ou igual a 2 * sum(tamanho dos grupos de atualização) + a sobrecarga, que, por sua vez, é maior ou igual a 2 * sum(tamanho das partições) + a sobrecarga.

Mudanças no carregador de inicialização

Durante a etapa de mesclagem de uma atualização, /data mantém a única instância inteira do SO Android. Quando a migração começar, os system, vendor e product partições estarão incompletas até a cópia ser concluída. Se o dispositivo for redefinir para a configuração original durante esse processo, por meio de recuperação ou de configuração, não será possível inicializar o dispositivo.

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

  • Se o novo build foi inicializado 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, defina o slot ativo como o antigo.

O carregador de inicialização e o fastbootd podem apagar a partição /data se o dispositivo está desbloqueado. Embora fastbootd possa forçar a conclusão da migração, a pelo carregador de inicialização. O carregador de inicialização não sabe se há ou não uma mesclagem o progresso ou quais blocos em /data constituem as partições do SO. Os dispositivos precisam impedir que o usuário torne o dispositivo inoperante sem saber (bricking) ao fazendo o seguinte:

  1. Implementar a HAL de controle de inicialização para que o carregador de inicialização possa ler o conjunto de valores pelo método setSnapshotMergeStatus().
  2. Se o status da mesclagem for MERGING ou se o status da mesclagem for SNAPSHOTTED e ele for alterado para o horário recém-atualizado, solicitar a exclusão permanente userdata, metadata ou a partição que armazena o status de mesclagem precisa ser no carregador de inicialização.
  3. Implemente o comando fastboot snapshot-update cancel para que os usuários possam sinalizar ao carregador de inicialização 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 todo o dispositivo. É seguro emitir, porque atualizar todo o dispositivo remove o OTA. As ferramentas podem detectar esse comando durante a execução implementando fastboot getvar snapshot-update-status. Isso 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 de fastboot

O Android 11 faz as mudanças abaixo no fastboot: protocolo:

  • getvar snapshot-update-status: retorna o valor que o inicializador controla a HAL comunicada com o 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 com recuperação/fastbootd, se necessário. Esse comando só é válido se snapshot-update-status é 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 com o status de mesclagem do controle de inicialização da HAL deve verificar o status da mesclagem de snapshots. Se o status for MERGING ou SNAPSHOTTED, o dispositivo deve abortar a operação.
  • set_active: um comando set_active que altera o slot ativo. deve verificar o status da mesclagem de snapshots. Se o status for MERGING, o dispositivo deve abortar a operação. O slot pode ser alterado com segurança SNAPSHOTTED.

Essas alterações foram criadas para evitar que um dispositivo não inicializasse por acidente. mas podem prejudicar o uso de ferramentas automatizadas. Quando os comandos são usados de atualizar todas as partições, por exemplo, executar fastboot flashall, ele é é recomendável usar o seguinte fluxo:

  1. Consulta getvar snapshot-update-status.
  2. Se merging ou snapshotted, emita snapshot-update cancel.
  3. Prossiga com as etapas de atualização.
.

Reduzir os requisitos de armazenamento

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

Métodos 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 (gz, lz4, zstd e none) que têm vantagens e desvantagens entre o tempo de instalação, o uso do espaço COW, o tempo de inicialização e o snapshot data/hora da mesclagem. A opção padrão habilitada para o AB virtual com compactação é a gz compression method: Observação: desempenho relativo entre métodos de compactação varia de acordo com a velocidade da CPU e a capacidade de processamento do armazenamento, que pode mudar no dispositivo. Todos os pacotes OTA gerados abaixo estão com o PostInstall desativado, o que retarda um pouco o tempo de inicialização. O tamanho total da partição dinâmica de um total de ota sem compactação é de 4,81 GB).

OTA incremental no Pixel 6 Pro

Tempo de instalação sem a fase pós-instalação Uso do espaço COW Tempo de inicialização pós-OTA Horário de mesclagem do snapshot
gz (em inglês) 24min 1,18 GB 40,2 s 45,5 s
lz4 (link em inglês) 13 min 1,49 GB 37,4s 37,1 s
none 13 min 2,90 GB 37,6 s 40,7s

OTA completa no Pixel 6 Pro

Tempo de instalação sem a fase pós-instalação Uso do espaço COW Tempo de inicialização pós-OTA Horário de mesclagem do snapshot
gz (em inglês) 23 min 2,79 GB 24,9s 41,7s
lz4 (link em inglês) 12 min 3,46 GB 20 s 25,3 s
none 10 min 4,85 GB 20,6 s 29,8 segundos