ใช้การอัปเดต A/B

OEM และผู้ให้บริการ SoC ที่ต้องการใช้การอัปเดตระบบ A/B ต้องตรวจสอบว่า Bootloader ใช้ HAL ของ boot_control และส่งพารามิเตอร์ที่ถูกต้องไปยัง เคอร์เนล

ใช้ HAL การควบคุมการบูต

Bootloader ที่ใช้ A/B ได้ต้องใช้ HAL ของ boot_control ที่ hardware/libhardware/include/hardware/boot_control.h คุณทดสอบการติดตั้งใช้งานได้โดยใช้ยูทิลิตี system/extras/bootctl และ system/extras/tests/bootloader/

นอกจากนี้ คุณยังต้องใช้เครื่องสถานะที่แสดงด้านล่างด้วย

รูปที่ 1 เครื่องสถานะของ Bootloader

ตั้งค่าเคอร์เนล

วิธีใช้การอัปเดตระบบ A/B

  1. เลือกแพตช์เคอร์เนลชุดต่อไปนี้ (หากจำเป็น)
  2. ตรวจสอบว่าอาร์กิวเมนต์บรรทัดคำสั่งของเคอร์เนลมีอาร์กิวเมนต์เพิ่มเติมต่อไปนี้
    skip_initramfs rootwait ro init=/init root="/dev/dm-0 dm=system none ro,0 1 android-verity <public-key-id> <path-to-system-partition>"
    ... โดยที่ค่า <public-key-id> คือรหัสของคีย์สาธารณะที่ใช้เพื่อ ยืนยันลายเซ็นตารางความถูกต้อง (ดูรายละเอียดได้ที่ dm-verity)
  3. เพิ่มใบรับรอง .X509 ที่มีคีย์สาธารณะลงในคีย์ริงระบบ
    1. คัดลอกใบรับรอง .X509 ที่จัดรูปแบบในรูปแบบ .der ไปยังรูทของไดเรกทอรี kernel หากใบรับรอง .X509 จัดรูปแบบเป็นไฟล์ .pem ให้ใช้คำสั่ง openssl ต่อไปนี้เพื่อแปลงจาก .pem เป็นรูปแบบ .der
      openssl x509 -in <x509-pem-certificate> -outform der -out <x509-der-certificate>
    2. สร้าง zImage เพื่อรวมใบรับรองเป็นส่วนหนึ่งของคีย์ริงระบบ หากต้องการยืนยัน ให้ตรวจสอบรายการ procfs (ต้องเปิดใช้ KEYS_CONFIG_DEBUG_PROC_KEYS):
      angler:/# cat /proc/keys
      
      1c8a217e I------     1 perm 1f010000     0     0 asymmetri
      Android: 7e4333f9bba00adfe0ede979e28ed1920492b40f: X509.RSA 0492b40f []
      2d454e3e I------     1 perm 1f030000     0     0 keyring
      .system_keyring: 1/4
      การรวมใบรับรอง .X509 สำเร็จแสดงว่ามีคีย์สาธารณะในคีย์ริงระบบ (ไฮไลต์จะระบุรหัสคีย์สาธารณะ)
    3. แทนที่ช่องว่างด้วย # แล้วส่งเป็น <public-key-id> ในบรรทัดคำสั่งของเคอร์เนล เช่น ส่ง Android:#7e4333f9bba00adfe0ede979e28ed1920492b40f แทน <public-key-id>

ตั้งค่าตัวแปรบิลด์

Bootloader ที่ใช้ A/B ได้ต้องเป็นไปตามเกณฑ์ตัวแปรบิลด์ต่อไปนี้

ต้องนิยามเป้าหมาย A/B
  • AB_OTA_UPDATER := true
  • AB_OTA_PARTITIONS := \
      boot \
      system \
      vendor
    และพาร์ติชันอื่นๆ ที่อัปเดตผ่าน update_engine (วิทยุ, Bootloader และอื่นๆ)
  • PRODUCT_PACKAGES += \
      update_engine \
      update_verifier
ดูตัวอย่างได้ที่ /device/google/marlin/+/android-7.1.0_r1/device-common.mk คุณเลือกที่จะทำขั้นตอน dex2oat หลังการติดตั้ง (แต่ก่อนการรีบูต) ที่อธิบายไว้ใน การคอมไพล์ได้
ขอแนะนำอย่างยิ่งสำหรับเป้าหมาย A/B
  • นิยาม TARGET_NO_RECOVERY := true
  • นิยาม BOARD_USES_RECOVERY_AS_BOOT := true
  • อย่านิยาม BOARD_RECOVERYIMAGE_PARTITION_SIZE
นิยามเป้าหมาย A/B ไม่ได้
  • BOARD_CACHEIMAGE_PARTITION_SIZE
  • BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE
ไม่บังคับสำหรับบิลด์การแก้ไขข้อบกพร่อง PRODUCT_PACKAGES_DEBUG += update_engine_client

ตั้งค่าพาร์ติชัน (สล็อต)

อุปกรณ์ A/B ไม่จำเป็นต้องมีพาร์ติชันการกู้คืนหรือพาร์ติชันแคช เนื่องจาก Android ไม่ได้ใช้พาร์ติชันเหล่านี้อีกต่อไป ตอนนี้พาร์ติชันข้อมูลจะใช้สำหรับแพ็กเกจ OTA ที่ดาวน์โหลด และ โค้ดอิมเมจการกู้คืนจะอยู่ในพาร์ติชันการบูต พาร์ติชันทั้งหมดที่ใช้การทดสอบ A/B ควรมีชื่อดังนี้ (สล็อตจะมีชื่อเป็น a, b ฯลฯ เสมอ) boot_a, boot_b, system_a, system_b, vendor_a, vendor_b

แคช

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

การกู้คืน

ตอนนี้ดิสก์ RAM สำหรับการกู้คืนอยู่ในไฟล์ boot.img แล้ว เมื่อเข้าสู่โหมดการกู้คืน Bootloader จะไม่สามารถใส่ตัวเลือก skip_initramfs ในบรรทัดคำสั่งของเคอร์เนลได้

สำหรับการอัปเดตที่ไม่ใช่ A/B พาร์ติชันการกู้คืนจะมีโค้ดที่ใช้ในการใช้การอัปเดต การอัปเดตแบบ A/B จะใช้โดย update_engine ที่กำลังทำงานในอิมเมจระบบที่บูตแบบปกติ แต่ก็ยังมี Recovery Mode ที่ใช้เพื่อรีเซ็ตข้อมูลเป็นค่าเริ่มต้นและไซด์โหลดแพ็กเกจการอัปเดต (ซึ่งเป็นที่มาของชื่อ "Recovery") โค้ดและข้อมูลสำหรับ Recovery Mode จะจัดเก็บไว้ในพาร์ติชันการบูตแบบปกติใน Ramdisk เพื่อบูตเข้าสู่อิมเมจระบบ โดย Bootloader จะบอกเคอร์เนลให้ข้าม Ramdisk (มิฉะนั้นอุปกรณ์จะบูตเข้าสู่ Recovery Mode Recovery Mode มีขนาดเล็ก (และส่วนใหญ่ก็อยู่ในพาร์ติชันการบูตอยู่แล้ว) ดังนั้นพาร์ติชันการบูตจึงไม่เพิ่มขนาด

Fstab

อาร์กิวเมนต์ slotselect ต้องอยู่ในบรรทัดสำหรับพาร์ติชันที่ทำการทดสอบ A/B เช่น

<path-to-block-device>/vendor  /vendor  ext4  ro
wait,verify=<path-to-block-device>/metadata,slotselect

ไม่ควรตั้งชื่อพาร์ติชันว่า vendor โดยระบบจะเลือกและติดตั้งพาร์ติชัน vendor_a หรือ vendor_b ในจุดต่อเชื่อม /vendor แทน

อาร์กิวเมนต์ของสล็อตเคอร์เนล

ควรส่งต่อคำต่อท้ายของสล็อตปัจจุบันผ่านโหนดแผนผังอุปกรณ์ (DT) ที่เฉพาะเจาะจง (/firmware/android/slot_suffix) หรือผ่านบรรทัดคำสั่งเคอร์เนล androidboot.slot_suffix หรืออาร์กิวเมนต์ bootconfig

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

  • --slot SLOT ลบล้างลักษณะการทำงานเริ่มต้นและแจ้งให้ Fastboot แฟลชสล็อตที่ส่งผ่านเป็นอาร์กิวเมนต์
  • --set-active [SLOT] ตั้งค่าสล็อตเป็นใช้งานอยู่ หากไม่ได้ระบุอาร์กิวเมนต์ที่ไม่บังคับ ระบบจะตั้งค่าสล็อตปัจจุบันเป็นใช้งานอยู่
  • fastboot --help ดูรายละเอียดเกี่ยวกับคำสั่ง

หาก Bootloader ใช้ Fastboot ก็ควรจะรองรับคำสั่ง set_active <slot> ที่ตั้งค่าสล็อตที่ใช้งานอยู่ปัจจุบันเป็นสล็อตที่ระบุ (คำสั่งนี้ต้องล้างแฟล็กที่บูตไม่ได้สำหรับสล็อตนั้นและรีเซ็ตจำนวนครั้งที่ลองใหม่เป็นค่าเริ่มต้นด้วย) นอกจากนี้ Bootloader ควรจะรองรับตัวแปรต่อไปนี้ด้วย

  • has-slot:<partition-base-name-without-suffix> แสดงผล "yes" หากพาร์ติชันที่ระบุรองรับสล็อต และแสดงผล "no" ในกรณีอื่นๆ
  • current-slot. แสดงผลคำต่อท้ายสล็อตที่จะเริ่มต้นบูตในครั้งถัดไป
  • slot-count แสดงผลจำนวนสล็อตว่างในรูปแบบจำนวนเต็ม ปัจจุบันรองรับ 2 สล็อต ดังนั้นค่านี้จึงเป็น 2
  • slot-successful:<slot-suffix> แสดงผล "yes" หากมีการทำเครื่องหมายว่าสล็อตที่ระบุ บูตสำเร็จ หรือ "no" ในกรณีอื่นๆ
  • slot-unbootable:<slot-suffix> แสดงผล "yes" หากมีการทำเครื่องหมายว่าสล็อตที่ระบุ บูตไม่ได้ และแสดงผล "no" ในกรณีอื่นๆ
  • slot-retry-count:<slot-suffix> จำนวนการลองใหม่ที่เหลืออยู่เพื่อพยายามบูตสล็อตที่ระบุ

หากต้องการดูตัวแปรทั้งหมด ให้เรียกใช้ fastboot getvar all

สร้างแพ็กเกจ OTA

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

ตัวอย่าง

  • วิธีสร้าง OTA แบบเต็ม
    ./build/make/tools/releasetools/ota_from_target_files \
        dist_output/tardis-target_files.zip \
        ota_update.zip
    
  • วิธีสร้าง OTA แบบเพิ่ม
    ./build/make/tools/releasetools/ota_from_target_files \
        -i PREVIOUS-tardis-target_files.zip \
        dist_output/tardis-target_files.zip \
        incremental_ota_update.zip
    

กำหนดค่าพาร์ติชัน

update_engine สามารถอัปเดตพาร์ติชัน A/B คู่ใดก็ได้ที่กำหนดไว้ในดิสก์เดียวกัน พาร์ติชัน 2 รายการจะมีคำนำหน้าร่วมกัน (เช่น system หรือ boot) และคำต่อท้ายต่อสล็อต (เช่น _a) รายการพาร์ติชันที่เครื่องมือสร้างเพย์โหลดกำหนดการอัปเดตจะได้รับการกำหนดค่าโดยตัวแปร AB_OTA_PARTITIONS

ตัวอย่างเช่น หากมีพาร์ติชันคู่ bootloader_a และ booloader_b (_a และ _b เป็นคำต่อท้ายของสล็อต ) คุณสามารถอัปเดตพาร์ติชันเหล่านี้ได้โดยระบุข้อมูลต่อไปนี้ในการกำหนดค่าผลิตภัณฑ์หรือบอร์ด

AB_OTA_PARTITIONS := \
  boot \
  system \
  bootloader

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

กำหนดค่าหลังการติดตั้ง

คุณสามารถกำหนดค่าขั้นตอนหลังการติดตั้งที่แตกต่างกันสำหรับแต่ละพาร์ติชันที่อัปเดตได้โดยใช้ชุด คู่คีย์-ค่า หากต้องการเรียกใช้โปรแกรมที่อยู่ใน /system/usr/bin/postinst ในอิมเมจใหม่ ให้ระบุเส้นทางที่สัมพันธ์กับรูทของระบบไฟล์ในพาร์ติชันของระบบ

เช่น usr/bin/postinst คือ system/usr/bin/postinst (หากไม่ได้ ใช้ RAM Disk) นอกจากนี้ ให้ระบุประเภทระบบไฟล์ที่จะส่งไปยัง mount(2) การเรียกใช้ระบบ เพิ่มข้อมูลต่อไปนี้ลงในไฟล์ .mk ของผลิตภัณฑ์หรืออุปกรณ์ (หากมี)

AB_OTA_POSTINSTALL_CONFIG += \
  RUN_POSTINSTALL_system=true \
  POSTINSTALL_PATH_system=usr/bin/postinst \
  FILESYSTEM_TYPE_system=ext4

คอมไพล์แอป

แอปสามารถคอมไพล์ในเบื้องหลังก่อนการรีบูตด้วยอิมเมจระบบใหม่ หากต้องการคอมไพล์ แอปในเบื้องหลัง ให้เพิ่มข้อมูลต่อไปนี้ลงในการกำหนดค่าอุปกรณ์ของผลิตภัณฑ์ (ใน device.mk ของผลิตภัณฑ์)

  1. รวมคอมโพเนนต์ดั้งเดิมไว้ในการสร้างเพื่อให้แน่ใจว่าสคริปต์การคอมไพล์และไบนารีจะได้รับการคอมไพล์และรวมไว้ในอิมเมจระบบ
      # A/B OTA dexopt package
      PRODUCT_PACKAGES += otapreopt_script
    
  2. เชื่อมต่อสคริปต์การคอมไพล์กับ update_engine เพื่อให้ทำงานเป็น ขั้นตอนหลังการติดตั้ง
      # A/B OTA dexopt update_engine hookup
      AB_OTA_POSTINSTALL_CONFIG += \
        RUN_POSTINSTALL_system=true \
        POSTINSTALL_PATH_system=system/bin/otapreopt_script \
        FILESYSTEM_TYPE_system=ext4 \
        POSTINSTALL_OPTIONAL_system=true
    

หากต้องการความช่วยเหลือในการติดตั้งไฟล์ที่ผ่านการเพิ่มประสิทธิภาพล่วงหน้าในพาร์ติชันระบบที่ 2 ที่ไม่ได้ใช้ โปรดดู การติดตั้งไฟล์ DEX_PREOPT ในการบูตครั้งแรก