Layout da partição

No Android 10, o sistema de arquivos raiz não está mais incluído em ramdisk.img. Em vez disso, ele é mesclado em system.img. Ou seja, system.img é sempre criado como se BOARD_BUILD_SYSTEM_ROOT_IMAGE estivesse definido. Dispositivos lançados com o Android 10:

  • Use um layout de partição de sistema como raiz (aplicado automaticamente pelo build sem opções para mudar o comportamento).
  • É necessário usar um ramdisk, que é obrigatório para dm-linear.
  • Defina BOARD_BUILD_SYSTEM_ROOT_IMAGE como false. Essa configuração é usada apenas para diferenciar dispositivos que usam um ramdisk e aqueles que não usam (e, em vez disso, montam system.img diretamente).

O significado de uma configuração de sistema como raiz é diferente entre o Android 9 e o Android 10. Em uma configuração do sistema como raiz do Android 9, BOARD_BUILD_SYSTEM_ROOT_IMAGE é definido como true, o que força o build a mesclar o sistema de arquivos raiz em system.img e, em seguida, montar system.img como o sistema de arquivos raiz (rootfs). Essa configuração é obrigatória para dispositivos lançados com o Android 9, mas é opcional para dispositivos que fazem upgrade para o Android 9 e para dispositivos com versões anteriores do Android. Em uma configuração do sistema como raiz do Android 10, o build sempre mescla $TARGET_SYSTEM_OUT e $TARGET_ROOT_OUT em system.img. Essa configuração é o comportamento padrão para todos os dispositivos com Android 10.

O Android 10 faz outras mudanças para oferecer suporte a partições dinâmicas, um sistema de particionamento no espaço do usuário que permite que atualizações over-the-air (OTA) criem, redimensionem ou destruam partições. Como parte dessa mudança, o kernel do Linux não pode mais montar a partição lógica do sistema em dispositivos com o Android 10. Portanto, essa operação é processada pela inicialização da primeira etapa.

As seções a seguir descrevem os requisitos do sistema como raiz para OTAs somente do sistema e fornecem orientações sobre como atualizar dispositivos para usar o sistema como raiz (incluindo mudanças no layout da partição e requisitos do kernel dm-verity). Para detalhes sobre mudanças no ramdisk, consulte Partições de ramdisk.

Sobre OTAs somente do sistema

As OTAs somente do sistema, que permitem que as versões do Android atualizem system.img e product.img sem mudar outras partições, exigem um layout de partição de sistema como raiz. Todos os dispositivos com Android 10 precisam usar um layout de partição de sistema como raiz para ativar as OTAs somente do sistema.

  • Dispositivos A/B, que montam a partição system como rootfs, já usam o sistema como raiz e não exigem mudanças para oferecer suporte a OTAs do sistema.
  • Os dispositivos não A/B, que ativam a partição system em /system, precisam ser atualizados para usar um layout de partição de sistema como raiz para oferecer suporte a OTAs do sistema.

Para detalhes sobre dispositivos A/B e não A/B, consulte Atualizações do sistema A/B (ininterruptas).

Usar sobreposição do fornecedor (<=AOSP 14)

A sobreposição do fornecedor permite sobrepor mudanças na partição vendor durante a inicialização do dispositivo. Uma sobreposição do fornecedor é um conjunto de módulos do fornecedor na partição product que são sobrepostos à partição vendor quando o dispositivo é inicializado, substituindo e adicionando aos módulos existentes.

Quando o dispositivo é inicializado, o processo init conclui a primeira montagem de estágio e lê as propriedades padrão. Em seguida, ele pesquisa /product/vendor_overlay/<target_vendor_version> e monta cada subdiretório no diretório de partição vendor correspondente, se as seguintes condições forem atendidas:

  • /vendor/<overlay_dir> existe.
  • /product/vendor_overlay/<target_vendor_version>/<overlay_dir> tem o mesmo contexto de arquivo que /vendor/<overlay_dir>.
  • init tem permissão para montar no contexto de arquivo de /vendor/<overlay_dir>.

Implementar a sobreposição do fornecedor

Instale arquivos de sobreposição do fornecedor em /product/vendor_overlay/<target_vendor_version>. Esses arquivos substituem a partição vendor quando o dispositivo é inicializado, substituindo arquivos de mesmo nome e adicionando novos arquivos. A sobreposição do fornecedor não pode remover arquivos da partição vendor.

Os arquivos de sobreposição do fornecedor precisam ter o mesmo contexto dos arquivos de destino que eles substituem na partição vendor. Por padrão, os arquivos no diretório /product/vendor_overlay/<target_vendor_version> têm o contexto vendor_file. Se houver incompatibilidades de contexto de arquivo entre os arquivos de sobreposição do fornecedor e os arquivos que eles substituem, especifique isso na sepolicy específica do dispositivo. O contexto do arquivo é definido no nível do diretório. Se o contexto de arquivo de um diretório de sobreposição do fornecedor não corresponder ao diretório de destino e o contexto de arquivo correto não for especificado na sepolicy específica do dispositivo, esse diretório de sobreposição do fornecedor não será sobreposto ao diretório de destino.

Para usar a sobreposição do fornecedor, o kernel precisa ativar o OverlayFS definindo CONFIG_OVERLAY_FS=y. Além disso, o kernel precisa ser mesclado do kernel comum 4.4 ou mais recente ou corrigido com "overlayfs: override_creds=off option bypass creator_cred".

Exemplo de implementação de sobreposição de fornecedor

Este procedimento demonstra a implementação de uma sobreposição do fornecedor que sobrepõe os diretórios /vendor/lib/*, /vendor/etc/* e /vendor/app/*.

  1. Adicione arquivos de fornecedor pré-criados em device/<vendor>/<target>/vendor_overlay/<target_vendor_version>/:

    device/google/device/vendor_overlay/28/lib/libfoo.so
    device/google/device/vendor_overlay/28/lib/libbar.so
    device/google/device/vendor_overlay/28/etc/baz.xml
    device/google/device/vendor_overlay/28/app/qux.apk
  2. Instale os arquivos do fornecedor pré-criados em product/vendor_overlay em device/google/device/device.mk:

    PRODUCT_COPY_FILES += \
        $(call find-copy-subdir-files,*,device/google/device/vendor_overlay,$(TARGET_COPY_OUT_PRODUCT)/vendor_overlay)
  3. Defina contextos de arquivo se os arquivos de partição vendor de destino tiverem contextos diferentes de vendor_file. Como /vendor/lib/* usa o contexto vendor_file, este exemplo não inclui esse diretório.

    Adicione o seguinte a device/google/device-sepolicy/private/file_contexts:

    /(product|system/product)/vendor_overlay/[0-9]+/etc(/.*)?   u:object_r:vendor_configs_file:s0
    /(product|system/product)/vendor_overlay/[0-9]+/app(/.*)?   u:object_r:vendor_app_file:s0
  4. Permita que o processo init monte a sobreposição do fornecedor em contextos de arquivo diferentes de vendor_file. Como o processo init já tem permissão para montar no contexto vendor_file, este exemplo não define a política para vendor_file.

    Adicione o seguinte a device/google/device-sepolicy/public/init.te:

    allow init vendor_configs_file:dir mounton;
    allow init vendor_app_file:dir mounton;

Validar a sobreposição do fornecedor

Para validar a configuração de substituição do fornecedor, adicione arquivos em /product/vendor_overlay/<target_vendor_version>/<overlay_dir> e verifique se eles foram substituídos pelos arquivos em /vendor/<overlay_dir>.

Para builds do userdebug, há um módulo de teste para o Atest:

$ atest -v fs_mgr_vendor_overlay_test

Atualizar para sistema como raiz

Para atualizar dispositivos não A/B para usar o sistema como raiz, é necessário atualizar o esquema de particionamento para boot.img e system.img, configurar o dm-verity e remover todas as dependências de inicialização nas pastas raiz específicas do dispositivo.

Atualizar partições

Ao contrário dos dispositivos A/B, que reutilizam /boot como a partição de recuperação, os dispositivos não A/B precisam manter a partição /recovery separada, já que não têm a partição de slot de fallback (por exemplo, de boot_a para boot_b). Se /recovery for removida em um dispositivo não A/B e ficar semelhante ao esquema A/B, o modo de recuperação poderá ser interrompido durante uma atualização com falha na partição /boot. Por esse motivo, a partição /recovery precisa ser separada de /boot em dispositivos não A/B, o que implica que a imagem de recuperação continua sendo atualizada de maneira adiada (ou seja, da mesma forma que em dispositivos com o Android 8.1.0 ou versões anteriores).

A tabela a seguir lista as diferenças de partição de imagem para dispositivos não A/B antes e depois do Android 9.

Imagem Ramdisk (antes do Android 9) Sistema como raiz (após o Android 9)
boot.img Contém um kernel e um ramdisk.img:
ramdisk.img
  -/
    - init.rc
    - init
    - etc -> /system/etc
    - system/ (mount point)
    - vendor/ (mount point)
    - odm/ (mount point)
    ...
Contém apenas um kernel de inicialização normal.
recovery.img Contém um kernel de recuperação e uma ramdisk.img de recuperação.
system.img Contém o seguinte:
system.img
  -/
    - bin/
    - etc
    - vendor -> /vendor
    - ...
Contém o conteúdo mesclado de system.img e ramdisk.img originais:
system.img
  -/
    - init.rc
    - init
    - etc -> /system/etc
    - system/
      - bin/
      - etc/
      - vendor -> /vendor
      - ...
    - vendor/ (mount point)
    - odm/ (mount point)
    ...

As partições não mudam. Tanto o ramdisk quanto o sistema como raiz usam o seguinte esquema de partição:

  • /boot
  • /system
  • /system
  • /recovery
  • /vendor etc.

Configurar o dm-verity

No sistema como raiz, o kernel precisa montar system.img em / (ponto de montagem) com dm-verity. O AOSP é compatível com as seguintes implementações de dm-verity para system.img.

vboot 1.0

Para o vboot 1.0, o kernel precisa analisar os metadados específicos do Android em /system e converter para parâmetros dm-verity para configurar o dm-verity (requer estes patches do kernel). O exemplo a seguir mostra as configurações relacionadas ao dm-verity para system-as-root na linha de comando do kernel:

ro root=/dev/dm-0 rootwait skip_initramfs init=/init
dm="system none ro,0 1 android-verity /dev/sda34"
veritykeyid=id:7e4333f9bba00adfe0ede979e28ed1920492b40f

vboot 2.0

Para o vboot 2.0 (AVB), o carregador de inicialização precisa integrar external/avb/libavb, que analisa o descritor de árvore de hash para /system, converte em parâmetros dm-verity e, por fim, transmite os parâmetros para o kernel pela linha de comando do kernel. (Os descritores de hashtree de /system podem estar em /vbmeta ou no próprio /system.)

O vboot 2.0 requer os seguintes patches do kernel:

O exemplo a seguir mostra as configurações relacionadas ao dm-verity para system-as-root na linha de comando do kernel:

ro root=/dev/dm-0 rootwait  skip_initramfs init=/init

dm="1 vroot none ro 1,0 5159992 verity 1
PARTUUID=00000016-0000-0000-0000-000000000000
PARTUUID=00000016-0000-0000-0000-000000000000 4096 4096 644999 644999
sha1 d80b4a8be3b58a8ab86fad1b498640892d4843a2
8d08feed2f55c418fb63447fec0d32b1b107e42c 10 restart_on_corruption
ignore_zero_blocks use_fec_from_device
PARTUUID=00000016-0000-0000-0000-000000000000 fec_roots 2 fec_blocks
650080 fec_start 650080"

Usar pastas raiz específicas do dispositivo

Com o sistema como raiz, depois que a imagem genérica do sistema (GSI) é gravada no dispositivo (e antes de executar os testes do Vendor Test Suite), todas as pastas raiz específicas do dispositivo adicionadas com BOARD_ROOT_EXTRA_FOLDERS desaparecem porque todo o conteúdo do diretório raiz foi substituído pela GSI do sistema como raiz. A remoção dessas pastas pode fazer com que o dispositivo não possa ser inicializado se houver uma dependência das pastas raiz específicas do dispositivo (por exemplo, elas são usadas como pontos de montagem).

Para evitar esse problema, não use BOARD_ROOT_EXTRA_FOLDERS para adicionar pastas raiz específicas do dispositivo. Se você precisar especificar pontos de montagem específicos do dispositivo, use /mnt/vendor/<mount point> (adicionado nestas listas de mudanças). Esses pontos de montagem específicos do fornecedor podem ser especificados diretamente na árvore de dispositivos fstab (para montagem de primeira etapa) e no arquivo /vendor/etc/fstab.{ro.hardware} sem configuração adicional, já que o fs_mgr os cria automaticamente em /mnt/vendor/*.