Mover o fastboot para o espaço do usuário

Fastboot é o nome de um módulo e modo do carregador de inicialização. O Android 10 e versões mais recentes oferecem suporte a partições redimensionáveis, realocando a implementação do fastboot do gerenciador de inicialização para o espaço do usuário. Essa relocalização permite mover o código de flash para um local comum de manutenção e teste com apenas as partes específicas do fornecedor do Fastboot implementadas por uma camada de abstração de hardware (HAL). Além disso, o Android 12 e versões mais recentes oferecem suporte à atualização de ramdisks usando um comando fastboot adicionado.

Unificar o fastboot e a recuperação

Como o fastboot e a recuperação do espaço do usuário são semelhantes, é possível mesclá-los em uma partição ou binário. Isso oferece vantagens, como usar menos espaço, ter menos partições no geral e ter o Fastboot e a recuperação compartilhando o kernel e as bibliotecas.

Fastbootd é o nome de um daemon e modo do espaço do usuário. Para oferecer suporte a fastbootd, o carregador de inicialização precisa implementar um novo comando de bloco de controle de inicialização (BCB, na sigla em inglês) de boot-fastboot. Para entrar no modo fastbootd, o carregador de inicialização grava boot-fastboot no campo de comando da mensagem BCB e deixa o campo recovery do BCB inalterado para permitir a reinicialização de tarefas de recuperação interrompidas. Os campos status, stage e reserved também permanecem inalterados. O carregador de inicialização carrega e inicializa a imagem de recuperação ao encontrar boot-fastboot no campo de comando do BCB. Em seguida, a recuperação analisa a mensagem do BCB e alterna para o modo fastbootd.

Comandos adb

Esta seção descreve o comando adb para integrar fastbootd. O comando tem resultados diferentes, dependendo se ele é executado pelo sistema ou pela recuperação.

Comando Descrição
reboot fastboot
  • Reinicia no fastbootd (sistema).
  • Entra em fastbootd diretamente sem uma reinicialização (recuperação).

Comandos do Fastboot

Esta seção descreve os comandos de fastboot para integrar fastbootd, incluindo novos comandos para flash e gerenciamento de partições lógicas. Alguns comandos têm resultados diferentes, dependendo se foram executados pelo bootloader ou por fastbootd.

Comando Descrição
reboot recovery
  • Reinicializa a recuperação (carregador de inicialização).
  • Entra na recuperação diretamente sem uma reinicialização (fastbootd).
reboot fastboot Reinicializa em fastbootd.
getvar is-userspace
  • Retorna yes (fastbootd).
  • Retorna no (carregador de inicialização).
getvar is-logical:<partition> Retorna yes se a partição especificada for lógica, no, caso contrário. As partições lógicas são compatíveis com todos os comandos listados abaixo.
getvar super-partition-name Retorna o nome da superpartição. O nome inclui o sufixo de slot atual se a superpartição for uma partição A/B (geralmente não é).
create-logical-partition <partition> <size> Cria uma partição lógica com o nome e o tamanho especificados. O nome não pode existir como uma partição lógica.
delete-logical-partition <partition> Exclui a partição lógica especifica (limpa a partição).
resize-logical-partition <partition> <size> Redimensiona a partição lógica para o novo tamanho sem alterar o conteúdo. Falha se não houver espaço suficiente disponível para redimensionar.
update-super <partition> Mescla as alterações nos metadados da superpartição. Se uma mesclagem não for possível (por exemplo, se o formato no dispositivo for de uma versão sem suporte), esse comando falhará. Um parâmetro wipe opcional substitui os metadados do dispositivo em vez de realizar uma mesclagem.
flash <partition><filename> ] Grava um arquivo em uma partição flash. O dispositivo precisa estar desbloqueado.
erase <partition> Exclui uma partição (não é necessário que seja um apagamento seguro). O dispositivo precisa estar desbloqueado.
getvar <variable> | all Mostra uma variável do carregador de inicialização ou todas as variáveis. Se a variável não existir, vai retornar um erro.
set_active <slot>

Define o slot de inicialização A/B especificado como active. Na próxima tentativa de inicialização, o sistema será inicializado pelo slot especificado.

Para suporte A/B, os slots são conjuntos duplicados de partições que podem ser inicializados de forma independente. Os slots são chamados de a, b e assim por diante, e são diferenciados pela adição dos sufixos _a, _b e assim por diante ao nome da partição.

reboot Reinicia o dispositivo normalmente.
reboot-bootloader (ou reboot bootloader) Reinicia o dispositivo no carregador de inicialização.
fastboot fetch vendor_boot <out.img>

Use no Android 12 e versões mais recentes para oferecer suporte a ramdisks de fornecedores.

Recebe o tamanho da partição inteira e do bloco. Recebe dados de cada bloco e os agrupa em <out.img>

Para mais detalhes, consulte fastboot fetch vendor_boot <out.img>.

fastboot flash vendor_boot:default <vendor-ramdisk.img>

Use no Android 12 e versões mais recentes para oferecer suporte a atualizações de ramdisks do fornecedor.

Essa é uma variante especial do comando flash. Ele executa uma função de imagem fetch vendor_boot, como se fastboot fetch fosse chamado. A nova imagem vendor_boot piscada depende se a versão do cabeçalho de inicialização é 3 ou 4.

Para mais detalhes, consulte fastboot flash vendor_boot:default <vendor-ramdisk.img>.

fastboot flash vendor_boot:<foo> <vendor-ramdisk.img> Use no Android 12 e versões mais recentes para oferecer suporte a atualizações de ramdisks do fornecedor.

Busca a imagem vendor_boot. Retorna um erro se o cabeçalho de inicialização do fornecedor for a versão 3. Se for a versão 4, ele vai encontrar o fragmento correto do ramdisk do fornecedor (se disponível). Ele substitui isso pela imagem fornecida, recalcula tamanhos e deslocamentos e exibe o novo vendor_boot image.

Para mais detalhes, consulte fastboot flash vendor_boot:<foo> <vendor-ramdisk.img>.

Fastboot e carregador de inicialização

O carregador de inicialização atualiza as partições bootloader, radio e boot/recovery. Depois disso, o dispositivo é inicializado no fastboot (espaço do usuário) e atualiza todas as outras partições. O carregador de inicialização precisa oferecer suporte aos comandos abaixo.

Comando Descrição
download Faz o download da imagem para flash.
flash recovery <image>/ flash boot <image>/ flash bootloader <image>/ Atualiza a partição recovery/boot e o carregador de inicialização.
reboot Reinicia o dispositivo.
reboot fastboot Reinicia para o modo fastboot.
reboot recovery Reinicia para a recuperação.
getvar Recebe uma variável do carregador de inicialização que é necessária para atualizar a imagem de recuperação/inicialização (por exemplo, current-slot e max-download-size).
oem <command> Comando definido pelo OEM.

Partições dinâmicas

O carregador de inicialização não pode permitir a gravação ou a exclusão de partições dinâmicas e precisa retornar um erro se essas operações forem tentadas. Para dispositivos atualizados de partição dinâmica, a ferramenta fastboot (e o carregador de inicialização) aceita um modo de força para atualizar diretamente uma partição dinâmica no modo de carregador de inicialização. Por exemplo, se system for uma partição dinâmica no dispositivo retrofit, o uso do comando fastboot --force flash system ativa o carregador de inicialização (em vez de fastbootd) para fazer o flash da partição.

Carregamento fora do modo

Se um dispositivo oferecer suporte ao carregamento fora do modo ou inicializar automaticamente em um modo especial quando a energia for aplicada, uma implementação do comando fastboot oem off-mode-charge 0 precisará ignorar esses modos especiais para que o dispositivo seja inicializado como se o usuário tivesse pressionado o botão de energia.

HAL OEM do fastboot

Para substituir completamente o fastboot do carregador de inicialização, o fastboot precisa processar todos os comandos existentes. Muitos desses comandos são de OEMs e estão documentados, mas exigem uma implementação personalizada. Muitos comandos específicos do OEM não estão documentados. Para processar esses comandos, a HAL de fastboot especifica os comandos do OEM necessários. Os OEMs também podem implementar os próprios comandos.

A definição de HAL do Fastboot é a seguinte:

import IFastbootLogger;

/**
 * IFastboot interface implements vendor specific fastboot commands.
 */
interface IFastboot {
    /**
     * Returns a bool indicating whether the bootloader is enforcing verified
     * boot.
     *
     * @return verifiedBootState True if the bootloader is enforcing verified
     * boot and False otherwise.
     */
    isVerifiedBootEnabled() generates (bool verifiedBootState);

    /**
     * Returns a bool indicating the off-mode-charge setting. If off-mode
     * charging is enabled, the device autoboots into a special mode when
     * power is applied.
     *
     * @return offModeChargeState True if the setting is enabled and False if
     * not.
     */
    isOffModeChargeEnabled() generates (bool offModeChargeState);

    /**
     * Returns the minimum battery voltage required for flashing in mV.
     *
     * @return batteryVoltage Minimum battery voltage (in mV) required for
     * flashing to be successful.
     */
    getBatteryVoltageFlashingThreshold() generates (int32_t batteryVoltage);

    /**
     * Returns the file system type of the partition. This is only required for
     * physical partitions that need to be wiped and reformatted.
     *
     * @return type Can be ext4, f2fs or raw.
     * @return result SUCCESS if the operation is successful,
     * FAILURE_UNKNOWN if the partition is invalid or does not require
     * reformatting.
     */
    getPartitionType(string partitionName) generates (FileSystemType type, Result result);

    /**
     * Executes a fastboot OEM command.
     *
     * @param oemCmd The oem command that is passed to the fastboot HAL.
     * @response result Returns the status SUCCESS if the operation is
     * successful,
     * INVALID_ARGUMENT for bad arguments,
     * FAILURE_UNKNOWN for an invalid/unsupported command.
     */
    doOemCommand(string oemCmd) generates (Result result);

};

Ativar o fastbootd

Para ativar o fastbootd em um dispositivo:

  1. Adicionar fastbootd a PRODUCT_PACKAGES em device.mk: PRODUCT_PACKAGES += fastbootd.

  2. Confira se a HAL de fastboot, a HAL de controle de inicialização e a HAL de integridade estão empacotados como parte da imagem de recuperação.

  3. Adicione todas as permissões SEPolicy específicas do dispositivo exigidas por fastbootd. Por exemplo, fastbootd requer acesso de gravação a uma partição específica do dispositivo para atualizar essa partição. Além disso, a implementação do HAL do Fastboot também pode exigir permissões específicas do dispositivo.

Para validar o fastboot do espaço do usuário, execute o conjunto de testes de fornecedor (VTS, na sigla em inglês).

Atualizar ramdisks do fornecedor

O Android 12 e versões mais recentes oferecem suporte a ramdisks de atualização com um comando fastboot adicionado que extrai a imagem vendor_boot completa de um dispositivo. O comando solicita que a ferramenta fastboot no lado do host leia o cabeçalho de inicialização do fornecedor, recrie a imagem e a atualize.

Para extrair a imagem vendor_boot completa, o comando fetch:vendor_boot foi adicionado ao protocolo fastboot e à implementação fastbootd do protocolo no Android 12. O fastbootd implementa isso, mas o carregador de inicialização em si pode não implementar. Os OEMs podem adicionar o comando fetch:vendor_boot à implementação do carregador de inicialização do protocolo. No entanto, se o comando não for reconhecido no modo de carregador de inicialização, atualizar ramdisks individuais do fornecedor no modo de carregador de inicialização não será uma opção compatível com o fornecedor.

Mudanças no carregador de inicialização

Os comandos getvar:max-fetch-size e fetch:name são implementados em fastbootd. Para oferecer suporte a ramdisks de fornecedor no carregador de inicialização, é necessário implementar estes dois comandos.

Mudanças do Fastbootd

getvar:max-fetch-size é semelhante a max-download-size. Ele especifica o tamanho máximo que o dispositivo pode enviar em uma resposta de DADOS. O driver não pode buscar um tamanho maior que esse valor.

O fetch:name[:offset[:size]] executa uma série de verificações no dispositivo. Se todas as condições a seguir forem verdadeiras, o comando fetch:name[:offset[:size]] vai retornar dados:

  • O dispositivo está executando um build depurável.
  • O dispositivo está desbloqueado (estado de inicialização laranja).
  • O nome da partição recuperada é vendor_boot.
  • O valor de size está dentro de 0 < size <= max-fetch-size.

Quando eles são verificados, fetch:name[:offset[:size]] retorna o tamanho e o deslocamento da partição. Observe o seguinte:

  • fetch:name é equivalente a fetch:name:0, que equivale a fetch:name:0:partition_size.
  • fetch:name:offset é equivalente a fetch:name:offset:(partition_size - offset)

Portanto, fetch:name[:offset[:size]] = fetch:name:offset:(partition_size - offset).

Quando offset ou partition_size (ou ambos) não são especificados, os valores padrão são usados, que para offset é 0 e para size é o valor calculado de partition_size - offset.

  • Deslocamento especificado, tamanho não especificado: size = partition_size - offset
  • Nenhuma especificada: valores padrão usados para ambos, size = partition_size - 0.

Por exemplo, fetch:foo busca toda a partição foo no deslocamento 0.

Mudanças de driver

Comandos foram adicionados à ferramenta de inicialização rápida para implementar mudanças no driver. Cada um deles está vinculado à definição completa na tabela de comandos do Fastboot.

  • fastboot fetch vendor_boot out.img

    • Chama getvar max-fetch-size para determinar o tamanho do bloco.
    • Chama getvar partition-size:vendor_boot[_a] para determinar o tamanho de toda a partição.
    • Chama fastboot fetch vendor_boot[_a]:offset:size para cada bloco. O tamanho do bloco é maior que o tamanho de vendor_boot, portanto, normalmente há apenas um bloco.
    • Unifica os dados ao out.img.
  • fastboot flash vendor_boot:default vendor-ramdisk.img

    Essa é uma variante especial do comando flash. Ele busca a imagem vendor_boot, como se fastboot fetch tivesse sido chamado.

    • Se o cabeçalho de inicialização do fornecedor for versão 3, ele fará o seguinte:
      • Substitui o ramdisk do fornecedor pela imagem fornecida.
      • Atualiza a nova imagem vendor_boot.
    • Se o cabeçalho de inicialização do fornecedor for a versão 4, ele fará o seguinte:
      • Substitui todo o ramdisk do fornecedor pela imagem especificada para que ela se torne o único fragmento de ramdisk do fornecedor na imagem vendor_boot.
      • Recalcula o tamanho e o deslocamento na tabela de ramdisk do fornecedor.
      • Atualiza a nova imagem vendor_boot.
  • fastboot flash vendor_boot:foo vendor-ramdisk.img

    Busca vendor_boot image, como se fastboot fetch tivesse sido chamado.

    • Se o cabeçalho de inicialização do fornecedor for a versão 3, ele vai retornar um erro.
    • Se o cabeçalho de inicialização do fornecedor for a versão 4, ele fará o seguinte:

      • Encontra o fragmento de ramdisk do fornecedor com o nome ramdisk_<var>&lt;foo></var>. Se não for encontrado ou se houver várias correspondências, um erro será retornado.
      • Substitui o fragmento de ramdisk do fornecedor pela imagem fornecida.
      • Recalcula cada tamanho e deslocamento na tabela do ramdisk do fornecedor.
      • Mostra a nova imagem vendor_boot.
    • Se <foo> não for especificado, ele tentará encontrar ramdisk_.

mkbootimg

O nome default é reservado para nomear fragmentos do ramdisk do fornecedor no Android 12 e versões mais recentes. Embora a semântica do flash vendor_boot:default do Fastboot permaneça a mesma, não é possível nomear os fragmentos de ramdisk como default.

Mudanças no SELinux

Uma mudança foi feita no fastbootd.te para oferecer suporte a ramdisks de fornecedores.