ใช้พาร์ติชันแบบไดนามิก

การแบ่งพาร์ติชันแบบไดนามิกจะใช้โมดูล Device Mapper แบบ dm-linear ในเคอร์เนล Linux พาร์ติชัน super มีข้อมูลเมตาที่แสดงชื่อและช่วงบล็อกของพาร์ติชันแบบไดนามิกแต่ละพาร์ติชันภายใน super ในระหว่างระยะที่ 1 init ระบบจะแยกวิเคราะห์และตรวจสอบข้อมูลเมตานี้ รวมถึงสร้างอุปกรณ์บล็อกเสมือนเพื่อแสดงถึงพาร์ติชันแบบไดนามิกแต่ละรายการ

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

เนื่องจากมีการใช้พาร์ติชันแบบไดนามิกในพื้นที่ผู้ใช้ พาร์ติชันที่จําเป็นสําหรับบูตโหลดเดอร์จึงไม่สามารถทําให้เป็นแบบไดนามิกได้ เช่น boot, dtbo และ vbmeta จะถูกอ่านโดย Bootloader จึงต้องยังคงเป็นพาร์ติชันจริง

พาร์ติชันแบบไดนามิกแต่ละรายการอาจอยู่ในกลุ่มการอัปเดต กลุ่มเหล่านี้จะจำกัดพื้นที่สูงสุดที่พาร์ติชันในกลุ่มนั้นใช้ได้ เช่น system และ vendor อาจอยู่ในกลุ่มที่จำกัดขนาดรวมของ system และ vendor

ใช้พาร์ติชันแบบไดนามิกในอุปกรณ์ใหม่

ส่วนนี้จะอธิบายรายละเอียดวิธีใช้พาร์ติชันแบบไดนามิกในอุปกรณ์ใหม่ที่เปิดตัวด้วย Android 10 ขึ้นไป หากต้องการอัปเดตอุปกรณ์ที่มีอยู่ โปรดดูหัวข้อการอัปเกรดอุปกรณ์ Android

การเปลี่ยนแปลงพาร์ติชัน

สำหรับอุปกรณ์ที่เปิดตัวด้วย Android 10 ให้สร้างพาร์ติชันชื่อ super พาร์ติชัน super จะจัดการช่อง A/B ภายใน ดังนั้นอุปกรณ์ A/B จึงไม่จำเป็นต้องมีพาร์ติชัน super_a และ super_b แยกกัน พาร์ติชัน AOSP แบบอ่านอย่างเดียวทั้งหมดที่ไม่ได้ใช้โดยโปรแกรมบูตต้องเป็นแบบไดนามิกและต้องนำออกจากตารางพาร์ติชัน GUID (GPT) พาร์ติชันเฉพาะของผู้ให้บริการไม่จำเป็นต้องเป็นแบบไดนามิกและอาจวางไว้ใน GPT

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

เลย์เอาต์ตารางพาร์ติชัน
รูปที่ 1 เลย์เอาต์ตารางพาร์ติชันฟิสิคัลใหม่เมื่อแปลงเป็นพาร์ติชันแบบไดนามิก

พาร์ติชันแบบไดนามิกที่รองรับมีดังนี้

  • ระบบ
  • ตัวแทนจำหน่ายรายย่อย
  • ผลิตภัณฑ์
  • System Ext
  • ODM

สำหรับอุปกรณ์ที่เปิดตัวด้วย Android 10 ตัวเลือกบรรทัดคำสั่งเคอร์เนล androidboot.super_partition ต้องว่างเปล่าเพื่อให้คำสั่ง sysprop ro.boot.super_partition ว่างเปล่า

การจัดแนวพาร์ติชัน

โมดูล Device-Mapper อาจทำงานได้อย่างมีประสิทธิภาพน้อยลงหากมีการจัดแนวพาร์ติชัน super อย่างไม่ถูกต้อง พาร์ติชัน super ต้องสอดคล้องกับขนาดคำขอ I/O ขั้นต่ำตามที่เลเยอร์บล็อกกำหนด โดยค่าเริ่มต้น ระบบบิลด์ (ผ่าน lpmake ซึ่งสร้างsuper อิมเมจพาร์ติชัน) จะถือว่าการจัดแนว 1 MiB เพียงพอสำหรับพาร์ติชันแบบไดนามิกทุกพาร์ติชัน อย่างไรก็ตาม ผู้ให้บริการควรตรวจสอบว่ามีการจัดแนวพาร์ติชัน super อย่างถูกต้อง

คุณกำหนดขนาดคำขอขั้นต่ำของอุปกรณ์บล็อกได้โดยการตรวจสอบ sysfs เช่น

# ls -l /dev/block/by-name/super
lrwxrwxrwx 1 root root 16 1970-04-05 01:41 /dev/block/by-name/super -> /dev/block/sda17
# cat /sys/block/sda/queue/minimum_io_size
786432

คุณสามารถยืนยันการจัดตำแหน่งของพาร์ติชัน super ในลักษณะที่คล้ายกัน ดังนี้

# cat /sys/block/sda/sda17/alignment_offset

ออฟเซ็ตการจัดตำแหน่งต้องเป็น 0

การเปลี่ยนแปลงการกำหนดค่าอุปกรณ์

หากต้องการเปิดใช้การแบ่งพาร์ติชันแบบไดนามิก ให้เพิ่ม Flag ต่อไปนี้ใน device.mk

PRODUCT_USE_DYNAMIC_PARTITIONS := true

การเปลี่ยนแปลงการกำหนดค่ากระดาน

คุณต้องตั้งค่าขนาดของพาร์ติชัน super ดังนี้

BOARD_SUPER_PARTITION_SIZE := <size-in-bytes>

ในอุปกรณ์ A/B ระบบบิลด์จะแสดงข้อผิดพลาดหากขนาดรวมของภาพพาร์ติชันแบบไดนามิกมากกว่าครึ่งหนึ่งของขนาดพาร์ติชัน super

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

ต่อไปนี้เป็นตัวอย่างอุปกรณ์ที่วางพาร์ติชันทั้งหมดไว้ในกลุ่มที่ชื่อ example_dynamic_partitions

BOARD_SUPER_PARTITION_GROUPS := example_dynamic_partitions
BOARD_EXAMPLE_DYNAMIC_PARTITIONS_SIZE := 6442450944
BOARD_EXAMPLE_DYNAMIC_PARTITIONS_PARTITION_LIST := system vendor product

ต่อไปนี้เป็นตัวอย่างอุปกรณ์ที่วางบริการระบบและบริการผลิตภัณฑ์ไว้ใน group_foo และ vendor, product และ odm ใน group_bar

BOARD_SUPER_PARTITION_GROUPS := group_foo group_bar
BOARD_GROUP_FOO_SIZE := 4831838208
BOARD_GROUP_FOO_PARTITION_LIST := system product_services
BOARD_GROUP_BAR_SIZE := 1610612736
BOARD_GROUP_BAR_PARTITION_LIST := vendor product odm
  • สําหรับอุปกรณ์ที่เปิดใช้งาน A/B เสมือน จํานวนกลุ่มทั้งหมดรวมกันต้องไม่เกิน
    BOARD_SUPER_PARTITION_SIZE - ค่าใช้จ่ายเพิ่มเติม
    ดูการใช้ A/B เสมือน
  • สําหรับอุปกรณ์ที่เปิดใช้งาน A/B ผลรวมของขนาดสูงสุดของทุกกลุ่มต้องเท่ากับ
    BOARD_SUPER_PARTITION_SIZE / 2 - ค่าใช้จ่ายเพิ่มเติม
  • สําหรับอุปกรณ์ที่ไม่ใช่ A/B และอุปกรณ์ A/B ที่ติดตั้งเพิ่ม ผลรวมของขนาดสูงสุดของกลุ่มทั้งหมดต้องเป็น
    BOARD_SUPER_PARTITION_SIZE - ค่าใช้จ่ายเพิ่มเติม
  • ในช่วงเวลาที่สร้าง ผลรวมของขนาดของภาพของแต่ละพาร์ติชันในกลุ่มอัปเดตต้องไม่เกินขนาดสูงสุดของกลุ่ม
  • ต้องใช้ค่าใช้จ่ายเพิ่มเติมในการคํานวณเพื่อพิจารณาข้อมูลเมตา การจัดแนว และอื่นๆ พื้นที่เก็บข้อมูลส่วนเกินที่เหมาะสมคือ 4 MiB แต่คุณเลือกพื้นที่เก็บข้อมูลส่วนเกินที่มากกว่าได้หากอุปกรณ์ต้องการ

ปรับขนาดพาร์ติชันแบบไดนามิก

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

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

นอกจากนี้ คุณยังบีบอัดอิมเมจ ext4 เพิ่มเติมได้ด้วยการเปิดใช้การกรองข้อมูลซ้ำระดับบล็อก หากต้องการเปิดใช้ ให้ใช้การกําหนดค่าต่อไปนี้

BOARD_EXT4_SHARE_DUP_BLOCKS := true

หากไม่ต้องการการจัดสรรขนาดขั้นต่ำของพาร์ติชันโดยอัตโนมัติ คุณควบคุมขนาดพาร์ติชันได้ 2 วิธีดังนี้ คุณสามารถระบุปริมาณพื้นที่ว่างขั้นต่ำด้วย BOARD_partitionIMAGE_PARTITION_RESERVED_SIZE หรือระบุ BOARD_partitionIMAGE_PARTITION_SIZE เพื่อบังคับให้พาร์ติชันแบบไดนามิกมีขนาดใหญ่ที่เจาะจง เราไม่แนะนำให้ใช้วิธีใดวิธีหนึ่งเหล่านี้ เว้นแต่จำเป็น

เช่น

BOARD_PRODUCTIMAGE_PARTITION_RESERVED_SIZE := 52428800

ซึ่งจะบังคับให้ระบบไฟล์ใน product.img มีพื้นที่ว่างที่ไม่ได้ใช้ 50 MiB

การเปลี่ยนแปลงระบบในฐานะรูท

อุปกรณ์ที่เปิดตัวด้วย Android 10 ต้องไม่ใช้ระบบเป็นรูท

อุปกรณ์ที่มีพาร์ติชันแบบไดนามิก (ไม่ว่าจะเปิดตัวด้วยหรือติดตั้งพาร์ติชันแบบไดนามิกในภายหลัง) ต้องไม่ใช้ระบบเป็นรูท เคอร์เนล Linux ตีความพาร์ติชัน super ไม่ได้ จึงไม่สามารถมา운ต์ system ได้ ตอนนี้ system ได้รับการต่อเชื่อมโดย init ระยะแรกที่อยู่ในแรมดิสก์

อย่าตั้งค่า BOARD_BUILD_SYSTEM_ROOT_IMAGE ใน Android 10 จะใช้ Flag BOARD_BUILD_SYSTEM_ROOT_IMAGE เพื่อแยกแยะว่าระบบได้รับการมาสก์โดยเคอร์เนลหรือโดย init ระยะที่ 1 ในแรมดิสก์

การตั้งค่า BOARD_BUILD_SYSTEM_ROOT_IMAGE เป็น true จะทำให้เกิดข้อผิดพลาดในการสร้างเมื่อ PRODUCT_USE_DYNAMIC_PARTITIONS เป็น true ด้วย

เมื่อตั้งค่า BOARD_USES_RECOVERY_AS_BOOT เป็น "จริง" ระบบจะสร้างอิมเมจการกู้คืนเป็น boot.img ซึ่งมี RAMdisk ของการกู้คืน ก่อนหน้านี้ บูตโหลดเดอร์ใช้พารามิเตอร์บรรทัดคำสั่งของเคอร์เนล skip_initramfs เพื่อเลือกโหมดที่จะบูต สำหรับอุปกรณ์ Android 10 บูตโหลดเดอร์ต้องไม่ส่ง skip_initramfs ไปยังบรรทัดคำสั่งของเคิร์นเนล แต่ควรส่ง androidboot.force_normal_boot=1 เพื่อข้ามการกู้คืนและบูต Android ปกติ อุปกรณ์ที่เปิดตัวด้วย Android 12 ขึ้นไปต้องใช้ bootconfig เพื่อส่ง androidboot.force_normal_boot=1

การเปลี่ยนแปลงการกำหนดค่า AVB

เมื่อใช้ Android Verified Boot 2.0 หากอุปกรณ์ไม่ได้ใช้ตัวระบุพาร์ติชันแบบเชน ก็ไม่จำเป็นต้องทำการเปลี่ยนแปลงใดๆ อย่างไรก็ตาม หากใช้พาร์ติชันที่เชื่อมโยงกันและพาร์ติชันที่ยืนยันแล้วรายการใดรายการหนึ่งเป็นแบบไดนามิก คุณจะต้องทําการเปลี่ยนแปลง

ต่อไปนี้คือตัวอย่างการกำหนดค่าสำหรับอุปกรณ์ที่ต่อเชื่อม vbmeta สำหรับพาร์ติชัน system และ vendor

BOARD_AVB_SYSTEM_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
BOARD_AVB_SYSTEM_ALGORITHM := SHA256_RSA2048
BOARD_AVB_SYSTEM_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
BOARD_AVB_SYSTEM_ROLLBACK_INDEX_LOCATION := 1

BOARD_AVB_VENDOR_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
BOARD_AVB_VENDOR_ALGORITHM := SHA256_RSA2048
BOARD_AVB_VENDOR_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
BOARD_AVB_VENDOR_ROLLBACK_INDEX_LOCATION := 1

เมื่อใช้การกำหนดค่านี้ บูตโหลดเดอร์จะคาดหวังว่าจะพบส่วนท้าย vbmeta ที่ส่วนท้ายของพาร์ติชัน system และ vendor เนื่องจาก bootloader มองไม่เห็นพาร์ติชันเหล่านี้อีกต่อไป (พาร์ติชันอยู่ใน super) จึงต้องมีการทำการเปลี่ยนแปลง 2 อย่าง

  • เพิ่มพาร์ติชัน vbmeta_system และ vbmeta_vendor ลงในตารางพาร์ติชันของอุปกรณ์ สําหรับอุปกรณ์ A/B ให้เพิ่ม vbmeta_system_a, vbmeta_system_b, vbmeta_vendor_a และ vbmeta_vendor_b หากเพิ่มพาร์ติชันเหล่านี้อย่างน้อย 1 รายการ พาร์ติชันดังกล่าวควรมีขนาดเท่ากับพาร์ติชัน vbmeta
  • เปลี่ยนชื่อ Flag การกําหนดค่าโดยเพิ่ม VBMETA_ และระบุพาร์ติชันที่จะขยายการเชื่อมโยง
    BOARD_AVB_VBMETA_SYSTEM := system
    BOARD_AVB_VBMETA_SYSTEM_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
    BOARD_AVB_VBMETA_SYSTEM_ALGORITHM := SHA256_RSA2048
    BOARD_AVB_VBMETA_SYSTEM_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
    BOARD_AVB_VBMETA_SYSTEM_ROLLBACK_INDEX_LOCATION := 1
    
    BOARD_AVB_VBMETA_VENDOR := vendor
    BOARD_AVB_VBMETA_VENDOR_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
    BOARD_AVB_VBMETA_VENDOR_ALGORITHM := SHA256_RSA2048
    BOARD_AVB_VBMETA_VENDOR_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
    BOARD_AVB_VBMETA_VENDOR_ROLLBACK_INDEX_LOCATION := 1

อุปกรณ์อาจใช้พาร์ติชันเหล่านี้เพียงอย่างเดียว ใช้ทั้ง 2 อย่าง หรือไม่ได้ใช้เลย การเปลี่ยนแปลงจะจำเป็นก็ต่อเมื่อมีการต่อเชื่อมกับพาร์ติชันเชิงตรรกะเท่านั้น

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

หากโปรแกรมโหลดบูตฝัง libavb ให้ใส่แพตช์ต่อไปนี้

หากใช้พาร์ติชันที่เชื่อมโยง ให้ใส่แพตช์เพิ่มเติม ดังนี้

  • 49936b4c0109411fdd38bd4ba3a32a01c40439a9 — "libavb: รองรับ vbmeta blob ในช่วงต้นของพาร์ติชัน"

การเปลี่ยนแปลงบรรทัดคำสั่งของเคอร์เนล

คุณต้องเพิ่มพารามิเตอร์ใหม่ androidboot.boot_devices ลงในบรรทัดคำสั่งเคอร์เนล init ใช้ค่านี้เพื่อเปิดใช้ /dev/block/by-name symlink โดยควรเป็นคอมโพเนนต์เส้นทางอุปกรณ์ไปยังซิงค์ลิงค์ตามชื่อที่อยู่เบื้องหลังซึ่งสร้างขึ้นโดย ueventd นั่นคือ /dev/block/platform/device-path/by-name/partition-name อุปกรณ์ที่เปิดตัวด้วย Android 12 ขึ้นไปต้องใช้ bootconfig เพื่อส่ง androidboot.boot_devices ไปยัง init

ตัวอย่างเช่น หากลิงก์สัญลักษณ์ของพาร์ติชันหลักตามชื่อคือ /dev/block/platform/soc/100000.ufshc/by-name/super คุณก็เพิ่มพารามิเตอร์บรรทัดคำสั่งในไฟล์ BoardConfig.mk ดังนี้

BOARD_KERNEL_CMDLINE += androidboot.boot_devices=soc/100000.ufshc
คุณสามารถเพิ่มพารามิเตอร์ bootconfig ในไฟล์ BoardConfig.mk ได้โดยทำดังนี้
BOARD_BOOTCONFIG += androidboot.boot_devices=soc/100000.ufshc

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

โครงสร้างอุปกรณ์และการวางซ้อนโครงสร้างอุปกรณ์ต้องไม่มีรายการ fstab ใช้ไฟล์ fstab ที่จะเป็นส่วนหนึ่งของ RAM disk

คุณต้องทําการเปลี่ยนแปลงในไฟล์ fstab สําหรับพาร์ติชันตรรกะ

  • ช่อง Flag ของ fs_mgr ต้องมี Flag logical และ Flag first_stage_mount ซึ่งเปิดตัวใน Android 10 ซึ่งบ่งบอกว่าต้องทำการต่อเชื่อมพาร์ติชันในระยะแรก
  • พาร์ติชันอาจระบุ avb=vbmeta partition name เป็น Flag fs_mgr จากนั้นระบบจะเริ่มต้นพาร์ติชัน vbmeta ที่ระบุโดย init ระยะแรกก่อนที่จะพยายามเมานต์อุปกรณ์
  • ช่อง dev ต้องเป็นชื่อพาร์ติชัน

รายการ fstab ต่อไปนี้จะตั้งค่าระบบ ผู้ให้บริการ และผลิตภัณฑ์เป็นพาร์ติชันตรรกะตามกฎข้างต้น

#<dev>  <mnt_point> <type>  <mnt_flags options> <fs_mgr_flags>
system   /system     ext4    ro,barrier=1        wait,slotselect,avb=vbmeta,logical,first_stage_mount
vendor   /vendor     ext4    ro,barrier=1        wait,slotselect,avb,logical,first_stage_mount
product  /product    ext4    ro,barrier=1        wait,slotselect,avb,logical,first_stage_mount

คัดลอกไฟล์ fstab ไปยัง RAM disk ระยะที่ 1

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

อุปกรณ์บล็อกพาร์ติชันระดับซูเปอร์ต้องติดป้ายกำกับ super_block_device ตัวอย่างเช่น หากลิงก์สัญลักษณ์ของพาร์ติชันหลักตามชื่อคือ /dev/block/platform/soc/100000.ufshc/by-name/super ให้เพิ่มบรรทัดต่อไปนี้ลงใน file_contexts

/dev/block/platform/soc/10000\.ufshc/by-name/super   u:object_r:super_block_device:s0

fastbootd

บูตโหลดเดอร์ (หรือเครื่องมือแฟลชที่ไม่ใช่พื้นที่ผู้ใช้) ไม่เข้าใจพาร์ติชันแบบไดนามิก จึงแฟลชพาร์ติชันดังกล่าวไม่ได้ ในการแก้ปัญหานี้ อุปกรณ์ต้องใช้การใช้งานโปรโตคอล fastboot ใน User Space ซึ่งเรียกว่า fastbootd

ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีใช้ fastbootd ได้ที่การย้าย Fastboot ไปยังพื้นที่ผู้ใช้

adb remount

สําหรับนักพัฒนาแอปที่ใช้บิลด์ eng หรือ userdebug adb remount จะมีประโยชน์อย่างยิ่งสำหรับการทำซ้ำอย่างรวดเร็ว พาร์ติชันแบบไดนามิกก่อให้เกิดปัญหาสำหรับ adb remount เนื่องจากไม่มีพื้นที่ว่างภายในระบบไฟล์แต่ละระบบอีกต่อไป อุปกรณ์สามารถเปิดใช้ overlayfs เพื่อแก้ไขปัญหานี้ได้ ตราบใดที่มีพื้นที่ว่างภายในพาร์ติชันซุปเปอร์ adb remount จะสร้างพาร์ติชันแบบไดนามิกชั่วคราวโดยอัตโนมัติ และใช้ overlayfs สำหรับการเขียน พาร์ติชันชั่วคราวจะมีชื่อว่า scratch ดังนั้นอย่าใช้ชื่อนี้กับพาร์ติชันอื่นๆ

ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีเปิดใช้ overlayfs ได้ที่ overlayfs README ใน AOSP

อัปเกรดอุปกรณ์ Android

หากอัปเกรดอุปกรณ์เป็น Android 10 และต้องการเพิ่มการรองรับพาร์ติชันแบบไดนามิกใน OTA คุณไม่จําเป็นต้องเปลี่ยนตารางพาร์ติชันในตัว ต้องมีการกําหนดค่าเพิ่มเติมบางอย่าง

การเปลี่ยนแปลงการกำหนดค่าอุปกรณ์

หากต้องการปรับค่าใช้จ่ายในการแบ่งพาร์ติชันแบบไดนามิก ให้เพิ่ม Flag ต่อไปนี้ใน device.mk

PRODUCT_USE_DYNAMIC_PARTITIONS := true
PRODUCT_RETROFIT_DYNAMIC_PARTITIONS := true

การเปลี่ยนแปลงการกำหนดค่ากระดาน

คุณต้องตั้งค่าตัวแปรของบอร์ดต่อไปนี้

  • ตั้งค่า BOARD_SUPER_PARTITION_BLOCK_DEVICES เป็นรายการอุปกรณ์บล็อกที่ใช้เพื่อจัดเก็บส่วนที่ขยายของพาร์ติชันแบบไดนามิก นี่คือรายการชื่อของพาร์ติชันที่มีอยู่จริงในอุปกรณ์
  • ตั้งค่า BOARD_SUPER_PARTITION_partition_DEVICE_SIZE เป็นขนาดของอุปกรณ์บล็อกแต่ละเครื่องใน BOARD_SUPER_PARTITION_BLOCK_DEVICES ตามลำดับ นี่คือรายการขนาดของพาร์ติชันที่มีอยู่จริงในอุปกรณ์ ซึ่งโดยปกติแล้วจะเป็นBOARD_partitionIMAGE_PARTITION_SIZEในการกําหนดค่าแผงที่มีอยู่
  • ยกเลิกการตั้งค่า BOARD_partitionIMAGE_PARTITION_SIZE ที่มีอยู่สำหรับพาร์ติชันทั้งหมดใน BOARD_SUPER_PARTITION_BLOCK_DEVICES
  • ตั้งค่า BOARD_SUPER_PARTITION_SIZE เป็นผลรวมของ BOARD_SUPER_PARTITION_partition_DEVICE_SIZE
  • ตั้งค่า BOARD_SUPER_PARTITION_METADATA_DEVICE เป็นอุปกรณ์บล็อกที่จัดเก็บข้อมูลเมตาของพาร์ติชันแบบไดนามิก โดยต้องเป็นหนึ่งใน BOARD_SUPER_PARTITION_BLOCK_DEVICES โดยทั่วไปแล้ว การตั้งค่านี้จะตั้งเป็น system
  • ตั้งค่า BOARD_SUPER_PARTITION_GROUPS, BOARD_group_SIZE และ BOARD_group_PARTITION_LIST ตามลำดับ โปรดดูรายละเอียดที่หัวข้อการเปลี่ยนแปลงการกําหนดค่าบอร์ดและอุปกรณ์ใหม่

เช่น หากอุปกรณ์มีพาร์ติชันระบบและพาร์ติชันของผู้ให้บริการอยู่แล้ว และคุณต้องการแปลงพาร์ติชันเหล่านั้นเป็นพาร์ติชันแบบไดนามิกและเพิ่มพาร์ติชันผลิตภัณฑ์ใหม่ในระหว่างการอัปเดต ให้ตั้งค่าการกำหนดค่าบอร์ดและกำหนดค่าดังนี้

BOARD_SUPER_PARTITION_BLOCK_DEVICES := system vendor
BOARD_SUPER_PARTITION_METADATA_DEVICE := system

# Rename BOARD_SYSTEMIMAGE_PARTITION_SIZE to BOARD_SUPER_PARTITION_SYSTEM_DEVICE_SIZE.
BOARD_SUPER_PARTITION_SYSTEM_DEVICE_SIZE := <size-in-bytes>

# Rename BOARD_VENDORIMAGE_PARTITION_SIZE to BOARD_SUPER_PARTITION_VENDOR_DEVICE_SIZE
BOARD_SUPER_PARTITION_VENDOR_DEVICE_SIZE := <size-in-bytes>

# This is BOARD_SUPER_PARTITION_SYSTEM_DEVICE_SIZE + BOARD_SUPER_PARTITION_VENDOR_DEVICE_SIZE
BOARD_SUPER_PARTITION_SIZE := <size-in-bytes>

# Configuration for dynamic partitions. For example:
BOARD_SUPER_PARTITION_GROUPS := group_foo
BOARD_GROUP_FOO_SIZE := <size-in-bytes>
BOARD_GROUP_FOO_PARTITION_LIST := system vendor product

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

อุปกรณ์บล็อกพาร์ติชันระดับซูเปอร์ต้องติดแท็กแอตทริบิวต์ super_block_device_type เช่น หากอุปกรณ์มีพาร์ติชัน system และ vendor อยู่แล้ว คุณอาจต้องการใช้เป็นอุปกรณ์บล็อกเพื่อจัดเก็บส่วนที่ขยายของพาร์ติชันแบบไดนามิก และมีการทําเครื่องหมายซิงค์ลิงค์ตามชื่อเป็น system_block_device ดังนี้

/dev/block/platform/soc/10000\.ufshc/by-name/system   u:object_r:system_block_device:s0
/dev/block/platform/soc/10000\.ufshc/by-name/vendor   u:object_r:system_block_device:s0

จากนั้นเพิ่มบรรทัดต่อไปนี้ลงใน device.te

typeattribute system_block_device super_block_device_type;

สําหรับการกําหนดค่าอื่นๆ โปรดดูการใช้พาร์ติชันแบบไดนามิกในอุปกรณ์ใหม่

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

อิมเมจเริ่มต้น

สำหรับอุปกรณ์ที่เปิดตัวโดยรองรับพาร์ติชันแบบไดนามิก ให้หลีกเลี่ยงการใช้ Fastboot ในพื้นที่ผู้ใช้เพื่อแฟลชอิมเมจโรงงาน เนื่องจากการบูตไปยังพื้นที่ผู้ใช้จะช้ากว่าวิธีการแฟลชอื่นๆ

ด้วยเหตุนี้ make dist จึงสร้างsuper.img เพิ่มเติมที่สามารถแฟลชไปยังพาร์ติชัน Super ได้โดยตรง โดยจะรวมเนื้อหาของพาร์ติชันเชิงตรรกะโดยอัตโนมัติ ซึ่งหมายความว่าจะมี system.img, vendor.img และอื่นๆ นอกเหนือจากข้อมูลเมตาของพาร์ติชัน super คุณสามารถแฟลชภาพนี้ลงในพาร์ติชัน super ได้โดยตรงโดยไม่ต้องใช้เครื่องมือเพิ่มเติมหรือใช้ fastbootd หลังจากบิลด์แล้ว super.img จะอยู่ใน ${ANDROID_PRODUCT_OUT}

สำหรับอุปกรณ์ A/B ที่เปิดตัวด้วยพาร์ติชันแบบไดนามิก super.img จะมีรูปภาพในช่อง A หลังจากแฟลช Super Image โดยตรงแล้ว ให้ทำเครื่องหมายช่อง A เป็นบูตได้ก่อนที่จะรีบูตอุปกรณ์

สำหรับอุปกรณ์ที่ติดตั้งอุปกรณ์ต่อพ่วง make dist จะสร้างชุดsuper_*.imgอิมเมจที่สามารถแฟลชไปยังพาร์ติชันฟิสิคัลที่เกี่ยวข้องได้โดยตรง เช่น make distสร้างขึ้นจาก super_system.img และ super_vendor.img เมื่อ BOARD_SUPER_PARTITION_BLOCK_DEVICES เป็นผู้ให้บริการระบบ รูปภาพเหล่านี้จะอยู่ในโฟลเดอร์ OTA ใน target_files.zip

การปรับแต่งพื้นที่เก็บข้อมูลของอุปกรณ์แมปเปอร์

การแบ่งพาร์ติชันแบบไดนามิกรองรับออบเจ็กต์ Device-Mapper ที่ไม่แน่นอนจํานวนหนึ่ง พาร์ติชันเหล่านี้อาจไม่ได้สร้างอินสแตนซ์ทั้งหมดตามที่คาดไว้ คุณจึงต้องติดตามการต่อเชื่อมทั้งหมดและอัปเดตพร็อพเพอร์ตี้ Android ของพาร์ติชันที่เชื่อมโยงทั้งหมดกับอุปกรณ์เก็บข้อมูลที่เกี่ยวข้อง

กลไกภายใน init จะติดตามการต่อเชื่อมและอัปเดตพร็อพเพอร์ตี้ Android แบบไม่สอดคล้องกัน เราไม่รับประกันว่าระยะเวลานี้จะอยู่ภายในระยะเวลาที่เจาะจง ดังนั้นคุณต้องให้เวลาเพียงพอเพื่อให้ทริกเกอร์ on property ทั้งหมดตอบสนอง พร็อพเพอร์ตี้คือ dev.mnt.blk.<partition> โดยที่ <partition> คือ root, system, data หรือ vendor เป็นต้น พร็อพเพอร์ตี้แต่ละรายการจะเชื่อมโยงกับชื่ออุปกรณ์เก็บข้อมูลพื้นฐาน ดังที่แสดงในตัวอย่างต่อไปนี้

taimen:/ % getprop | grep dev.mnt.blk
[dev.mnt.blk.data]: [sda]
[dev.mnt.blk.firmware]: [sde]
[dev.mnt.blk.metadata]: [sde]
[dev.mnt.blk.persist]: [sda]
[dev.mnt.blk.root]: [dm-0]
[dev.mnt.blk.vendor]: [dm-1]

blueline:/ $ getprop | grep dev.mnt.blk
[dev.mnt.blk.data]: [dm-4]
[dev.mnt.blk.metadata]: [sda]
[dev.mnt.blk.mnt.scratch]: [sda]
[dev.mnt.blk.mnt.vendor.persist]: [sdf]
[dev.mnt.blk.product]: [dm-2]
[dev.mnt.blk.root]: [dm-0]
[dev.mnt.blk.system_ext]: [dm-3]
[dev.mnt.blk.vendor]: [dm-1]
[dev.mnt.blk.vendor.firmware_mnt]: [sda]

ภาษา init.rc ช่วยให้ขยายพร็อพเพอร์ตี้ Android เป็นส่วนหนึ่งของกฎได้ และแพลตฟอร์มจะปรับแต่งอุปกรณ์เก็บข้อมูลได้ตามต้องการด้วยคำสั่งต่อไปนี้

write /sys/block/${dev.mnt.blk.root}/queue/read_ahead_kb 128
write /sys/block/${dev.mnt.blk.data}/queue/read_ahead_kb 128

เมื่อการประมวลผลคําสั่งเริ่มขึ้นในระยะที่ 2 init จะทํางาน และค่าต่างๆ จะเริ่มอัปเดตepoll loop อย่างไรก็ตาม เนื่องจากทริกเกอร์พร็อพเพอร์ตี้จะไม่ทำงานจนกว่าจะถึงช่วงปลายinit คุณจึงใช้ทริกเกอร์ดังกล่าวในขั้นตอนการบูตครั้งแรกเพื่อจัดการ root, system หรือ vendor ไม่ได้ คุณอาจคาดหวังว่าค่าเริ่มต้น read_ahead_kb ของเคอร์เนลจะเพียงพอจนกว่าสคริปต์ init.rc จะลบล้างได้ใน early-fs (เมื่อระบบเริ่มทำงานเดรัม่อนและยูทิลิตีต่างๆ) ดังนั้น Google จึงขอแนะนําให้คุณใช้ฟีเจอร์ on property ร่วมกับพร็อพเพอร์ตี้ที่ควบคุมด้วย init.rc เช่น sys.read_ahead_kb เพื่อจัดการกับการกำหนดเวลาการดำเนินการและเพื่อป้องกันเงื่อนไขการแข่งขัน ดังตัวอย่างต่อไปนี้

on property:dev.mnt.blk.root=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.root}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on property:dev.mnt.blk.system=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.system}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on property:dev.mnt.blk.vendor=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.vendor}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on property:dev.mnt.blk.product=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.system_ext}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on property:dev.mnt.blk.oem=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.oem}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on property:dev.mnt.blk.data=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.data}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on early-fs:
    setprop sys.read_ahead_kb ${ro.read_ahead_kb.boot:-2048}

on property:sys.boot_completed=1
   setprop sys.read_ahead_kb ${ro.read_ahead_kb.bootcomplete:-128}