พาร์ติชันการเปิดเครื่องของผู้ให้บริการ

Android 11 นำเสนอแนวคิดของเคอร์เนลทั่วไป รูปภาพ (GKI) วิธีเปิดใช้การเปิดเครื่องอุปกรณ์ที่กำหนดเองด้วย GKI, Android 11 อุปกรณ์สามารถใช้ส่วนหัวอิมเมจการเปิดเครื่องเวอร์ชัน 3 ได้ ใน เวอร์ชัน 3 มีการนำข้อมูลเฉพาะผู้ให้บริการทั้งหมดออกจาก boot และย้ายไปยังพาร์ติชัน vendor_boot ใหม่ อุปกรณ์ ARM64 การเปิดตัวด้วย Android 11 บนเคอร์เนลของ Linux 5.4 รองรับพาร์ติชัน vendor_boot และรูปแบบพาร์ติชัน boot ที่อัปเดตแล้วเพื่อ ผ่านการทดสอบกับ GKI

อุปกรณ์ Android 12 สามารถใช้ส่วนหัวอิมเมจการเปิดเครื่องเวอร์ชัน 4 ได้ ซึ่งรองรับการรวม RAM ของผู้ให้บริการหลายรายการใน vendor_boot พาร์ติชัน ส่วนย่อย RAM ของผู้ให้บริการหลายรายการจะต่อกันทีละส่วน ในส่วน RAM ของผู้ให้บริการ มีการใช้ตาราง RAM ของผู้ให้บริการเพื่ออธิบาย การจัดวางของส่วน RAM ของผู้ให้บริการและข้อมูลเมตาของ RAM ดิสก์ของผู้ให้บริการแต่ละราย ส่วนย่อย

โครงสร้างพาร์ติชัน

พาร์ติชันการเปิดเครื่องของผู้ให้บริการเป็นแบบ A/B พร้อม A/B เสมือนและได้รับการปกป้องโดย Android การเปิดเครื่องที่ได้รับการยืนยัน

เวอร์ชัน 3

พาร์ติชันประกอบด้วยส่วนหัว, ramdisk ของผู้ให้บริการ และ BLOB ของแผนผังอุปกรณ์ (DTB)

โซน จำนวนหน้า
ส่วนหัวการเปิดเครื่องของผู้ให้บริการ (n หน้า) n = (2112 + page_size - 1) / page_size
ramdisk ของผู้ให้บริการ (o หน้า) o = (vendor_ramdisk_size + page_size - 1) / page_size
DTB (หน้า P) p = (dtb_size + page_size - 1) / page_size

เวอร์ชัน 4

พาร์ติชันประกอบด้วยส่วนหัว ส่วน RAM ของผู้ให้บริการ (ประกอบด้วย ส่วนย่อย RAM ของผู้ให้บริการทั้งหมด, เชื่อมต่อ), BLOB แผนผังอุปกรณ์ (DTB) และส่วน ตาราง RAM ของผู้ให้บริการ

โซน จำนวนหน้า
ส่วนหัวการเปิดเครื่องของผู้ให้บริการ (n หน้า) n = (2128 + page_size - 1) / page_size
ส่วนย่อย RAM ของผู้ให้บริการ (o หน้า) o = (vendor_ramdisk_size + page_size - 1) / page_size
DTB (หน้า P) p = (dtb_size + page_size - 1) / page_size
ตาราง RAM ของผู้ให้บริการ (หน้า q) q = (vendor_ramdisk_table_size + page_size - 1) / page_size
Bootconfig (หน้า r) r = (bootconfig_size + page_size - 1) / page_size

ส่วนหัวการเปิดเครื่องของผู้ให้บริการ

เนื้อหาของส่วนหัวบูตพาร์ติชันของผู้ให้บริการประกอบไปด้วยข้อมูลเป็นหลัก ที่มีการโยกย้ายมาจาก ส่วนหัวของรูปภาพเปิดเครื่อง ทั้งนี้ ยังมีข้อมูลเกี่ยวกับ RAM ของผู้ให้บริการด้วย

เวอร์ชัน 3

struct vendor_boot_img_hdr_v3
{
#define VENDOR_BOOT_MAGIC_SIZE 8
    uint8_t magic[VENDOR_BOOT_MAGIC_SIZE];
    uint32_t header_version;
    uint32_t page_size;           /* flash page size we assume */

    uint32_t kernel_addr;         /* physical load addr */
    uint32_t ramdisk_addr;        /* physical load addr */

    uint32_t vendor_ramdisk_size; /* size in bytes */

#define VENDOR_BOOT_ARGS_SIZE 2048
    uint8_t cmdline[VENDOR_BOOT_ARGS_SIZE];

    uint32_t tags_addr;           /* physical addr for kernel tags */

#define VENDOR_BOOT_NAME_SIZE 16
    uint8_t name[VENDOR_BOOT_NAME_SIZE]; /* asciiz product name */
    uint32_t header_size;         /* size of vendor boot image header in
                                   * bytes */
    uint32_t dtb_size;            /* size of dtb image */
    uint64_t dtb_addr;            /* physical load address */

};

เวอร์ชัน 4

struct vendor_boot_img_hdr_v4
{
#define VENDOR_BOOT_MAGIC_SIZE 8
    uint8_t magic[VENDOR_BOOT_MAGIC_SIZE];
    uint32_t header_version;
    uint32_t page_size;           /* flash page size we assume */

    uint32_t kernel_addr;         /* physical load addr */
    uint32_t ramdisk_addr;        /* physical load addr */

    uint32_t vendor_ramdisk_size; /* size in bytes */

#define VENDOR_BOOT_ARGS_SIZE 2048
    uint8_t cmdline[VENDOR_BOOT_ARGS_SIZE];

    uint32_t tags_addr;           /* physical addr for kernel tags */

#define VENDOR_BOOT_NAME_SIZE 16
    uint8_t name[VENDOR_BOOT_NAME_SIZE]; /* asciiz product name */
    uint32_t header_size;         /* size of vendor boot image header in
                                   * bytes */
    uint32_t dtb_size;            /* size of dtb image */
    uint64_t dtb_addr;            /* physical load address */

    uint32_t vendor_ramdisk_table_size; /* size in bytes for the vendor ramdisk table */
    uint32_t vendor_ramdisk_table_entry_num; /* number of entries in the vendor ramdisk table */
    uint32_t vendor_ramdisk_table_entry_size; /* size in bytes for a vendor ramdisk table entry */
    uint32_t bootconfig_size; /* size in bytes for the bootconfig section */
};

#define VENDOR_RAMDISK_TYPE_NONE 0
#define VENDOR_RAMDISK_TYPE_PLATFORM 1
#define VENDOR_RAMDISK_TYPE_RECOVERY 2
#define VENDOR_RAMDISK_TYPE_DLKM 3

struct vendor_ramdisk_table_entry_v4
{
    uint32_t ramdisk_size; /* size in bytes for the ramdisk image */
    uint32_t ramdisk_offset; /* offset to the ramdisk image in vendor ramdisk section */
    uint32_t ramdisk_type; /* type of the ramdisk */
#define VENDOR_RAMDISK_NAME_SIZE 32
    uint8_t ramdisk_name[VENDOR_RAMDISK_NAME_SIZE]; /* asciiz ramdisk name */

#define VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE 16
    // Hardware identifiers describing the board, soc or platform which this
    // ramdisk is intended to be loaded on.
    uint32_t board_id[VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE];
};
  • vendor_ramdisk_size คือขนาดรวมของ Fragment ramdisk ของผู้ให้บริการทั้งหมด
  • ramdisk_type หมายถึงประเภทของ RAM โดยค่าที่เป็นไปได้มีดังนี้
    • VENDOR_RAMDISK_TYPE_NONE ระบุว่าไม่ได้ระบุค่า
    • RAM ดิสก์ VENDOR_RAMDISK_TYPE_PLATFORM มีบิตเฉพาะแพลตฟอร์ม Bootloader ต้องโหลดรายการเหล่านี้ลงในหน่วยความจำเสมอ
    • แรมดิสก์ VENDOR_RAMDISK_TYPE_RECOVERY รายการมีทรัพยากรการกู้คืน Bootloader ต้องโหลดลงในหน่วยความจำเมื่อเปิดเครื่องในการกู้คืน
    • แรมดิสก์ VENDOR_RAMDISK_TYPE_DLKM รายการมีเคอร์เนลที่โหลดแบบไดนามิกได้ โมดูล
  • ramdisk_name เป็นชื่อที่ไม่ซ้ำกันของ RAM
  • board_id คือเวกเตอร์ของตัวระบุฮาร์ดแวร์ที่ผู้ให้บริการกำหนด

การรองรับ Bootloader

เนื่องจากพาร์ติชันบูตของผู้ให้บริการมีข้อมูล (เช่น ขนาดหน้า Flash เคอร์เนล, ที่อยู่สำหรับโหลด RAM, DTB) ที่เคยมีอยู่ใน พาร์ติชันบูต โดย Bootloader ต้องเข้าถึงทั้งการเปิดเครื่องและผู้ให้บริการในการเปิดเครื่อง พาร์ติชันเพื่อให้มีข้อมูลเพียงพอสำหรับการเปิดเครื่อง

Bootloader ต้องโหลด RAM ดิสก์ทั่วไปลงในหน่วยความจำทันทีหลังจาก ramdisk ของผู้ให้บริการ (รูปแบบ CPIO, Gzip และ lz4 รองรับแท็กประเภทนี้ การเชื่อมต่อ) อย่าจัดหน้าให้สอดคล้องกับรูปภาพ RAM ทั่วไปหรือแทรกรูปภาพ พื้นที่อื่นๆ ระหว่างแท็กและจุดสิ้นสุดของ RAM ของผู้ให้บริการในหน่วยความจำ หลังจาก เคอร์เนลจะแตกข้อมูล และแยกไฟล์ที่เชื่อมต่อกันไว้ใน initramfs ซึ่งทำให้มีโครงสร้างไฟล์แบบ RAM ทั่วไปที่วางซ้อนอยู่บน โครงสร้างไฟล์ ramdisk ของผู้ให้บริการ

เนื่องจาก ramdisk ทั่วไปและ ramdisk ของผู้ให้บริการ ต้องเชื่อมต่อกัน รูปแบบเดียวกัน อิมเมจการเปิดเครื่อง GKI ใช้ RAM ทั่วไปที่บีบอัด lz4 ดังนั้น อุปกรณ์ที่เป็นไปตามข้อกำหนดของ GKI ต้องใช้ RAM ของผู้ให้บริการที่บีบอัด lz4 การกำหนดค่าสำหรับกรณีนี้จะแสดงอยู่ด้านล่าง

ข้อกำหนดของ Bootloader สำหรับการรองรับ Bootconfig มีอยู่ใน ใช้งาน Bootconfig

Ramdisk ของผู้ให้บริการจำนวนมาก (เวอร์ชัน 4)

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

ตัวอย่างเช่น Bootloader สามารถละเว้น RAM ดิสก์ของผู้ให้บริการที่กำลังโหลดประเภท VENDOR_RAMDISK_TYPE_RECOVERY ระหว่างการเปิดเครื่องปกติเพื่อประหยัดทรัพยากร RAM ของผู้ให้บริการประเภท VENDOR_RAMDISK_TYPE_PLATFORM และ ระบบโหลด VENDOR_RAMDISK_TYPE_DLKM ลงในหน่วยความจำ ในขณะที่ผู้ให้บริการ ramdisks ของประเภท VENDOR_RAMDISK_TYPE_PLATFORM, VENDOR_RAMDISK_TYPE_RECOVERY และ VENDOR_RAMDISK_TYPE_DLKM จะโหลดลงในหน่วยความจำเมื่อเปิดเครื่องในการกู้คืน

อีกวิธีหนึ่งคือ Bootloader เพิกเฉยต่อตาราง RAM ของผู้ให้บริการและโหลด Ramdisk ของผู้ให้บริการทั้งหมด ซึ่งจะมีผลเหมือนกับการโหลด Fragment ramdisk ของผู้ให้บริการในพาร์ติชัน vendor_boot

สร้างการสนับสนุน

วิธีใช้การสนับสนุนการเปิดเครื่องของผู้ให้บริการสำหรับอุปกรณ์มีดังนี้

  • ตั้งค่า BOARD_BOOT_HEADER_VERSION เป็น 3 หรือมากกว่า

  • ตั้งค่า BOARD_RAMDISK_USE_LZ4 เป็น true หากอุปกรณ์เป็นไปตามข้อกำหนด GKI หรือหาก มิเช่นนั้นจะใช้ RAM ทั่วไปที่บีบอัด lz4

  • ตั้งค่า BOARD_VENDOR_BOOTIMAGE_PARTITION_SIZE เป็นขนาดที่เหมาะสมสำหรับ โดยพิจารณาโมดูลเคอร์เนลที่ต้องไปอยู่บน RAM ของผู้ให้บริการ

  • อัปเดต AB_OTA_PARTITIONS ให้รวม vendor_boot และผู้ให้บริการที่เฉพาะเจาะจง รายการพาร์ติชัน OTA ในอุปกรณ์

  • คัดลอกอุปกรณ์ fstab ไปยัง /first_stage_ramdisk ในvendor_boot พาร์ติชัน ไม่ใช่พาร์ติชัน boot ตัวอย่างเช่น $(LOCAL_PATH)/fstab.hardware:$(TARGET_COPY_OUT_VENDOR_RAMDISK)/first_stage_ramdisk/fstab.$(PRODUCT_PLATFORM).

วิธีรวม RAM ของผู้ให้บริการหลายรายการใน vendor_boot

  • ตั้งค่า BOARD_BOOT_HEADER_VERSION เป็น 4
  • ตั้งค่า BOARD_VENDOR_RAMDISK_FRAGMENTS เป็นรายการ RAM ของผู้ให้บริการเชิงตรรกะ ชื่อส่วนย่อยที่จะรวมอยู่ใน vendor_boot

  • หากต้องการเพิ่ม RAM ของผู้ให้บริการที่สร้างไว้ล่วงหน้า ให้ตั้งค่า BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).PREBUILT ไปยังรายชื่อที่สร้างไว้ล่วงหน้า เส้นทาง

  • หากต้องการเพิ่ม ramdisk ผู้ให้บริการ DLKM ให้ตั้งค่า BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).KERNEL_MODULE_DIRS เป็น รายการไดเรกทอรีโมดูลเคอร์เนลที่จะรวม

  • ตั้ง BOARD_VENDOR_RAMDISK_FRAGMENT.$(vendor_ramdisk).MKBOOTIMG_ARGS เป็น mkbootimg อาร์กิวเมนต์ ต่อไปนี้คือ--board_id[0-15]และ--ramdisk_type อาร์กิวเมนต์สำหรับ Fragment ramdisk ของผู้ให้บริการ สำหรับ ramdisk ของผู้ให้บริการ DLKM นั้น ค่าเริ่มต้น --ramdisk_type จะเป็น DLKM หากไม่ได้ระบุไว้เป็นอย่างอื่น

วิธีสร้างทรัพยากรการกู้คืนเป็น RAM ดิสก์ recovery แบบสแตนด์อโลนใน vendor_boot:

  • ตั้งค่า BOARD_BOOT_HEADER_VERSION เป็น 4
  • ตั้งค่า BOARD_MOVE_RECOVERY_RESOURCES_TO_VENDOR_BOOT เป็น true
  • ตั้งค่า BOARD_INCLUDE_RECOVERY_RAMDISK_IN_VENDOR_BOOT เป็น true
  • การดำเนินการนี้จะเพิ่มส่วนย่อย RAM ของผู้ให้บริการซึ่งมี ramdisk_name เท่ากับ recovery และ ramdisk_type คือ VENDOR_RAMDISK_TYPE_RECOVERY จากนั้น ramdisk จะมี ไฟล์การกู้คืนทั้งหมด ซึ่งเป็นไฟล์ที่ติดตั้งใน $(TARGET_RECOVERY_ROOT_OUT).

อาร์กิวเมนต์ mkbootimg

อาร์กิวเมนต์ คำอธิบาย
--ramdisk_type ประเภทของ RAM อาจเป็น NONE PLATFORM, RECOVERY หรือ DLKM
--board_id[0-15] ระบุเวกเตอร์ board_id ค่าเริ่มต้นคือ 0

ตัวอย่างการกำหนดค่ามีดังนี้

BOARD_KERNEL_MODULE_DIRS := foo bar baz
BOARD_BOOT_HEADER_VERSION := 4
BOARD_VENDOR_RAMDISK_FRAGMENTS := dlkm_foobar
BOARD_VENDOR_RAMDISK_FRAGMENT.dlkm_foobar.KERNEL_MODULE_DIRS := foo bar
BOARD_VENDOR_RAMDISK_FRAGMENT.dlkm_foobar.MKBOOTIMG_ARGS := --board_id0 0xF00BA5 --board_id1 0xC0FFEE

vendor_boot ที่ได้จะมี Fragment ramdisk ของผู้ให้บริการ 2 รายการ รายการแรกคือ "ค่าเริ่มต้น" ramdisk ซึ่งมีไดเรกทอรี DLKM baz และ ไฟล์ที่เหลือใน $(TARGET_VENDOR_RAMDISK_OUT) อย่างที่ 2 คือ dlkm_foobar ramdisk ซึ่งมีไดเรกทอรี DLKM foo และ bar และ --ramdisk_type จะมีค่าเริ่มต้นเป็น DLKM