가상 A/B 구현

새 기기에서 가상 A/B를 구현하거나 출시된 기기를 개조하려면 기기별 코드를 변경해야 합니다.

빌드 플래그

가상 A/B를 사용하는 장치 는 A/B 장치로 구성 해야 하며 동적 파티션으로 시작 해야 합니다.

가상 A/B로 시작하는 장치의 경우 가상 A/B 장치 기본 구성을 상속하도록 설정합니다.

$(call inherit-product, \
    $(SRC_TARGET_DIR)/product/virtual_ab_ota.mk)

가상 A/B로 시작하는 기기는 B 슬롯이 더 이상 슈퍼에 없기 때문에 BOARD_SUPER_PARTITION_SIZE 에 대해 절반의 보드 크기만 필요합니다. 즉, BOARD_SUPER_PARTITION_SIZEsum(업데이트 그룹의 크기) + 오버헤드 보다 크거나 같아야 하며, 이는 다시 sum(파티션 크기) + 오버헤드 보다 크거나 같아야 합니다.

Virtual A/B로 압축된 스냅샷을 활성화하려면 대신 다음 기본 구성을 상속하십시오.

$(call inherit-product, \
    $(SRC_TARGET_DIR)/product/virtual_ab_ota/compression.mk)

부팅 제어 HAL

부팅 제어 HAL 은 OTA 클라이언트가 부팅 슬롯을 제어할 수 있는 인터페이스를 제공합니다. 가상 A/B는 부팅 제어 HAL의 마이너 버전 업그레이드가 필요합니다. 플래싱/공장 초기화 중에 부트로더를 보호하려면 추가 API가 필요하기 때문입니다. HAL 정의의 최신 버전은 IBootControl.haltypes.hal 을 참조하십시오.

// hardware/interfaces/boot/1.1/types.hal
enum MergeStatus : uint8_t {
    NONE, UNKNOWN, SNAPSHOTTED, MERGING, CANCELLED };

// hardware/interfaces/boot/1.1/IBootControl.hal
package android.hardware.boot@1.1;
interface IBootControl extends @1.0::IBootControl {
    setSnapshotMergeStatus(MergeStatus status)
        generates (bool success);
    getSnapshotMergeStatus()
        generates (MergeStatus status);
}
// Recommended implementation

Return<bool> BootControl::setSnapshotMergeStatus(MergeStatus v) {
    // Write value to persistent storage
    // e.g. misc partition (using libbootloader_message)
    // bootloader rejects wipe when status is SNAPSHOTTED
    // or MERGING
}

Fstab 변경 사항

메타데이터 파티션의 무결성은 특히 OTA 업데이트가 적용된 직후 부팅 프로세스에 필수적입니다. 따라서 first_stage_init 가 마운트하기 전에 메타데이터 파티션을 확인해야 합니다. 이를 확인하려면 /metadata 항목에 check fs_mgr 플래그를 추가하십시오. 다음은 예를 제공합니다.

/dev/block/by-name/metadata /metadata ext4 noatime,nosuid,nodev,discard,sync wait,formattable,first_stage_mount,check

커널 요구 사항

스냅샷을 활성화하려면 CONFIG_DM_SNAPSHOTtrue 로 설정하십시오.

F2FS를 사용하는 장치의 경우 f2fs: export FS_NOCOW_FL 플래그를 사용자 커널 패치에 포함하여 파일 고정을 수정합니다. f2fs 포함: 정렬된 고정 파일 커널 패치도 지원 합니다.

가상 A/B는 커널 버전 4.3에 추가된 기능( snapshotsnapshot-merge 대상의 오버플 로 상태 비트)에 의존합니다. Android 9 이상으로 실행되는 모든 기기에는 이미 커널 버전 4.4 이상이 있어야 합니다.

압축된 스냅샷을 활성화하기 위해 지원되는 최소 커널 버전은 4.19입니다. CONFIG_DM_USER=m 또는 CONFIG_DM_USER=y 로 설정하십시오. 전자(모듈)를 사용하는 경우 모듈을 1단계 램디스크에 로드해야 합니다. 장치 Makefile에 다음 줄을 추가하면 됩니다.

BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD := dm-user.ko

Android 11로 업그레이드하는 기기의 개조

Android 11로 업그레이드할 때 동적 파티션으로 시작된 기기는 선택적으로 가상 A/B를 개조할 수 있습니다. 업데이트 프로세스는 몇 가지 사소한 차이점을 제외하고 가상 A/B로 시작하는 기기와 거의 동일합니다.

  • COW 파일 위치 — 시작 장치의 경우 OTA 클라이언트는 /data 의 공간을 사용하기 전에 슈퍼 파티션에서 사용 가능한 모든 빈 공간을 사용합니다. 개조 장치의 경우 슈퍼 파티션에 항상 충분한 공간이 있으므로 COW 파일이 /data 에 생성되지 않습니다.

  • 빌드 타임 기능 플래그 — 가상 A/B를 개조하는 장치의 경우 아래와 같이 PRODUCT_VIRTUAL_AB_OTAPRODUCT_VIRTUAL_AB_OTA_RETROFIT 모두 true 로 설정됩니다.

    (call inherit-product, \
        (SRC_TARGET_DIR)/product/virtual_ab_ota_retrofit.mk)
    
  • 슈퍼 파티션 크기 — 가상 A/B로 시작하는 기기는 B 슬롯이 슈퍼 파티션에 없기 때문에 BOARD_SUPER_PARTITION_SIZE 를 절반으로 줄일 수 있습니다. 가상 A/B를 개조하는 장치는 이전 슈퍼 파티션 크기를 유지하므로 BOARD_SUPER_PARTITION_SIZE2 * sum(업데이트 그룹 크기) + 오버헤드 보다 크거나 같으며, 이는 차례로 2 * sum(파티션 크기) 보다 크거나 같습니다. + 오버 헤드 .

부트로더 변경 사항

업데이트 병합 단계에서 /data 는 Android OS의 유일한 전체 인스턴스를 보유합니다. 마이그레이션이 시작되면 기본 system , vendorproduct 파티션은 복사가 완료될 때까지 불완전합니다. 복구 또는 시스템 설정 대화 상자를 통해 이 프로세스 동안 장치를 공장 초기화하면 장치를 부팅할 수 없습니다.

/data 를 지우기 전에 장치 상태에 따라 복구 또는 롤백에서 병합을 완료하십시오.

  • 새 빌드가 이전에 성공적으로 부팅된 경우 마이그레이션을 완료합니다.
  • 그렇지 않으면 이전 슬롯으로 롤백합니다.
    • 동적 파티션의 경우 이전 상태로 롤백합니다.
    • 정적 파티션의 경우 활성 슬롯을 이전 슬롯으로 설정합니다.

장치가 잠금 해제된 경우 부트로더와 fastbootd 모두 /data 파티션을 지울 수 있습니다. fastbootd 는 마이그레이션을 강제로 완료할 수 있지만 부트로더는 그렇게 할 수 없습니다. 부트로더는 병합이 진행 중인지 여부 또는 /data 의 어떤 블록이 OS 파티션을 구성하는지 알지 못합니다. 장치는 다음을 수행하여 사용자가 무의식적으로 장치를 작동 불능 상태로 만드는 것을 방지해야 합니다.

  1. 부트로더가 setSnapshotMergeStatus() 메소드에서 설정한 값을 읽을 수 있도록 부트 제어 HAL을 구현합니다.
  2. 병합 상태가 MERGING 이거나 병합 상태가 SNAPSHOTTED 이고 슬롯이 새로 업데이트된 슬롯으로 변경된 경우 userdata , metadata 또는 병합 상태를 저장하는 파티션 지우기 요청은 부트로더에서 거부되어야 합니다.
  3. 사용자가 이 보호 메커니즘을 우회하고 싶다는 신호를 부트로더에 보낼 수 있도록 fastboot snapshot-update cancel 명령을 구현합니다.
  4. 전체 장치를 플래싱할 때 fastboot snapshot-update cancel 하도록 사용자 정의 플래싱 도구 또는 스크립트를 수정합니다. 전체 장치를 플래싱하면 OTA가 제거되므로 문제가 안전합니다. 도구는 fastboot getvar snapshot-update-status 를 구현하여 런타임에 이 명령을 감지할 수 있습니다. 이 명령은 오류 조건을 구별하는 데 도움이 됩니다.

예시

struct VirtualAbState {
    uint8_t StructVersion;
    uint8_t MergeStatus;
    uint8_t SourceSlot;
};

bool ShouldPreventUserdataWipe() {
    VirtualAbState state;
    if (!ReadVirtualAbState(&state)) ...
    return state.MergeStatus == MergeStatus::MERGING ||
           (state.MergeStatus == MergeStatus::SNAPSHOTTED &&
            state.SourceSlot != CurrentSlot()));
}

Fastboot 도구 변경

Android 11은 fastboot 프로토콜을 다음과 같이 변경합니다.

  • getvar snapshot-update-status — 부트 제어 HAL이 부트로더에 전달한 값을 반환합니다.
    • 상태가 MERGING 이면 부트로더는 merging 을 반환해야 합니다.
    • 상태가 SNAPSHOTTED 이면 부트로더는 snapshotted 을 반환해야 합니다.
    • 그렇지 않으면 부트로더가 none 을 반환해야 합니다.
  • snapshot-update merge — 병합 작업을 완료하고 필요한 경우 복구/빠른 부팅으로 부팅합니다. 이 명령은 snapshot-update-statusmerging 중인 경우에만 유효하며 fastbootd에서만 지원됩니다.
  • snapshot-update cancel — 부팅 제어 HAL의 병합 상태를 CANCELLED 로 설정합니다. 이 명령은 장치가 잠겨 있을 때 유효하지 않습니다.
  • erase 또는 wipemetadata , userdata 또는 부팅 제어 HAL에 대한 병합 상태를 유지하는 파티션의 erase 또는 wipe 는 스냅샷 병합 상태를 확인해야 합니다. 상태가 MERGING 또는 SNAPSHOTTED 인 경우 장치는 작업을 중단해야 합니다.
  • set_active — 활성 슬롯을 변경하는 set_active 명령은 스냅샷 병합 상태를 확인해야 합니다. 상태가 MERGING 이면 장치는 작업을 중단해야 합니다. 슬롯은 SNAPSHOTTED 상태에서 안전하게 변경할 수 있습니다.

이러한 변경은 실수로 장치를 부팅할 수 없게 만드는 것을 방지하도록 설계되었지만 자동화된 도구에 지장을 줄 수 있습니다. fastboot flashall 실행과 같이 명령이 모든 파티션을 플래싱하는 구성 요소로 사용되는 경우 다음 흐름을 사용하는 것이 좋습니다.

  1. 쿼리 getvar snapshot-update-status .
  2. merging 또는 snapshotted 이 생성된 경우 snapshot-update cancel 를 실행합니다.
  3. 깜박이는 단계를 진행합니다.

스토리지 요구 사항 감소

super에 전체 A/B 저장소가 할당되지 않고 필요에 따라 /data 를 사용할 것으로 예상되는 장치는 블록 매핑 도구를 사용하는 것이 좋습니다. 블록 매핑 도구는 빌드 간에 블록 할당을 일관되게 유지하여 스냅샷에 대한 불필요한 쓰기를 줄입니다. 이것은 OTA 크기 줄이기 에 설명되어 있습니다.