Layout de partição

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

  • Use um layout de partição do sistema como raiz (aplicado automaticamente pela compilação, sem opções para alterar o comportamento).
  • Deve usar um ramdisk, que é necessário para dm-linear.
  • Deve definir BOARD_BUILD_SYSTEM_ROOT_IMAGE como false . Esta configuração é usada apenas para diferenciar entre dispositivos que usam um ramdisk e dispositivos que não usam um ramdisk (e, em vez disso, montar system.img diretamente).

O significado de uma configuração de sistema como raiz difere entre o Android 9 e o Android 10. Em uma configuração de sistema como raiz do Android 9, BOARD_BUILD_SYSTEM_ROOT_IMAGE é definido como true , o que força a compilação a mesclar o sistema de arquivos raiz em system.img e então monte system.img como o sistema de arquivos raiz (rootfs). Esta configuração é obrigatória para dispositivos lançados com Android 9, mas é opcional para dispositivos atualizados para Android 9 e para dispositivos que executam versões anteriores do Android. Em uma configuração de sistema como raiz do Android 10, a compilação sempre mescla $TARGET_SYSTEM_OUT e $TARGET_ROOT_OUT em system.img ; esta configuração é o comportamento padrão para todos os dispositivos que executam o Android 10.

O Android 10 faz mais alterações para oferecer suporte a partições dinâmicas , um sistema de particionamento de espaço do usuário que permite atualizações over-the-air (OTA) para criar, redimensionar ou destruir 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 que executam o Android 10, portanto, essa operação é realizada pelo primeiro estágio init.

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

Sobre OTAs somente de sistema

OTAs somente de sistema, que permitem que versões do Android atualizem system.img e product.img sem alterar outras partições, exigem um layout de partição do sistema como raiz. Todos os dispositivos que executam o Android 10 devem usar um layout de partição do sistema como raiz para habilitar OTAs somente do sistema.

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

Usando sobreposição de fornecedor

A sobreposição do fornecedor permite sobrepor alterações na partição vendor no momento da inicialização do dispositivo. Uma sobreposição de fornecedor é um conjunto de módulos de fornecedor na partição product que são sobrepostos na partição vendor quando o dispositivo é inicializado, substituindo e adicionando aos módulos existentes.

Quando o dispositivo é inicializado, o processo init conclui o primeiro estágio de montagem e lê as propriedades padrão. Em seguida, ele pesquisa /product/vendor_overlay/<target_vendor_version> e monta cada subdiretório em seu 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 pode ser montado no contexto do arquivo de /vendor/<overlay_dir> .

Implementando sobreposição de fornecedor

Instale arquivos de sobreposição do fornecedor em /product/vendor_overlay/<target_vendor_version> . Esses arquivos se sobrepõem à partição vendor quando o dispositivo é inicializado, substituindo arquivos com o 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 devem ter o mesmo contexto de arquivo que os arquivos de destino que eles substituem na partição vendor . Por padrão, os arquivos no diretório /product/vendor_overlay/<target_vendor_version> possuem 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 política 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 de 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 de fornecedor não será sobreposto ao diretório de destino.

Para usar a sobreposição do fornecedor, o kernel deve ativar o OverlayFS configurando CONFIG_OVERLAY_FS=y . Além disso, o kernel deve ser mesclado do kernel comum 4.4 ou posterior, 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 de fornecedor que sobrepõe os diretórios /vendor/lib/* , /vendor/etc/* e /vendor/app/* .

  1. Adicione arquivos de fornecedor pré-construídos 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 pré-construídos do fornecedor 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;
    

Validando a sobreposição do fornecedor

Para validar a configuração de sobreposição do fornecedor, adicione arquivos em /product/vendor_overlay/<target_vendor_version>/<overlay_dir> e verifique se os arquivos estão sobrepostos aos arquivos em /vendor/<overlay_dir> .

Para compilações userdebug , existe um módulo de teste para Atest :

$ atest -v fs_mgr_vendor_overlay_test

Atualizando para o sistema como root

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

Atualizando partições

Ao contrário dos dispositivos A/B que reaproveitam /boot como partição de recuperação , os dispositivos não A/B devem manter a partição /recovery separada, pois não possuem a partição de slot de fallback (por exemplo, de boot_a para boot_b ). Se /recovery for removido em um dispositivo não A/B e tornado semelhante ao esquema A/B, o modo de recuperação poderá ser interrompido durante uma falha na atualização da partição /boot . Por esse motivo, a partição /recovery deve ser uma partição separada de /boot para dispositivos não-A/B, o que implica que a imagem de recuperação continuará a ser atualizada de maneira diferida (ou seja, da mesma forma que em dispositivos rodando Android). 8.1.0 ou inferior).

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 das 9) Sistema como root (após 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 um ramdisk.img de recuperação.
system.img Contém o seguinte:
system.img
  -/
    - bin/
    - etc
    - vendor -> /vendor
    - ...
Contém o conteúdo mesclado do 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 próprias partições não mudam; tanto o ramdisk quanto o sistema como root usam o seguinte esquema de partição:

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

Configurando dm-verity

No sistema como raiz, o kernel deve montar system.img em / (ponto de montagem) com dm-verity . AOSP suporta as seguintes implementações de dm-verity para system.img .

vboot 1.0

Para vboot 1.0 , o kernel deve analisar os metadados específicos do Android em /system e, em seguida, converter para parâmetros dm-verity para configurar o dm-verity (requer esses patches do kernel ). O exemplo a seguir mostra configurações relacionadas ao dm-verity para sistema como 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 vboot 2.0 ( AVB ), o bootloader deve integrar external/avb/libavb , que então analisa o descritor hashtree para /system , converte-o em dm-verity params e finalmente passa os parâmetros para o kernel através da linha de comando do kernel. (Os descritores Hashtree de /system podem estar em /vbmeta ou no próprio /system .)

O vboot 2.0 requer os seguintes patches de kernel:

O exemplo a seguir mostra configurações relacionadas ao dm-verity para sistema como 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"

Usando pastas raiz específicas do dispositivo

Com o sistema como raiz, depois que a imagem genérica do sistema (GSI) é atualizada 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 pelo GSI do sistema como raiz. A remoção dessas pastas pode fazer com que o dispositivo não seja inicializável se existir uma dependência nas 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 changelists ). Esses pontos de montagem específicos do fornecedor podem ser especificados diretamente na árvore de dispositivos fstab (para montagem de primeiro estágio) e no arquivo /vendor/etc/fstab.{ro.hardware} sem configuração adicional (já que fs_mgr os cria em /mnt/vendor/* automaticamente).