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

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

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

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

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

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

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

หากต้องการใช้การอัปเดตระบบ A/B:

  1. Cherrypick ชุดแพทช์เคอร์เนลต่อไปนี้ (หากจำเป็น):
  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> คือ 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 ได้สำเร็จบ่งชี้ว่ามีคีย์สาธารณะอยู่ในคีย์ริงของระบบ (ไฮไลต์หมายถึง ID คีย์สาธารณะ)
    3. แทนที่ช่องว่างด้วย # และส่งผ่านเป็น <public-key-id> ในบรรทัดคำสั่งเคอร์เนล ตัวอย่างเช่น ส่ง Android:#7e4333f9bba00adfe0ede979e28ed1920492b40f แทน <public-key-id>

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

บูตโหลดเดอร์ที่รองรับ 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-ed ควรตั้งชื่อดังต่อไปนี้ (สล็อตจะมีชื่อว่า 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 ที่ทำงานอยู่ในอิมเมจระบบที่บูตตามปกติ ยังคงมีโหมดการกู้คืนที่ใช้ในการรีเซ็ตข้อมูลเป็นค่าเริ่มต้นและไซด์โหลดแพ็คเกจการอัปเดต (ซึ่งเป็นที่มาของชื่อ "การกู้คืน") รหัสและข้อมูลสำหรับโหมดการกู้คืนจะถูกจัดเก็บไว้ในพาร์ติชันสำหรับเริ่มระบบปกติใน ramdisk ในการบูตเข้าสู่อิมเมจระบบ bootloader จะบอกให้เคอร์เนลข้าม ramdisk (ไม่เช่นนั้นอุปกรณ์จะบู๊ตเข้าสู่โหมดการกู้คืน โหมดการกู้คืนมีขนาดเล็ก (และส่วนใหญ่อยู่ในพาร์ติชันสำหรับเริ่มระบบแล้ว) ดังนั้นพาร์ติชันสำหรับบูตจึงไม่เพิ่มขึ้น ในขนาด.

Fstab

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

<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> ส่งคืน "ใช่" หากพาร์ติชันที่กำหนดรองรับสล็อต มิฉะนั้น "ไม่"
  • current-slot ส่งคืนส่วนต่อท้ายสล็อตที่จะถูกบูตจากครั้งถัดไป
  • slot-count ส่งกลับจำนวนเต็มที่แสดงถึงจำนวนช่องที่มีอยู่ ปัจจุบัน รองรับช่อง 2 ช่อง ดังนั้นค่านี้คือ 2
  • slot-successful:<slot-suffix> . ส่งคืน "ใช่" หากช่องที่กำหนดถูกทำเครื่องหมายว่าบูตได้สำเร็จ มิฉะนั้น "ไม่"
  • slot-unbootable:<slot-suffix> . ส่งคืน "ใช่" หากช่องที่ระบุถูกทำเครื่องหมายว่าไม่สามารถบูตได้ หากไม่เป็นเช่นนั้น ให้ "ไม่"
  • slot-retry-count . จำนวนครั้งในการลองใหม่ที่เหลืออยู่เพื่อพยายามบูตช่องที่กำหนด

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

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

เครื่องมือแพ็คเกจ OTA ทำตามคำสั่งเดียวกันกับคำสั่งสำหรับอุปกรณ์ที่ไม่ใช่ A/B ไฟล์ target_files.zip ต้องถูกสร้างขึ้นโดยการกำหนดตัวแปร build สำหรับเป้าหมาย 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 ใดๆ ที่กำหนดไว้ในดิสก์เดียวกัน คู่ของพาร์ติชันมีคำนำหน้าทั่วไป (เช่น system หรือ boot ) และส่วนต่อท้ายต่อสล็อต (เช่น _a ) รายการพาร์ติชันที่ตัวสร้างเพย์โหลดกำหนดการอัปเดตได้รับการกำหนดค่าโดยตัวแปร make 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) นอกจากนี้ ให้ระบุประเภทระบบไฟล์ที่จะส่งผ่านไปยังการเรียกระบบ 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
    

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