동적 파티션이 없는 A/B 기기의 OTA

Android 10에서는 무선(OTA) 업데이트 중에 파티션을 만들고 크기를 조절하고 제거할 수 있는 사용자 공간 파티션 나누기 시스템인 동적 파티션을 지원합니다.

이 페이지에서는 동적 파티션 지원 없이 출시된 A/B 기기를 업데이트하는 동안 OTA 클라이언트에서 동적 파티션의 크기를 조절하는 방법과 OTA 클라이언트가 Android 10으로 업그레이드하는 방법을 설명합니다.

배경

동적 파티션 지원을 위해 A/B 기기를 업데이트하는 동안 기기의 GUID 파티션 테이블(GPT)이 보존되므로 기기에 super 파티션이 없습니다. 메타데이터는 system_asystem_b에 저장되지만 BOARD_SUPER_PARTITION_METADATA_DEVICE를 변경하여 맞춤설정할 수 있습니다.

각 블록 기기에는 두 개의 메타데이터 슬롯이 있으며, 각 블록 기기에서 메타데이터 슬롯 한 개만 사용됩니다. 예를 들어 system_a의 메타데이터 0과 system_b의 메타데이터 1은 각각 A 슬롯과 B 슬롯의 파티션에 상응합니다. 런타임 시에는 어떤 슬롯이 업데이트되고 있든 상관없습니다.

이 페이지에서는 메타데이터 슬롯을 메타데이터 S(소스)와 메타데이터 T(타겟)라고 부릅니다. 마찬가지로 파티션은 system_s, vendor_t 등으로 부릅니다.

빌드 시스템 구성에 관한 자세한 내용은 기기 업그레이드를 참고하세요.

파티션이 어떻게 업데이트 그룹에 속하는지에 관한 자세한 내용은 새 기기의 보드 구성 변경사항을 참고하세요.

기기의 메타데이터에 관한 예는 다음과 같습니다.

  • 실제 블록 기기 system_a
    • 메타데이터 0
      • 그룹 foo_a
        • 논리 (동적) 파티션 system_a
        • 논리 (동적) 파티션 product_services_a
        • Foo에 의해 업데이트된 다른 파티션
      • 그룹 bar_a
        • 논리 (동적) 파티션 vendor_a
        • 논리 (동적) 파티션 product_a
        • Bar에 의해 업데이트된 다른 파티션
    • 메타데이터 1(사용되지 않음)
  • 실제 블록 기기 system_b
    • 메타데이터 0(사용되지 않음)
    • 메타데이터 1
      • 그룹 foo_b
        • 논리 (동적) 파티션 system_b
        • 논리 (동적) 파티션 product_services_b
        • Foo에 의해 업데이트된 다른 파티션
      • 그룹 bar_b
        • 논리 (동적) 파티션 vendor_b
        • 논리 (동적) 파티션 product_b
        • Bar에 의해 업데이트된 다른 파티션

system/extras/partition_tools 아래의 lpdump 도구를 사용하여 기기의 메타데이터를 덤프할 수 있습니다. 예:

lpdump --slot 0 /dev/block/by-name/system_a
lpdump --slot 1 /dev/block/by-name/system_b

업데이트 재구성

Android 9 이하를 실행하는 기기에서 기기의 OTA 클라이언트는 업데이트 전에 동적 파티션 매핑을 지원하지 않습니다. 매핑을 기존의 실제 파티션에 직접 적용할 수 있도록 추가적인 패치 모음이 생성됩니다.

OTA 생성기는 모든 동적 파티션의 콘텐츠가 포함된 최종 super.img 파일을 빌드한 후 시스템, 공급업체 등에 상응하는 실제 블록 기기의 크기와 일치하는 여러 이미지로 이미지를 분할합니다. 이러한 이미지의 이름은 super_system.img, super_vendor.img 등으로 지정됩니다. OTA 클라이언트는 논리 (동적) 파티션의 이미지를 적용하는 대신 이러한 이미지를 실제 파티션에 적용합니다.

OTA 클라이언트는 동적 파티션을 어떻게 매핑하는지 모릅니다. 따라서 업데이트 패키지가 생성되면 모든 설치 후 단계가 이러한 파티션에서 자동으로 사용 중지됩니다. 자세한 내용은 설치 후 구성을 참고하세요.

업데이트 흐름은 Android 9와 동일합니다.

업데이트 전:

ro.boot.dynamic_partitions=
ro.boot.dynamic_partitions_retrofit=

업데이트 후:

ro.boot.dynamic_partitions=true
ro.boot.dynamic_partitions_retrofit=true

재구성 이후의 향후 업데이트

재구성 업데이트 이후에는 OTA 클라이언트가 동적 파티션과 함께 작동하도록 업데이트됩니다. 소스 파티션의 크기는 타겟 실제 파티션 전체를 포함하지 않습니다.

일반 업데이트 패키지를 사용한 업데이트 흐름

  1. super 파티션 메타데이터를 초기화합니다.
    1. 메타데이터 S(소스 메타데이터)에서 새 메타데이터 M을 구성합니다. 예를 들어 메타데이터 S가 [system_s, vendor_s, product_s]를 블록 기기로 사용한다면 새 메타데이터 M은 [system_t, vendor_t, product_t]를 블록 기기로 사용합니다. 모든 그룹 및 파티션은 M에서 삭제됩니다.
    2. 업데이트 매니페스트의 dynamic_partition_metadata 필드에 따라 타겟 그룹과 파티션을 추가합니다. 각 파티션의 크기는 new_partition_info에서 확인할 수 있습니다.
    3. M을 메타데이터 T에 씁니다.
    4. 추가된 파티션을 기기 매퍼에 작성 가능으로 매핑합니다.
  2. 업데이트를 블록 기기에 적용합니다.
    1. 필요한 경우 기기 매퍼의 소스 파티션을 읽기-전용으로 매핑합니다. 이는 소스 파티션이 업데이트 전에 매핑되지 않았으므로 사이드로드에 필요합니다.
    2. 전체 또는 델타 업데이트를 타겟 슬롯의 모든 블록 기기에 적용합니다.
    3. 파티션을 마운트하여 설치 후 스크립트를 실행한 다음 파티션을 마운트 해제합니다.
  3. 타겟 파티션을 매핑 해제합니다.

재구성 업데이트 패키지를 사용한 업데이트 흐름

재구성 업데이트 패키지가 동적 파티션을 이미 사용 설정한 기기에 적용되는 경우 OTA 클라이언트는 분할 super.img 파일을 블록 기기에 직접 적용합니다. 업데이트 흐름은 재구성 업데이트와 유사합니다. 자세한 내용은 업데이트 재구성을 참고하세요.

예를 들어 다음을 가정해 보세요.

  • 슬롯 A는 활성 슬롯입니다.
  • system_a에는 슬롯 0에 활성 메타데이터가 포함되어 있습니다.
  • system_a, vendor_a, product_a는 블록 기기로 사용됩니다.

OTA 클라이언트가 재구성 업데이트 패키지를 수신하면 실제 system_bsuper_system.img, 실제 vendor_bsuper_vendor.img, 실제 product_bsuper_product.img가 적용됩니다. 실제 블록 기기 system_b에는 부팅 시 논리 system_b, vendor_b, product_b를 매핑하기 위한 올바른 메타데이터가 포함되어 있습니다.

업데이트 패키지 생성

증분 OTA

재구성 기기의 증분 OTA를 생성하는 경우 기본 빌드에서 PRODUCT_USE_DYNAMIC_PARTITIONSPRODUCT_RETROFIT_DYNAMIC_PARTITIONS를 정의하는지 여부에 따라 업데이트가 결정됩니다.

  • 기본 빌드가 변수를 정의하지 않는 경우 이는 재구성 업데이트입니다. 업데이트 패키지는 분할 super.img 파일을 포함하고 설치 후 단계를 사용 중지합니다.
  • 기본 빌드가 변수를 정의하는 경우 이는 동적 파티션을 이용한 일반적인 업데이트와 동일합니다. 업데이트 패키지에는 논리 (동적) 파티션의 이미지가 포함됩니다. 설치 후 단계를 사용 설정할 수 있습니다.

전체 OTA

재구성 기기에 2개의 전체 OTA 패키지가 생성됩니다.

  • $(PRODUCT)-ota-retrofit-$(TAG).zip은 항상 분할 super.img를 포함하고 업데이트 재구성을 위한 설치 후 단계를 사용 중지합니다.
    • ota_from_target_files 스크립트의 추가 인수 --retrofit_dynamic_partitions로 생성됩니다.
    • 모든 빌드에 적용할 수 있습니다.
  • $(PRODUCT)-ota-$(TAG).zip에는 향후 업데이트를 위한 논리 이미지가 포함되어 있습니다.
    • 동적 파티션이 사용 설정된 빌드에만 적용하세요. 적용에 관한 내용은 아래 세부정보를 참고하세요.

기존 빌드의 재구성 외 업데이트 거부

동적 파티션이 사용 설정된 빌드에만 일반 전체 OTA 패키지를 적용합니다. OTA 서버가 잘못 구성되었거나 Android 9 이하를 실행 중인 기기에 이러한 패키지를 푸시하면 기기가 부팅되지 않습니다. Android 9 이하의 OTA 클라이언트는 재구성 OTA 패키지와 일반 전체 OTA 패키지의 차이점을 알지 못합니다. 따라서 클라이언트에서 전체 패키지를 거부하지 않습니다.

기기가 전체 OTA 패키지를 수락하지 않도록 하려면 설치 후 단계를 요구하여 기존 기기 설정을 확인하세요. 예:

device/device_name/dynamic_partitions/check_dynamic_partitions

#!/system/bin/sh
DP_PROPERTY_NAME="ro.boot.dynamic_partitions"
DP_RETROFIT_PROPERTY_NAME="ro.boot.dynamic_partitions_retrofit"

DP_PROPERTY=$(getprop ${DP_PROPERTY_NAME})
DP_RETROFIT_PROPERTY=$(getprop ${DP_RETROFIT_PROPERTY_NAME})

if [ "${DP_PROPERTY}" != "true" ] || [ "${DP_RETROFIT_PROPERTY}" != "true" ] ; then
    echo "Error: applied non-retrofit update on build without dynamic" \
         "partitions."
    echo "${DP_PROPERTY_NAME}=${DP_PROPERTY}"
    echo "${DP_RETROFIT_PROPERTY_NAME}=${DP_RETROFIT_PROPERTY}"
    exit 1
fi

device/device_name/dynamic_partitions/Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE:= check_dynamic_partitions
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_SRC_FILES := check_dynamic_partitions
LOCAL_PRODUCT_MODULE := true
include $(BUILD_PREBUILT)

device/device_name/device.mk

PRODUCT_PACKAGES += check_dynamic_partitions

# OPTIONAL=false so that the error in check_dynamic_partitions will be
# propagated to OTA client.
AB_OTA_POSTINSTALL_CONFIG += \
    RUN_POSTINSTALL_product=true \
    POSTINSTALL_PATH_product=bin/check_dynamic_partitions \
    FILESYSTEM_TYPE_product=ext4 \
    POSTINSTALL_OPTIONAL_product=false \

일반 OTA 패키지가 동적 파티션이 사용 설정되지 않은 기기에 적용되면 OTA 클라이언트는 check_dynamic_partitions를 설치 후 단계로 실행하고 업데이트를 거부합니다.