ใช้งาน 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 เสมือนต้องการขนาดบอร์ดเพียงครึ่งหนึ่งสำหรับ BOARD_SUPER_PARTITION_SIZE เนื่องจากสล็อต B ไม่ได้อยู่ในระดับซุปเปอร์อีกต่อไป นั่นคือ BOARD_SUPER_PARTITION_SIZE จะต้องมากกว่าหรือเท่ากับ sum(ขนาดของกลุ่มการอัปเดต) + overhead ซึ่งในทางกลับกันจะต้องมากกว่าหรือเท่ากับ sum(ขนาดของพาร์ติชัน) + overhead

สำหรับ Android 13 ขึ้นไป หากต้องการเปิดใช้สแนปชอตที่บีบอัดด้วย Virtual A/B ให้รับการกำหนดค่าพื้นฐานต่อไปนี้

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

ซึ่งช่วยให้สามารถถ่ายภาพสแนปชอตพื้นที่ผู้ใช้ด้วย Virtual A/B ในขณะที่ใช้วิธีการบีบอัดแบบ no-op จากนั้นคุณสามารถกำหนดค่าวิธีการบีบอัดเป็นหนึ่งในวิธีที่รองรับ ได้แก่ gz , zstd และ lz4

PRODUCT_VIRTUAL_AB_COMPRESSION_METHOD := lz4

สำหรับ Android 12 หากต้องการเปิดใช้สแนปช็อตที่บีบอัดด้วย Virtual A/B ให้สืบทอดการกำหนดค่าพื้นฐานต่อไปนี้:

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

การบีบอัดแฮคเกอร์

สำหรับอุปกรณ์ที่อัปเกรดเป็น Android 13 ขึ้นไป ฟีเจอร์การบีบอัด XOR จะไม่เปิดใช้ตามค่าเริ่มต้น หากต้องการเปิดใช้งานการบีบอัด XOR ให้เพิ่มสิ่งต่อไปนี้ลงในไฟล์ .mk ของอุปกรณ์

PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.compression.xor.enabled=true

การบีบอัด XOR ถูกเปิดใช้งานตามค่าเริ่มต้นสำหรับอุปกรณ์ที่สืบทอดมาจาก android_t_baseline.mk

ผสานพื้นที่ผู้ใช้

สำหรับอุปกรณ์ที่อัปเกรดเป็น Android 13 ขึ้นไป กระบวนการรวมพื้นที่ผู้ใช้ตามที่อธิบายไว้ใน การแบ่งเลเยอร์ตัวทำแผนที่อุปกรณ์ จะไม่เปิดใช้งานตามค่าเริ่มต้น หากต้องการเปิดใช้งานการรวมพื้นที่ผู้ใช้ ให้เพิ่มบรรทัดต่อไปนี้ลงในไฟล์ .mk ของอุปกรณ์:

PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.userspace.snapshots.enabled=true

การรวม Userspace จะเปิดใช้งานตามค่าเริ่มต้นในอุปกรณ์ที่เปิดตัวด้วยเวอร์ชัน 13 ขึ้นไป

ระบบควบคุมการบูต HAL

การควบคุมการบูต HAL จัดเตรียมอินเทอร์เฟซสำหรับไคลเอนต์ OTA เพื่อควบคุมสล็อตการบูต A/B เสมือนจำเป็นต้องมีการอัปเกรดเวอร์ชันรองของการควบคุมการบูต HAL เนื่องจากจำเป็นต้องมี API เพิ่มเติมเพื่อให้แน่ใจว่าโปรแกรมโหลดบูตได้รับการป้องกันในระหว่างการกะพริบ/รีเซ็ตเป็นค่าจากโรงงาน โปรดดู IBootControl.hal และ types.hal สำหรับเวอร์ชันล่าสุดของคำจำกัดความ 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 เพื่อให้แน่ใจว่าสิ่งนี้จะเกิดขึ้น ให้เพิ่มแฟล็ก check fs_mgr ไปยังรายการสำหรับ /metadata ต่อไปนี้เป็นตัวอย่าง:

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

ข้อกำหนดเคอร์เนล

หากต้องการเปิดใช้งานสแนปชอต ให้ตั้งค่า CONFIG_DM_SNAPSHOT เป็น true

สำหรับอุปกรณ์ที่ใช้ F2FS ให้รวม f2fs: ส่งออกแฟล็ก FS_NOCOW_FL ไปยังเคอร์เนลแพตช์ของผู้ใช้ เพื่อแก้ไขการปักหมุดไฟล์ รวม f2fs: รองรับแพตช์เคอร์เนลไฟล์ที่ปักหมุดไว้ ด้วยเช่นกัน

A/B เสมือนอาศัยคุณสมบัติที่เพิ่มในเคอร์เนลเวอร์ชัน 4.3: บิตสถานะ โอเวอร์โฟลว์ ใน snapshot และเป้าหมาย snapshot-merge อุปกรณ์ทั้งหมดที่เปิดตัวด้วย Android 9 และใหม่กว่าควรมีเคอร์เนลเวอร์ชัน 4.4 หรือใหม่กว่าอยู่แล้ว

หากต้องการเปิดใช้งานสแน็ปช็อตที่บีบอัด เวอร์ชันเคอร์เนลขั้นต่ำที่รองรับคือ 4.19 ตั้งค่า CONFIG_DM_USER=m หรือ CONFIG_DM_USER=y หากใช้โมดูลเดิม (โมดูล) จะต้องโหลดโมดูลใน ramdisk ขั้นแรก ซึ่งสามารถทำได้โดยเพิ่มบรรทัดต่อไปนี้ลงในอุปกรณ์ 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_OTA และ PRODUCT_VIRTUAL_AB_OTA_RETROFIT จะถูกตั้งค่าเป็น true ดังที่แสดงด้านล่าง:

    (call inherit-product, \
        (SRC_TARGET_DIR)/product/virtual_ab_ota_retrofit.mk)
    
  • ขนาดพาร์ติชั่นพิเศษ — อุปกรณ์ที่เปิดใช้งานด้วย A/B เสมือนสามารถลด BOARD_SUPER_PARTITION_SIZE ลงครึ่งหนึ่งได้ เนื่องจากสล็อต B ไม่ได้อยู่ในพาร์ติชั่นพิเศษ อุปกรณ์ที่ดัดแปลง A/B เสมือนใหม่จะรักษาขนาดพาร์ติชั่นซุปเปอร์เก่าไว้ ดังนั้น BOARD_SUPER_PARTITION_SIZE จึงมากกว่าหรือเท่ากับ 2 * sum(size of update groups) + overhead ซึ่งจะมากกว่าหรือเท่ากับ 2 * sum(ขนาดของพาร์ติชั่น) + ค่าโสหุ้ย .

การเปลี่ยนแปลง Bootloader

ในระหว่างขั้นตอนการรวมการอัปเดต /data จะเก็บอินสแตนซ์ทั้งหมดของระบบปฏิบัติการ Android เท่านั้น เมื่อการย้ายเริ่มต้นขึ้น พาร์ติชัน system เนทิฟ vendor และพาร์ติชัน product จะไม่สมบูรณ์จนกว่าการคัดลอกจะเสร็จสิ้น หากอุปกรณ์ถูกรีเซ็ตเป็นค่าเริ่มต้นจากโรงงานในระหว่างกระบวนการนี้ ไม่ว่าจะโดยการกู้คืนหรือผ่านกล่องโต้ตอบการตั้งค่าระบบ อุปกรณ์จะไม่สามารถบูตได้

ก่อนที่จะลบ /data ให้เสร็จสิ้นการผสานในการกู้คืนหรือย้อนกลับ ขึ้นอยู่กับสถานะของอุปกรณ์:

  • หากบิลด์ใหม่บูตได้สำเร็จก่อนหน้านี้ ให้ทำการโยกย้ายให้เสร็จสิ้น
  • มิฉะนั้น ให้ย้อนกลับไปยังช่องเก่า:
    • สำหรับพาร์ติชันแบบไดนามิก ให้ย้อนกลับไปสู่สถานะก่อนหน้า
    • สำหรับพาร์ติชันแบบสแตติก ให้ตั้งค่าสล็อตที่ใช้งานอยู่เป็นสล็อตเก่า

ทั้ง bootloader และ fastbootd สามารถลบพาร์ติชัน /data ได้หากอุปกรณ์ถูกปลดล็อค แม้ว่า fastbootd สามารถบังคับให้การย้ายข้อมูลเสร็จสิ้นได้ แต่ bootloader ก็ไม่สามารถทำได้ bootloader ไม่ทราบว่ากำลังดำเนินการผสานอยู่หรือไม่ หรือบล็อกใดใน /data ที่ประกอบเป็นพาร์ติชันระบบปฏิบัติการ อุปกรณ์จะต้องป้องกันไม่ให้ผู้ใช้ทำให้อุปกรณ์ใช้งานไม่ได้โดยไม่รู้ตัว (อิฐ) โดยทำดังต่อไปนี้:

  1. ใช้การควบคุมการบูต HAL เพื่อให้ bootloader สามารถอ่านค่าที่กำหนดโดยเมธอด setSnapshotMergeStatus()
  2. หากสถานะการผสานคือ MERGING หรือหากสถานะการผสานคือ SNAPSHOTTED และช่องเปลี่ยนเป็นช่องที่อัปเดตใหม่ ดังนั้นคำขอให้ล้าง userdata metadata หรือพาร์ติชันที่จัดเก็บสถานะการผสานจะต้องถูกปฏิเสธในบูตโหลดเดอร์
  3. ใช้คำสั่ง fastboot snapshot-update cancel เพื่อให้ผู้ใช้สามารถส่งสัญญาณไปยัง bootloader ว่าต้องการข้ามกลไกการป้องกันนี้
  4. ปรับเปลี่ยนเครื่องมือหรือสคริปต์การกะพริบแบบกำหนดเองเพื่อ fastboot snapshot-update cancel เมื่อทำการแฟลชทั้งอุปกรณ์ ปัญหานี้ทำได้อย่างปลอดภัยเนื่องจากการกะพริบทั้งอุปกรณ์จะเป็นการลบ OTA Tooling สามารถตรวจจับคำสั่งนี้ขณะรันไทม์ได้โดยใช้ 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 สื่อสารกับ bootloader:
    • หากสถานะเป็น MERGING bootloader จะต้องส่งคืน merging
    • หากสถานะเป็น SNAPSHOTTED bootloader จะต้องส่งคืน snapshotted
    • มิฉะนั้น bootloader จะต้องส่งคืน none
  • snapshot-update merge — ดำเนินการผสานให้เสร็จสมบูรณ์ โดยบูตเป็นการกู้คืน/บูตอย่างรวดเร็วหากจำเป็น คำสั่งนี้ใช้ได้เฉพาะในกรณีที่ snapshot-update-status กำลัง merging และรองรับใน fastbootd เท่านั้น
  • snapshot-update cancel - ตั้งค่าสถานะการรวมของการควบคุมการบูต HAL เป็น CANCELLED คำสั่งนี้ไม่ถูกต้องเมื่ออุปกรณ์ถูกล็อค
  • erase หรือ wipeerase หรือ wipe metadata userdata หรือพาร์ติชันที่มีสถานะผสานสำหรับการควบคุมการบูต HAL ควรตรวจสอบสถานะการรวมสแน็ปช็อต หากสถานะเป็น MERGING หรือ SNAPSHOTTED อุปกรณ์ควรยกเลิกการดำเนินการ
  • set_active — คำสั่ง set_active ที่เปลี่ยนช่องที่ใช้งานอยู่ควรตรวจสอบสถานะการรวมสแน็ปช็อต หากสถานะเป็น MERGING อุปกรณ์ควรยกเลิกการดำเนินการ สามารถเปลี่ยนช่องได้อย่างปลอดภัยในสถานะ SNAPSHOTTED

การเปลี่ยนแปลงเหล่านี้ได้รับการออกแบบมาเพื่อป้องกันการทำให้อุปกรณ์ไม่สามารถบูตได้โดยไม่ได้ตั้งใจ แต่อาจส่งผลกระทบต่อการใช้เครื่องมืออัตโนมัติได้ เมื่อใช้คำสั่งเป็นส่วนประกอบในการแฟลชพาร์ติชันทั้งหมด เช่น การรัน fastboot flashall ขอแนะนำให้ใช้โฟลว์ต่อไปนี้:

  1. แบบสอบถาม getvar snapshot-update-status
  2. หาก merging หรือ snapshotted snapshot-update cancel
  3. ดำเนินการตามขั้นตอนที่กระพริบ

ลดความต้องการในการจัดเก็บ

อุปกรณ์ที่ไม่ได้มีพื้นที่เก็บข้อมูล A/B เต็มรูปแบบที่จัดสรรในซุปเปอร์ และคาดว่าจะใช้ /data ตามความจำเป็น ขอแนะนำอย่างยิ่งให้ใช้เครื่องมือการแมปบล็อก เครื่องมือการแมปบล็อกช่วยให้การจัดสรรบล็อกสอดคล้องกันระหว่างบิวด์ ช่วยลดการเขียนที่ไม่จำเป็นลงในสแน็ปช็อต ข้อมูลนี้มีบันทึกไว้ใน การลดขนาด OTA

วิธีการบีบอัด OTA

แพ็คเกจ OTA สามารถปรับแต่งตามการวัดประสิทธิภาพที่แตกต่างกันได้ Android มีวิธีการบีบอัดที่รองรับหลายวิธี ( gz , lz4 , zstd และ none ) ซึ่งมีการแลกเปลี่ยนระหว่างเวลาติดตั้ง การใช้พื้นที่ COW เวลาบูต และเวลารวมสแนปช็อต ตัวเลือกเริ่มต้นที่เปิดใช้งานสำหรับ ab เสมือนพร้อมการบีบอัดคือ gz compression method (หมายเหตุ: ประสิทธิภาพสัมพัทธ์ระหว่างวิธีการบีบอัดจะแตกต่างกันไปขึ้นอยู่กับความเร็วของ CPU และปริมาณงานการจัดเก็บข้อมูลซึ่งสามารถเปลี่ยนแปลงได้ขึ้นอยู่กับอุปกรณ์ แพ็คเกจ OTA ทั้งหมดที่สร้างขึ้นด้านล่างจะปิดใช้งาน PostInstall ซึ่งจะทำให้เวลาในการบูตช้าลงเล็กน้อย ขนาดพาร์ติชันไดนามิกรวม ของ ota เต็ม โดยไม่มีการบีบอัดคือ 4.81 GB )

OTA แบบเพิ่มหน่วยใน Pixel 6 Pro

เวลาติดตั้งโดยไม่มีขั้นตอนหลังการติดตั้ง การใช้พื้นที่ของวัว โพสต์เวลาบูต OTA เวลารวมสแนปชอต
กซ 24 นาที 1.18GB 40.2 วินาที 45.5 วินาที
lz4 13 นาที 1.49GB 37.4 วินาที 37.1 วินาที
ไม่มี 13 นาที 2.90GB 37.6 วินาที 40.7 วินาที

OTA เต็มรูปแบบบน Pixel 6 Pro

เวลาติดตั้งโดยไม่มีขั้นตอนหลังการติดตั้ง การใช้พื้นที่ของ COW โพสต์เวลาบูต OTA เวลารวมสแนปชอต
กซ 23 นาที 2.79GB 24.9 วินาที 41.7 วินาที
lz4 12 นาที 3.46GB 20.0 วินาที 25.3 วินาที
ไม่มี 10 นาที 4.85GB 20.6 วินาที 29.8 วินาที