OTA para dispositivos não A/B com partições dinâmicas

O Android 10 oferece suporte a partições dinâmicas, um sistema de particionamento no espaço do usuário que pode criar, redimensionar e destruir partições durante atualizações OTA.

Esta página descreve como os clientes OTA redimensionam partições dinâmicas durante uma atualização para dispositivos não A/B.

Para dispositivos não A/B, a atualização OTA para partições dinâmicas é aplicada usando o updater dentro do pacote de atualização.

Atualizar dispositivos de inicialização

Esta seção se aplica a dispositivos não A/B iniciados com suporte a partições; Esses dispositivos foram atualizados do Android de 10 a versões mais recentes.

Gerar pacotes de atualização

Os pacotes de atualização OTA são gerados ota_from_target_files script, localizado em build/make/tools/releasetools. Por padrão, o script gera um pacote que atualiza o system e vendor partições. Se houver grupos dinâmicos adicionais partições diferentes, como product, product_services ou odm, o as atualizações precisam ser geradas específicos do dispositivo código.

Para gerar atualizações, no módulo estendido do Python, implemente FullOTA_GetBlockDifferences() e IncrementalOTA_GetBlockDifferences(). Essas duas funções retornam uma lista de objetos BlockDifference, cada uma descrevendo o patch de atualização que seria aplicado em uma partição. As partições retornadas por essas duas funções não podem ser modificadas manualmente ou verificadas em outro lugar, por exemplo, em *_InstallBegin() ou *_InstallEnd().

Exemplo de uma geração de atualização:

# device/yoyodyne/tardis/releasetools.py

import os
from common import BlockDifference, EmptyImage, GetUserImage

# The joined list of user image partitions of source and target builds.
# - Items should be added to the list if new dynamic partitions are added.
# - Items should not be removed from the list even if dynamic partitions are
#   deleted. When generating an incremental OTA package, this script needs to
#   know that an image is present in source build but not in target build.
USERIMAGE_PARTITIONS = [
    "product",
    "odm",
]

def GetUserImages(input_tmp, input_zip):
  return {partition: GetUserImage(partition, input_tmp, input_zip)
          for partition in USERIMAGE_PARTITIONS
          if os.path.exists(os.path.join(input_tmp,
                                         "IMAGES", partition + ".img"))}

def FullOTA_GetBlockDifferences(info):
  images = GetUserImages(info.input_tmp, info.input_zip)
  return [BlockDifference(partition, image)
          for partition, image in images.items()]

def IncrementalOTA_GetBlockDifferences(info):
  source_images = GetUserImages(info.source_tmp, info.source_zip)
  target_images = GetUserImages(info.target_tmp, info.target_zip)

  # Use EmptyImage() as a placeholder for partitions that will be deleted.
  for partition in source_images:
    target_images.setdefault(partition, EmptyImage())

  # Use source_images.get() because new partitions are not in source_images.
  return [BlockDifference(partition, target_image, source_images.get(partition))
          for partition, target_image in target_images.items()]

Atualizar fluxo

Nos bastidores, as seguintes funções são adicionadas ao script edify:

  • unmap_partition(name)
    • Desmapeia a partição se ela estiver mapeada. Caso contrário, nada será feito.
    • Retorne a string t em caso de sucesso ou um valor em caso de falha.
  • map_partition(name)
    • Mapeie a partição, se ainda não estiver mapeada.
    • Retorna o caminho absoluto do dispositivo de bloco mapeado em caso de êxito. ou uma string vazia em caso de falha.
  • update_dynamic_partitions(op_list)
    • Aplica a lista de operações fornecida aos metadados da partição dinâmica. e desmapear partições, se necessário.
    • Retorne t em caso de sucesso ou uma string vazia em caso de falha.

O argumento op_list para update_dynamic_partitions aponta para um arquivo no update. Cada linha no arquivo especifica uma operação. Se houver falha na operação, update_dynamic_partitions imediatamente retorna uma string vazia. As operações são:

  • resize partition-name size
    • Remova o mapeamento da partição e redimensione-a para size.
  • remove partition_name
    • Desfaça o mapeamento da partição e a remova.
  • add partition-name group-name
    • Adicione uma nova partição ao grupo especificado.
    • Aborta se o grupo não existir ou se a partição já existir.
  • move partition-name group-name
    • Mova a partição para o grupo especificado.
    • Aborta se o grupo ou a partição não existir.
  • add_group group-name maximum-size
    • Adiciona um grupo com o nome e o tamanho máximo fornecidos.
    • Aborta se o grupo já existir.
    • Um maximum_size de 0 significa que não há limites de tamanho nas partições do grupo. Outros testes são necessários para garantir que as partições no grupo não excedam o espaço disponível no dispositivo.
  • resize_group group-name maximum-size
    • Redimensione o grupo para o tamanho máximo fornecido.
    • Aborta se o grupo não existir.
    • Um maximum_size de 0 significa que não há limites de tamanho nas partições do grupo. Outros testes são necessários para garantir que as partições no grupo não excedam o espaço disponível no dispositivo.
  • remove_group group-name
    • Remover um grupo.
    • Aborta se houver partições no grupo.
  • remove_all_groups
    • Desmapear todas as partições do mapeador de dispositivos.
    • Remova todas as partições e grupos.

OTA incremental

As atualizações OTA incrementais usam a seguinte lógica:

  1. Reduzir partições/excluir partições/mover partições para fora do grupo (para que haja espaço suficiente para reduzir grupos)
  2. Reduzir grupos (para que haja espaço suficiente para aumentar os grupos)
  3. Aumente os grupos (para que tenhamos espaço suficiente para crescer/agregar partições)
  4. Ampliar/adicionar/mover partições para um novo grupo

Em detalhes, a update-script é gerada com esta lógica:

for each shrinking partition:
    block_image_update(map_partition(name), …)

update_dynamic_partitions(op_list)

for each growing / adding partition:
    block_image_update(map_partition(name), …)

O arquivo op_list de update_dynamic_partitions é gerado com isto lógica:

for each deleting partition:
    remove
for each partition that changes groups:
    move to "default"
for each shrinking partition:
    resize
for each shrinking / removing group:
    resize_group / remove_group
for each growing / adding group:
    resize_group / add_group
for each adding partition:
    add
for each growing / adding partition:
    resize
for each partition that changes groups:
    move to target group

OTA completo

As atualizações OTA completas usam a seguinte lógica:

  1. Excluir todos os grupos e partições existentes
  2. Adicionar grupos
  3. Adicionar partições

Em detalhes, update-script é gerado com esta lógica:

update_dynamic_partitions(op_list)

for each adding partition:
    block_image_update(map_partition(name), …)

O arquivo op_list de update_dynamic_partitions é gerado com isto lógica:

remove_all_groups
for each adding group:
    add_group
for each adding partition:
    add
for each adding partition:
    resize