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. Isso a realocação permite mover o código com flash para um ambiente local comum com apenas as partes do fastboot específicas do fornecedor implementadas por um camada de abstração de hardware (HAL). Além disso, o Android 12 e versões mais recentes oferecem suporte à atualização em ramdisks com um comando de 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 um 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 do daemon e do 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. A recuperação analisa a mensagem BCB e muda para o modo fastbootd.

Comandos adb

Esta seção descreve o comando adb para integrar o 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 de fastboot

Esta seção descreve os comandos do fastboot para integrar o fastbootd, incluindo novos comandos para atualização e gerenciamento de partições lógicas. Algumas têm resultados diferentes dependendo se eles foram executados carregador de inicialização 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 Reinicia para fastbootd.
getvar is-userspace
  • Retorna yes (fastbootd).
  • Retorna no (carregador de inicialização).
getvar is-logical:<partition> Retorna yes se a partição especificada é uma partição lógica. Caso contrário, no. As partições lógicas oferecem suporte a 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 fornecidos. O nome não pode já 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. Ocorrerá uma falha se não houver espaço suficiente disponível para fazer o redimensionamento.
update-super <partition> Mescla as alterações nos metadados da superpartição. Se não for possível fazer uma mesclagem (por exemplo, o formato no dispositivo é uma versão sem suporte), este falha. Um parâmetro wipe opcional substitui o parâmetro em vez de mesclar.
flash <partition><filename> ] Grava um arquivo em uma partição flash. O dispositivo precisa estar desbloqueado.
erase <partition> Apaga 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 diferenciados adicionando os sufixos _a, _b e e assim por diante, para o nome da partição.

reboot Reinicializa o dispositivo normalmente.
reboot-bootloader (ou reboot bootloader) Reinicializa 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 inteiro da partição e o tamanho do bloco. Recebe dados para cada bloco, e agrupa os dados 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 à atualização 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 que ela pisca depende de: a versão do cabeçalho de inicialização é a versã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 oferecem suporte à atualização em ramdisks do fornecedor.

Busca a imagem vendor_boot. Retornará um erro se o cabeçalho de inicialização do fornecedor for a versão 3. Se for a versão 4, ele encontra a versão fragmento do ramdisk do fornecedor (se disponível). Ela substitui o código pela imagem fornecida, recalcula tamanhos e deslocamentos e atualiza 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 bootloader, radio e boot/recovery. Depois disso, o dispositivo inicializa no fastboot (espaço do usuário) e atualiza todas as outras partições. O carregador de inicialização precisa ser compatível com os comandos abaixo.

Comando Descrição
download Faz o download da imagem para atualização.
flash recovery <image>/ flash boot <image>/ flash bootloader <image>/ Atualiza a partição recovery/boot e o carregador de inicialização.
reboot Reinicializa o dispositivo.
reboot fastboot Reinicializa para o fastboot.
reboot recovery Reinicializa 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 atualização ou a limpeza de partições dinâmicas e precisa retornar um erro se essas operações forem tentadas. Para dispositivos retrô dispositivos de partição dinâmica, a ferramenta fastboot (e o carregador de inicialização) oferecem suporte a uma para atualizar diretamente uma partição dinâmica enquanto estiver no modo de carregador de inicialização. Para Por exemplo, se system for uma partição dinâmica no dispositivo atualizado, o uso do comando fastboot --force flash system ativa o carregador de inicialização (em vez de fastbootd) para atualizar a partição.

Carregamento fora do modo

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

HAL de OEM de fastboot

Para substituir completamente o fastboot, o fastboot precisa lidar fastboot. 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 são documentadas. Para processar esses comandos, o HAL do fastboot especifica os comandos 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. Verifique se o HAL do Fastboot, o HAL de controle de inicialização e o 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. Para exemplo, fastbootd requer acesso de gravação a uma partição específica do dispositivo para atualizar a 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).

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 o fastboot no lado do host para ler o cabeçalho de inicialização do fornecedor, restaurar a imagem e atualizar a nova imagem.

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. OEMs podem adicionar o comando fetch:vendor_boot à implementação do carregador de inicialização protocolo. No entanto, se o comando não for reconhecido no modo de carregador de inicialização, a atualização em ramdisks de fornecedores individuais no modo de carregador de inicialização não é compatível com o fornecedor é a melhor opção.

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 no fastboot

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

O fetch:name[:offset[:size]] realiza uma série de verificações no dispositivo. Se todos dos itens a seguir forem verdadeiros, o comando fetch:name[:offset[:size]] vai retornar dados:

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

Após a verificação, fetch:name[:offset[:size]] retorna o tamanho da partição. e deslocamento. Observe o seguinte:

  • fetch:name é equivalente a fetch:name:0, que é equivalente 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 forem especificados, o são usados os valores padrão, sendo 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, então normalmente há apenas um bloco.
    • Une os dados para out.img.
  • fastboot flash vendor_boot:default vendor-ramdisk.img

    Essa é uma variante especial do comando flash. Ela busca Imagem vendor_boot, como se fastboot fetch fosse chamado.

    • Se a inicialização do fornecedor for a version de cabeçalho 3, ele faz o seguinte:
      • Substitui o ramdisk do fornecedor pela imagem especificada.
      • Mostra a nova imagem vendor_boot.
    • Se o cabeçalho de inicialização do fornecedor for version [versão] 4, ele faz 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 forem encontradas, ou se houver várias correspondências, retornará um erro.
      • 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 está reservado para nomear os fragmentos do ramdisk do fornecedor em Android 12 e versões mais recentes. Enquanto o fastboot flash vendor_boot:default sem mudar a mesma semântica, não dê nomes aos fragmentos do ramdisk como default.

Mudanças no SELinux

Uma alteração foi feita em fastbootd.te para oferecer suporte à atualização dos ramdisks do fornecedor.