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

OEM และผู้ให้บริการ SoC ที่ต้องการใช้การอัปเดตระบบ A/B ต้องตรวจสอบว่าโปรแกรมโหลดระบบ ใช้ 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 (วิทยุ ตัวโหลดโปรแกรม ฯลฯ)
  • 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 updates are applied by update_engine running in the regular booted system image. แต่ก็ยังมีโหมดการกู้คืนที่ใช้เพื่อรีเซ็ตข้อมูลเป็นค่าเริ่มต้นและโหลดแพ็กเกจการอัปเดตด้านข้าง (ซึ่งเป็นที่มาของชื่อ "การกู้คืน") โค้ดและข้อมูลสำหรับโหมดการกู้คืน จะจัดเก็บไว้ในพาร์ติชันการบูตปกติใน Ramdisk เพื่อบูตเข้าสู่รูปภาพระบบ Bootloader จะบอกเคอร์เนลให้ข้าม Ramdisk (มิฉะนั้นอุปกรณ์จะบูตเข้าสู่โหมดการกู้คืน โหมดการกู้คืนมีขนาดเล็ก (และส่วนใหญ่ก็อยู่ในพาร์ติชันการบูตอยู่แล้ว) ดังนั้นพาร์ติชันการบูตจึงไม่เพิ่มขนาด

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เมานต์พอยต์แทน

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

ควรส่งต่อคำต่อท้ายของสล็อตปัจจุบันผ่านโหนด Device Tree (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 ในการบูตครั้งแรก