เลย์เอาต์พาร์ติชัน

ใน Android 10 ระบบไฟล์รูทจะไม่รวมอยู่ใน ramdisk.img อีกต่อไป แต่รวมอยู่ใน system.img แทน (กล่าวคือ ระบบจะสร้าง system.img เป็นไฟล์รูทเสมอหากมีการตั้งค่า BOARD_BUILD_SYSTEM_ROOT_IMAGE) อุปกรณ์ที่เปิดตัวพร้อม Android 10

  • ใช้เลย์เอาต์พาร์ติชันระบบเป็นรูท (บิลด์บังคับใช้โดยอัตโนมัติโดยไม่มีตัวเลือกในการเปลี่ยนลักษณะการทำงาน)
  • ต้องใช้ RAM disk ซึ่งจำเป็นสำหรับ dm-linear
  • ต้องตั้งค่า BOARD_BUILD_SYSTEM_ROOT_IMAGE เป็น false การตั้งค่านี้ใช้เพื่อแยกความแตกต่างระหว่างอุปกรณ์ที่ใช้แรมดิสก์กับอุปกรณ์ที่ไม่ใช้แรมดิสก์ (และต่อเชื่อม system.img โดยตรงแทน) เท่านั้น

ความหมายของการกําหนดค่าระบบเป็นรูทจะแตกต่างกันระหว่าง Android 9 กับ Android 10 ในการกำหนดค่าระบบเป็นรูทของ Android 9 ระบบจะตั้งค่า BOARD_BUILD_SYSTEM_ROOT_IMAGE เป็น true ซึ่งจะบังคับให้บิลด์ผสานระบบไฟล์รูทเข้ากับ system.img แล้วต่อเชื่อม system.img เป็นระบบไฟล์รูท (rootfs) การกำหนดค่านี้จำเป็นสำหรับอุปกรณ์ที่เปิดตัวด้วย Android 9 แต่ไม่จำเป็นสำหรับอุปกรณ์ที่อัปเกรดเป็น Android 9 และอุปกรณ์ที่ใช้ Android เวอร์ชันที่ต่ำกว่า ในการกำหนดค่าระบบเป็นรูทของ Android 10 บิลด์จะผสาน $TARGET_SYSTEM_OUT และ $TARGET_ROOT_OUT เข้ากับ system.img เสมอ การกำหนดค่านี้เป็นลักษณะการทำงานเริ่มต้นสำหรับอุปกรณ์ทั้งหมดที่ใช้ Android 10

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

ส่วนต่อไปนี้จะอธิบายข้อกำหนดของ "ระบบเป็นรูท" สำหรับ OTA สำหรับระบบเท่านั้น รวมถึงให้คำแนะนำเกี่ยวกับการอัปเดตอุปกรณ์ให้ใช้ "ระบบเป็นรูท" (รวมถึงการเปลี่ยนแปลงเลย์เอาต์พาร์ติชันและข้อกำหนดของเคอร์เนล dm-verity) ดูรายละเอียดเกี่ยวกับการเปลี่ยนแปลงใน RAM Disk ได้ที่พาร์ติชัน RAM Disk

เกี่ยวกับการอัปเดตระบบผ่านอากาศ (OTA) สำหรับระบบเท่านั้น

OTA สำหรับระบบเท่านั้น ซึ่งช่วยให้อัปเดต Android เวอร์ชัน system.img และ product.img ได้โดยไม่ต้องเปลี่ยนพาร์ติชันอื่นๆ ต้องใช้เลย์เอาต์พาร์ติชันระบบเป็นรูท อุปกรณ์ทั้งหมดที่ใช้ Android 10 ต้องใช้เลย์เอาต์พาร์ติชันระบบเป็นรูทเพื่อเปิดใช้ OTA สำหรับระบบเท่านั้น

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

โปรดดูรายละเอียดเกี่ยวกับอุปกรณ์ A/B และอุปกรณ์ที่ไม่ใช่ A/B ที่หัวข้อการอัปเดตระบบ A/B (ต่อเนื่อง)

ใช้การซ้อนทับของผู้ให้บริการ (<=AOSP 14)

การซ้อนทับของผู้ให้บริการช่วยให้คุณวางซ้อนการเปลี่ยนแปลงลงในvendor พาร์ติชันได้เมื่ออุปกรณ์บูต การซ้อนทับของผู้ให้บริการคือชุดโมดูลของผู้ให้บริการในพาร์ติชัน product ที่วางซ้อนทับบนพาร์ติชัน vendor เมื่ออุปกรณ์บูต โดยแทนที่และเพิ่มลงในโมดูลที่มีอยู่

เมื่ออุปกรณ์บูตขึ้น กระบวนการ init จะทำการต่อเชื่อมระยะแรกจนเสร็จสมบูรณ์และอ่านพร็อพเพอร์ตี้เริ่มต้น จากนั้นจะค้นหา /product/vendor_overlay/<target_vendor_version> และต่อเชื่อม ไดเรกทอรีย่อยแต่ละรายการในไดเรกทอรีพาร์ติชัน vendor ที่เกี่ยวข้อง หากเป็นไปตามเงื่อนไขต่อไปนี้

  • มี /vendor/<overlay_dir> อยู่แล้ว
  • /product/vendor_overlay/<target_vendor_version>/<overlay_dir> มีบริบทไฟล์เดียวกับ /vendor/<overlay_dir>
  • init ได้รับอนุญาตให้มาสก์ในบริบทไฟล์ของ /vendor/<overlay_dir>

ใช้การซ้อนทับของผู้ให้บริการ

ติดตั้งไฟล์การวางซ้อนของผู้ให้บริการใน /product/vendor_overlay/<target_vendor_version> ไฟล์เหล่านั้นจะวางซ้อนทับพาร์ติชัน vendor เมื่ออุปกรณ์บูต โดยแทนที่ไฟล์ที่มีชื่อเดียวกันและเพิ่มไฟล์ใหม่ การวางซ้อนของผู้ให้บริการนำไฟล์ออกจากพาร์ติชัน vendor ไม่ได้

ไฟล์การวางซ้อนของผู้ให้บริการต้องมีบริบทไฟล์เดียวกับไฟล์เป้าหมายที่จะแทนที่ในพาร์ติชัน vendor โดยค่าเริ่มต้น ไฟล์ในไดเรกทอรี /product/vendor_overlay/<target_vendor_version> จะมีบริบท vendor_file หากบริบทของไฟล์ไม่ตรงกันระหว่างไฟล์การวางซ้อนของผู้ให้บริการกับไฟล์ที่แทนที่ ให้ระบุไว้ในนโยบายความปลอดภัยเฉพาะอุปกรณ์ บริบทของไฟล์จะตั้งค่าที่ระดับไดเรกทอรี หากบริบทไฟล์ของไดเรกทอรีการวางซ้อนของผู้ให้บริการไม่ตรงกับไดเรกทอรีเป้าหมาย และไม่ได้ระบุบริบทไฟล์ที่ถูกต้องใน sepolicy สำหรับอุปกรณ์โดยเฉพาะ ไดเรกทอรีการวางซ้อนของผู้ให้บริการดังกล่าวจะไม่วางซ้อนกับไดเรกทอรีเป้าหมาย

หากต้องการใช้การวางซ้อนของผู้ให้บริการ เคอร์เนลต้องเปิดใช้ OverlayFS โดยการตั้งค่า CONFIG_OVERLAY_FS=y นอกจากนี้ ต้องผสานเคอร์เนลจากเคอร์เนลทั่วไป 4.4 ขึ้นไป หรือแก้ไขด้วย "overlayfs: override_creds=off option bypass creator_cred"

ตัวอย่างการใช้งานการวางซ้อนของผู้ให้บริการ

ขั้นตอนนี้แสดงการใช้การวางซ้อนของผู้ให้บริการที่วางซ้อนไดเรกทอรี /vendor/lib/*, /vendor/etc/* และ /vendor/app/*

  1. เพิ่มไฟล์ผู้ให้บริการที่สร้างไว้ล่วงหน้าใน device/<vendor>/<target>/vendor_overlay/<target_vendor_version>/

    device/google/device/vendor_overlay/28/lib/libfoo.so
    device/google/device/vendor_overlay/28/lib/libbar.so
    device/google/device/vendor_overlay/28/etc/baz.xml
    device/google/device/vendor_overlay/28/app/qux.apk
  2. ติดตั้งไฟล์ผู้ให้บริการที่สร้างไว้ล่วงหน้าใน product/vendor_overlay ใน device/google/device/device.mk

    PRODUCT_COPY_FILES += \
        $(call find-copy-subdir-files,*,device/google/device/vendor_overlay,$(TARGET_COPY_OUT_PRODUCT)/vendor_overlay)
  3. กำหนดบริบทของไฟล์หากไฟล์พาร์ติชัน vendor เป้าหมายมีบริบทอื่นนอกเหนือจาก vendor_file เนื่องจาก /vendor/lib/* ใช้บริบท vendor_file ตัวอย่างนี้จึงไม่มีไดเรกทอรีนั้น

    เพิ่มข้อมูลต่อไปนี้ลงใน device/google/device-sepolicy/private/file_contexts

    /(product|system/product)/vendor_overlay/[0-9]+/etc(/.*)?   u:object_r:vendor_configs_file:s0
    /(product|system/product)/vendor_overlay/[0-9]+/app(/.*)?   u:object_r:vendor_app_file:s0
  4. อนุญาตให้กระบวนการ init วางซ้อนผู้ให้บริการในบริบทไฟล์อื่นๆ นอกเหนือจาก vendor_file เนื่องจากinit กระบวนการมีสิทธิ์ในการต่อเชื่อมในบริบท vendor_file อยู่แล้ว ตัวอย่างนี้จึงไม่กำหนดนโยบายสำหรับ vendor_file

    เพิ่มข้อมูลต่อไปนี้ลงใน device/google/device-sepolicy/public/init.te

    allow init vendor_configs_file:dir mounton;
    allow init vendor_app_file:dir mounton;

ตรวจสอบการวางซ้อนของผู้ให้บริการ

หากต้องการตรวจสอบการกําหนดค่าการวางซ้อนของผู้ให้บริการ ให้เพิ่มไฟล์ใน /product/vendor_overlay/<target_vendor_version>/<overlay_dir> แล้วตรวจสอบว่าไฟล์วางซ้อนบนไฟล์ใน /vendor/<overlay_dir> หรือไม่

สำหรับบิลด์ userdebug จะมีโมดูลทดสอบสำหรับ Atest ดังนี้

$ atest -v fs_mgr_vendor_overlay_test

อัปเดตเป็นระบบในฐานะรูท

หากต้องการอัปเดตอุปกรณ์ที่ไม่ใช่ A/B ให้ใช้ระบบเป็นรูท คุณต้องอัปเดตรูปแบบการแบ่งพาร์ติชันสำหรับ boot.img และ system.img, ตั้งค่า dm-verity และนำการพึ่งพาการบูตทั้งหมดในโฟลเดอร์รูทเฉพาะอุปกรณ์ออก

อัปเดตพาร์ติชัน

ซึ่งแตกต่างจากอุปกรณ์ A/B ที่ใช้ /boot เป็นพาร์ติชันการกู้คืน อุปกรณ์ที่ไม่ใช่ A/B ต้องแยกพาร์ติชัน /recovery ไว้ต่างหากเนื่องจากไม่มีพาร์ติชันสล็อตสำรอง (เช่น จาก boot_a เป็น boot_b) หากนำ /recovery ออกจากอุปกรณ์ที่ไม่ใช่ A/B และทำให้คล้ายกับรูปแบบ A/B โหมดการกู้คืนอาจใช้งานไม่ได้ระหว่างการอัปเดตพาร์ติชัน /boot ที่ไม่สำเร็จ ด้วยเหตุนี้ พาร์ติชัน /recovery ต้องเป็นพาร์ติชันแยกต่างหากจาก /boot สำหรับอุปกรณ์ที่ไม่ใช่ A/B ซึ่งหมายความว่าระบบจะอัปเดตอิมเมจการกู้คืนต่อไปในลักษณะที่เลื่อนเวลาไว้ (เช่นเดียวกับในอุปกรณ์ที่ใช้ Android 8.1.0 หรือต่ำกว่า)

ตารางต่อไปนี้แสดงความแตกต่างของพาร์ติชันรูปภาพสำหรับอุปกรณ์ที่ไม่ใช่ A/B ก่อนและหลัง Android 9

รูปภาพ แรมดิสก์ (ก่อนเวอร์ชัน 9) ระบบเป็นรูท (หลังจาก 9)
boot.img มีเคอร์เนลและramdisk.img
ramdisk.img
  -/
    - init.rc
    - init
    - etc -> /system/etc
    - system/ (mount point)
    - vendor/ (mount point)
    - odm/ (mount point)
    ...
มีเฉพาะเคอร์เนลการบูตปกติเท่านั้น
recovery.img มีเคอร์เนลการกู้คืนและไฟล์การกู้คืน ramdisk.img
system.img มีข้อมูลต่อไปนี้
system.img
  -/
    - bin/
    - etc
    - vendor -> /vendor
    - ...
มีเนื้อหาที่ผสานระหว่าง system.img ต้นฉบับและ ramdisk.img
system.img
  -/
    - init.rc
    - init
    - etc -> /system/etc
    - system/
      - bin/
      - etc/
      - vendor -> /vendor
      - ...
    - vendor/ (mount point)
    - odm/ (mount point)
    ...

ส่วนพาร์ติชันเองจะไม่มีการเปลี่ยนแปลง ทั้ง RAM Disk และระบบที่ใช้สิทธิ์รูทจะใช้รูปแบบพาร์ติชันต่อไปนี้

  • /boot
  • /system
  • /system
  • /recovery
  • /vendor ฯลฯ

ตั้งค่า dm-verity

ในระบบที่ใช้รูท เคอร์เนลต้องเมานต์ system.img ภายใต้ / (จุดเมานต์) ด้วย dm-verity AOSP รองรับการใช้งาน dm-verity ต่อไปนี้สําหรับ system.img

vboot 1.0

สำหรับ vboot 1.0 เคอร์เนลต้องแยกวิเคราะห์ข้อมูลเมตาสำหรับ Android โดยเฉพาะใน /system จากนั้นแปลงเป็น dm-verity params เพื่อตั้งค่า dm-verity (ต้องใช้แพตช์เคอร์เนลเหล่านี้) ตัวอย่างต่อไปนี้แสดงการตั้งค่าที่เกี่ยวข้องกับ dm-verity สำหรับระบบในฐานะรูทในบรรทัดคำสั่งเคอร์เนล

ro root=/dev/dm-0 rootwait skip_initramfs init=/init
dm="system none ro,0 1 android-verity /dev/sda34"
veritykeyid=id:7e4333f9bba00adfe0ede979e28ed1920492b40f

vboot 2.0

สำหรับ vboot 2.0 (AVB) บูตโหลดเดอร์ต้องผสานรวม external/avb/libavb ซึ่งจะแยกวิเคราะห์ ตัวบ่งชี้ hashtree สำหรับ /system จากนั้นแปลงเป็น dm-verity params และสุดท้ายส่งพารามิเตอร์ไปยังเคอร์เนลผ่านบรรทัดคำสั่งของเคิร์นัล (ตัวบ่งชี้ Hashtree ของ /system อาจอยู่ใน /vbmeta หรือใน /system เอง)

vboot 2.0 ต้องใช้แพตช์เคอร์เนลต่อไปนี้

ตัวอย่างต่อไปนี้แสดงการตั้งค่าที่เกี่ยวข้องกับ dm-verity สำหรับระบบในฐานะรูทในบรรทัดคำสั่งเคอร์เนล

ro root=/dev/dm-0 rootwait  skip_initramfs init=/init

dm="1 vroot none ro 1,0 5159992 verity 1
PARTUUID=00000016-0000-0000-0000-000000000000
PARTUUID=00000016-0000-0000-0000-000000000000 4096 4096 644999 644999
sha1 d80b4a8be3b58a8ab86fad1b498640892d4843a2
8d08feed2f55c418fb63447fec0d32b1b107e42c 10 restart_on_corruption
ignore_zero_blocks use_fec_from_device
PARTUUID=00000016-0000-0000-0000-000000000000 fec_roots 2 fec_blocks
650080 fec_start 650080"

ใช้โฟลเดอร์รูทเฉพาะอุปกรณ์

เมื่อใช้ระบบเป็นรูท หลังจากแฟลช System Image ทั่วไป (GSI) ในอุปกรณ์ (และก่อนทำการทดสอบ Vendor Test Suite) โฟลเดอร์รูทเฉพาะอุปกรณ์ที่เพิ่มด้วย BOARD_ROOT_EXTRA_FOLDERS จะหายไปเนื่องจากเนื้อหาไดเรกทอรีรูททั้งหมดถูกแทนที่ด้วย GSI ของระบบเป็นรูท การนําโฟลเดอร์เหล่านี้ออกอาจทําให้อุปกรณ์บูตไม่ได้หากมีการใช้งานโฟลเดอร์รูทเฉพาะอุปกรณ์ (เช่น ใช้เป็นแหล่งมาунт)

หากต้องการหลีกเลี่ยงปัญหานี้ อย่าใช้ BOARD_ROOT_EXTRA_FOLDERS เพื่อเพิ่มโฟลเดอร์รูทเฉพาะอุปกรณ์ หากต้องการระบุจุดยึดเฉพาะอุปกรณ์ ให้ใช้ /mnt/vendor/<mount point> (เพิ่มในรายการการเปลี่ยนแปลงเหล่านี้) คุณระบุจุดมานต์เฉพาะของผู้ให้บริการเหล่านี้ได้โดยตรงทั้งในfstab Device Tree (สำหรับการมานต์ระยะแรก) และไฟล์ /vendor/etc/fstab.{ro.hardware} โดยไม่ต้องตั้งค่าเพิ่มเติม (เนื่องจาก fs_mgr จะสร้างจุดมานต์เหล่านี้ใน /mnt/vendor/* โดยอัตโนมัติ)