การอัปเดตระบบ A/B (ไร้รอยต่อ)

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

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการอัปเดตระบบ A/B และวิธีการทำงาน โปรดดูที่ การเลือกพาร์ติชัน (ช่อง)

การอัปเดตระบบ A/B ให้ประโยชน์ดังต่อไปนี้:

  • การอัปเดต OTA สามารถเกิดขึ้นได้ในขณะที่ระบบกำลังทำงาน โดยไม่รบกวนผู้ใช้ ผู้ใช้จะยังใช้อุปกรณ์ของตนต่อไปได้ในระหว่าง OTA การหยุดทำงานเพียงอย่างเดียวระหว่างการอัปเดตคือเมื่ออุปกรณ์รีบูตเข้าสู่พาร์ติชั่นดิสก์ที่อัปเดต
  • หลังจากการอัพเดต การรีบูตจะใช้เวลาไม่นานกว่าการรีบูตปกติ
  • หากใช้ OTA ล้มเหลว (เช่น เนื่องจากแฟลชไม่ดี) ผู้ใช้จะไม่ได้รับผลกระทบ ผู้ใช้จะยังคงใช้ระบบปฏิบัติการเก่าต่อไป และไคลเอนต์มีอิสระที่จะลองอัปเดตอีกครั้ง
  • หากใช้การอัปเดต OTA แต่ไม่สามารถบู๊ตได้ อุปกรณ์จะรีบูตกลับเข้าไปในพาร์ติชันเก่าและยังคงใช้งานได้ ไคลเอนต์มีอิสระที่จะลองอัปเดตอีกครั้ง
  • ข้อผิดพลาดใดๆ (เช่น ข้อผิดพลาด I/O) จะส่งผลต่อชุดพาร์ติชัน ที่ไม่ได้ใช้ เท่านั้นและสามารถลองใหม่ได้ ข้อผิดพลาดดังกล่าวมีโอกาสน้อยลงเนื่องจากโหลด I/O ตั้งใจไว้ต่ำเพื่อหลีกเลี่ยงการเสื่อมคุณภาพประสบการณ์ผู้ใช้
  • สามารถสตรีมการอัปเดตไปยังอุปกรณ์ A/B ได้โดยไม่จำเป็นต้องดาวน์โหลดแพ็คเกจก่อนทำการติดตั้ง การสตรีมหมายความว่าผู้ใช้ไม่จำเป็นต้องมีพื้นที่ว่างเพียงพอในการจัดเก็บแพ็คเกจการอัปเดตบน /data หรือ /cache
  • พาร์ติชั่นแคชไม่ได้ถูกใช้เพื่อจัดเก็บแพ็คเกจการอัพเดท OTA อีกต่อไป ดังนั้นจึงไม่จำเป็นต้องตรวจสอบให้แน่ใจว่าพาร์ติชั่นแคชมีขนาดใหญ่เพียงพอสำหรับการอัพเดทในอนาคต
  • dm-verity รับประกันว่าอุปกรณ์จะบู๊ตอิมเมจที่ไม่เสียหาย หากอุปกรณ์ไม่บู๊ตเนื่องจากปัญหา OTA หรือ dm-verity ที่ไม่ดี อุปกรณ์สามารถรีบูตเป็นอิมเมจเก่าได้ (Android Verified Boot ไม่จำเป็นต้องอัปเดต A/B)

เกี่ยวกับการอัปเดตระบบ A/B

การอัปเดต A/B จำเป็นต้องเปลี่ยนแปลงทั้งไคลเอนต์และระบบ อย่างไรก็ตาม แพ็คเกจเซิร์ฟเวอร์ OTA ไม่ควรต้องมีการเปลี่ยนแปลง: แพ็คเกจการอัปเดตยังคงให้บริการผ่าน HTTPS สำหรับอุปกรณ์ที่ใช้โครงสร้างพื้นฐาน OTA ของ Google การเปลี่ยนแปลงระบบทั้งหมดอยู่ใน AOSP และรหัสไคลเอ็นต์จะได้รับจากบริการ Google Play OEM ที่ไม่ได้ใช้โครงสร้างพื้นฐาน OTA ของ Google จะสามารถใช้โค้ดระบบ AOSP ซ้ำได้ แต่จะต้องจัดหาไคลเอ็นต์ของตนเอง

สำหรับ OEM ที่จัดหาลูกค้าของตนเอง ลูกค้าจำเป็นต้อง:

  • ตัดสินใจว่าจะอัปเดตเมื่อใด เนื่องจากการอัปเดต A/B เกิดขึ้นในเบื้องหลัง จึงไม่ได้ดำเนินการโดยผู้ใช้อีกต่อไป เพื่อหลีกเลี่ยงการรบกวนผู้ใช้ ขอแนะนำให้กำหนดเวลาการอัปเดตเมื่ออุปกรณ์อยู่ในโหมดบำรุงรักษาที่ไม่ได้ใช้งาน เช่น ข้ามคืน และเปิด Wi-Fi อย่างไรก็ตาม ลูกค้าของคุณสามารถใช้การวิเคราะห์พฤติกรรมตามที่คุณต้องการได้
  • ตรวจสอบกับเซิร์ฟเวอร์แพ็คเกจ OTA ของคุณและพิจารณาว่ามีการอัปเดตหรือไม่ ซึ่งควรจะเหมือนกับรหัสไคลเอ็นต์ที่มีอยู่ของคุณเป็นส่วนใหญ่ ยกเว้นว่าคุณจะต้องการส่งสัญญาณว่าอุปกรณ์รองรับ A/B (ไคลเอนต์ของ Google ยังมีปุ่ม ตรวจสอบทันที เพื่อให้ผู้ใช้ตรวจสอบการอัปเดตล่าสุด)
  • โทร update_engine ด้วย HTTPS URL สำหรับแพ็คเกจอัพเดตของคุณ สมมติว่ามีอยู่ update_engine จะอัปเดตบล็อกดิบบนพาร์ติชันที่ไม่ได้ใช้ในปัจจุบันในขณะที่สตรีมแพ็คเกจอัปเดต
  • รายงานการติดตั้งสำเร็จหรือล้มเหลวไปยังเซิร์ฟเวอร์ของคุณ ตามโค้ดผลลัพธ์ update_engine หากใช้การอัปเดตสำเร็จ update_engine จะบอกให้ bootloader บูตเข้าสู่ระบบปฏิบัติการใหม่ในการรีบูตครั้งถัดไป โปรแกรมโหลดบูตจะถอยกลับไปใช้ระบบปฏิบัติการเก่าหากระบบปฏิบัติการใหม่ไม่สามารถบู๊ตได้ ดังนั้นจึงไม่จำเป็นต้องดำเนินการใดๆ จากไคลเอ็นต์ หากการอัปเดตล้มเหลว ลูกค้าจะต้องตัดสินใจว่าจะลองอีกครั้งเมื่อใด (และหรือไม่) โดยพิจารณาจากรหัสข้อผิดพลาดโดยละเอียด ตัวอย่างเช่น ลูกค้าที่ดีอาจรับรู้ว่าแพ็คเกจ OTA บางส่วน ("diff") ล้มเหลว และลองใช้แพ็คเกจ OTA แบบเต็มแทน

ทางเลือก ลูกค้าสามารถ:

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

ในด้านระบบ การอัปเดตระบบ A/B จะส่งผลต่อสิ่งต่อไปนี้:

  • การเลือกพาร์ติชัน (สล็อต), update_engine daemon และการโต้ตอบของ bootloader (อธิบายไว้ด้านล่าง)
  • กระบวนการสร้างและการสร้างแพ็คเกจการอัปเดต OTA (อธิบายไว้ใน การนำการอัปเดต A/B ไปใช้ )

การเลือกพาร์ติชัน (ช่อง)

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

แต่ละช่องมีคุณลักษณะ ที่สามารถบูตได้ ซึ่งระบุว่าช่องดังกล่าวมีระบบที่ถูกต้องซึ่งอุปกรณ์สามารถบู๊ตได้ สล็อตปัจจุบันสามารถบูตได้เมื่อระบบกำลังทำงาน แต่สล็อตอื่นอาจมีเวอร์ชันเก่า (ยังคงถูกต้อง) ของระบบ เวอร์ชันใหม่กว่า หรือข้อมูลที่ไม่ถูกต้อง ไม่ว่าสล็อต ปัจจุบัน จะเป็นอะไรก็ตาม มีสล็อตหนึ่งช่องที่เป็นสล็อต ที่ใช้งานอยู่ (ช่องที่ bootloader จะบู๊ตจากการบู๊ตครั้งถัดไป) หรือสล็อต ที่ต้องการ

แต่ละสล็อตยังมีคุณลักษณะ ที่สำเร็จ ซึ่งกำหนดโดยพื้นที่ผู้ใช้ ซึ่งจะเกี่ยวข้องเฉพาะในกรณีที่สล็อตนั้นสามารถบูตได้ด้วย ช่องที่ประสบความสำเร็จควรจะสามารถบูต รัน และอัปเดตตัวเองได้ สล็อตที่สามารถบู๊ตได้ซึ่งไม่ได้ทำเครื่องหมายว่าสำเร็จ (หลังจากพยายามบู๊ตหลายครั้ง) ควรถูกทำเครื่องหมายว่าไม่สามารถบู๊ตได้โดย bootloader รวมถึงการเปลี่ยนสล็อตที่ใช้งานเป็นสล็อตที่สามารถบู๊ตได้อื่น (โดยปกติจะเป็นสล็อตที่ทำงานทันทีก่อนที่จะพยายามบู๊ต) ให้เป็นอันใหม่ที่ใช้งานอยู่) รายละเอียดเฉพาะของอินเทอร์เฟซถูกกำหนดไว้ใน boot_control.h

อัพเดตดีมอนเครื่องยนต์

การอัปเดตระบบ A/B ใช้ดีมอนพื้นหลังที่เรียกว่า update_engine เพื่อเตรียมระบบให้บูตเป็นเวอร์ชันอัปเดตใหม่ daemon นี้สามารถดำเนินการต่อไปนี้:

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

เนื่องจาก update_engine daemon ไม่เกี่ยวข้องกับกระบวนการบู๊ต จึงถูกจำกัดในสิ่งที่สามารถทำได้ระหว่างการอัปเดตโดยนโยบายและฟีเจอร์ของ SELinux ในช่อง ปัจจุบัน (นโยบายและฟีเจอร์ดังกล่าวไม่สามารถอัปเดตได้จนกว่าระบบจะบู๊ตเข้าสู่ เวอร์ชั่นใหม่). เพื่อรักษาระบบที่แข็งแกร่ง กระบวนการอัปเดต ไม่ควร แก้ไขตารางพาร์ติชั่น เนื้อหาของพาร์ติชั่นในช่องปัจจุบัน หรือเนื้อหาของพาร์ติชั่นที่ไม่ใช่ A/B ซึ่งไม่สามารถล้างข้อมูลได้ด้วยการรีเซ็ตเป็นค่าจากโรงงาน

อัพเดทที่มาของเครื่องยนต์

แหล่งที่มา update_engine อยู่ใน system/update_engine ไฟล์ dexopt A/B OTA จะถูกแบ่งระหว่าง installd และตัวจัดการแพ็คเกจ:

สำหรับตัวอย่างการทำงาน โปรดดูที่ /device/google/marlin/device-common.mk

อัปเดตบันทึกเครื่องยนต์

สำหรับ Android 8.x และรุ่นก่อนหน้า คุณสามารถดูบันทึก update_engine ได้ใน logcat และในรายงานข้อผิดพลาด หากต้องการให้บันทึก update_engine พร้อมใช้งานในระบบไฟล์ ให้แก้ไขการเปลี่ยนแปลงต่อไปนี้ในบิลด์ของคุณ:

การเปลี่ยนแปลงเหล่านี้จะบันทึกสำเนาของบันทึก update_engine ล่าสุดไปที่ /data/misc/update_engine_log/update_engine. YEAR - TIME . นอกเหนือจากบันทึกปัจจุบัน บันทึกล่าสุดห้ารายการจะถูกบันทึกไว้ใน /data/misc/update_engine_log/ ผู้ใช้ที่มี ID กลุ่ม บันทึก จะสามารถเข้าถึงบันทึกระบบไฟล์ได้

การโต้ตอบของ Bootloader

boot_control HAL ถูกใช้โดย update_engine (และอาจเป็น daemons อื่นๆ) เพื่อสั่ง bootloader ว่าจะบูตจากอะไร สถานการณ์ตัวอย่างทั่วไปและสถานะที่เกี่ยวข้องมีดังต่อไปนี้:

  • กรณีปกติ : ระบบกำลังทำงานจากช่องปัจจุบัน ไม่ว่าจะเป็นช่อง A หรือ B ยังไม่มีการอัพเดตใดๆ สล็อตปัจจุบันของระบบสามารถบูตได้ สำเร็จ และเป็นสล็อตที่ใช้งานอยู่
  • อยู่ระหว่างดำเนินการอัปเดต : ระบบกำลังทำงานจากสล็อต B ดังนั้นสล็อต B จึงเป็นสล็อตที่สามารถบู๊ตได้ สำเร็จ และใช้งานอยู่ ช่อง A ถูกทำเครื่องหมายว่าไม่สามารถบูตได้เนื่องจากเนื้อหาของช่อง A กำลังได้รับการอัปเดตแต่ยังไม่เสร็จสมบูรณ์ การรีบูตในสถานะนี้ควรทำการบูทต่อจากสล็อต B
  • ใช้การอัปเดต รอรีบูตเครื่อง : ระบบกำลังทำงานจากสล็อต B สล็อต B สามารถบู๊ตได้และสำเร็จ แต่สล็อต A ถูกทำเครื่องหมายว่าใช้งานอยู่ (และดังนั้นจึงถูกทำเครื่องหมายว่าสามารถบู๊ตได้) Slot A ยังไม่ถูกทำเครื่องหมายว่าสำเร็จ และ bootloader ควรพยายามบูตจากช่อง A หลายครั้ง
  • ระบบรีบูตเป็นการอัปเดตใหม่ : ระบบกำลังทำงานจากสล็อต A เป็นครั้งแรก สล็อต B ยังคงสามารถบู๊ตได้และประสบความสำเร็จ ในขณะที่สล็อต A เป็นเพียงการบู๊ตเท่านั้น และยังคงทำงานอยู่ แต่ไม่สำเร็จ daemon พื้นที่ผู้ใช้ update_verifier ควรทำเครื่องหมายช่อง A ว่าสำเร็จหลังจากทำการตรวจสอบบางอย่างแล้ว

รองรับการอัพเดตสตรีมมิ่ง

อุปกรณ์ของผู้ใช้มีพื้นที่บน /data ไม่เพียงพอที่จะดาวน์โหลดแพ็คเกจอัพเดตเสมอไป เนื่องจากทั้ง OEM และผู้ใช้ไม่ต้องการเสียพื้นที่บนพาร์ติ /cache ผู้ใช้บางรายจึงไม่ได้รับการอัปเดตเนื่องจากอุปกรณ์ไม่มีที่สำหรับจัดเก็บแพ็คเกจการอัปเดต เพื่อแก้ไขปัญหานี้ Android 8.0 ได้เพิ่มการสนับสนุนสำหรับการสตรีมการอัปเดต A/B ที่เขียนบล็อกโดยตรงไปยังพาร์ติชัน B ขณะที่ดาวน์โหลด โดยไม่ต้องจัดเก็บบล็อกไว้ใน /data การอัปเดต A/B แบบสตรีมแทบไม่ต้องใช้พื้นที่เก็บข้อมูลชั่วคราว และต้องการพื้นที่เก็บข้อมูลเพียงพอสำหรับข้อมูลเมตาประมาณ 100 KiB

หากต้องการเปิดใช้งานการอัปเดตการสตรีมใน Android 7.1 ให้เลือกแพตช์ต่อไปนี้:

แพทช์เหล่านี้จำเป็นเพื่อรองรับการสตรีมการอัปเดต A/B ใน Android 7.1 และใหม่กว่า ไม่ว่าจะใช้ Google Mobile Services (GMS) หรือไคลเอนต์การอัปเดตอื่น ๆ

ชีวิตของการอัปเดต A/B

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

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

หลังจากที่เพย์โหลดพร้อมใช้งาน กระบวนการอัพเดตจะเป็นดังนี้:

ขั้นตอน กิจกรรม
1 ช่องปัจจุบัน (หรือ "ช่องต้นทาง") ถูกทำเครื่องหมายว่าสำเร็จ (หากยังไม่ได้ทำเครื่องหมาย) ด้วย markBootSuccessful()
2 ช่องที่ไม่ได้ใช้ (หรือ "ช่องเป้าหมาย") ถูกทำเครื่องหมายว่าไม่สามารถบูตได้โดยการเรียกใช้ฟังก์ชัน setSlotAsUnbootable() ช่องปัจจุบันจะถูกทำเครื่องหมายว่าสำเร็จเสมอเมื่อเริ่มต้นการอัปเดต เพื่อป้องกันไม่ให้ Bootloader ถอยกลับไปยังช่องที่ไม่ได้ใช้ ซึ่งจะมีข้อมูลที่ไม่ถูกต้องในไม่ช้า หากระบบถึงจุดที่สามารถเริ่มใช้การอัปเดตได้ ช่องปัจจุบันจะถูกทำเครื่องหมายว่าสำเร็จแม้ว่าส่วนประกอบหลักอื่นๆ จะใช้งานไม่ได้ (เช่น UI ในลูปข้อขัดข้อง) เนื่องจากเป็นไปได้ที่จะผลักดันซอฟต์แวร์ใหม่เพื่อแก้ไขปัญหาเหล่านี้ ปัญหา.

เพย์โหลดการอัปเดตเป็นหยดทึบพร้อมคำแนะนำในการอัปเดตเป็นเวอร์ชันใหม่ เพย์โหลดการอัพเดตประกอบด้วยสิ่งต่อไปนี้:
  • ข้อมูลเมตา ข้อมูลเมตาเป็นส่วนที่ค่อนข้างเล็กของเพย์โหลดการอัพเดต โดยประกอบด้วยรายการการดำเนินการเพื่อสร้างและตรวจสอบเวอร์ชันใหม่ในช่องเป้าหมาย ตัวอย่างเช่น การดำเนินการสามารถขยายขนาด Blob บางอันและเขียนลงในบล็อกเฉพาะในพาร์ติชันเป้าหมาย หรืออ่านจากพาร์ติชันต้นทาง ใช้แพตช์ไบนารี และเขียนลงในบล็อกบางบล็อกในพาร์ติชันเป้าหมาย
  • ข้อมูลเพิ่มเติม เนื่องจากเพย์โหลดการอัปเดตจำนวนมาก ข้อมูลเพิ่มเติมที่เกี่ยวข้องกับการดำเนินการประกอบด้วย blob ที่บีบอัดหรือแพตช์ไบนารีในตัวอย่างเหล่านี้
3 ข้อมูลเมตาของเพย์โหลดจะถูกดาวน์โหลด
4 สำหรับการดำเนินการแต่ละรายการที่กำหนดไว้ในข้อมูลเมตา ข้อมูลที่เกี่ยวข้อง (ถ้ามี) จะถูกดาวน์โหลดไปยังหน่วยความจำ การดำเนินการจะถูกนำไปใช้ และหน่วยความจำที่เกี่ยวข้องจะถูกละทิ้งตามลำดับ
5 พาร์ติชันทั้งหมดจะถูกอ่านซ้ำและตรวจสอบกับแฮชที่คาดหวัง
6 ขั้นตอนหลังการติดตั้ง (ถ้ามี) จะถูกรัน ในกรณีที่เกิดข้อผิดพลาดระหว่างการดำเนินการตามขั้นตอนใดๆ การอัปเดตจะล้มเหลวและพยายามอีกครั้งโดยอาจมีเพย์โหลดอื่น หากขั้นตอนทั้งหมดประสบความสำเร็จ การอัพเดตจะสำเร็จและดำเนินการขั้นตอนสุดท้าย
7 ช่องที่ไม่ได้ใช้ถูก ทำเครื่องหมายว่าใช้งานอยู่โดยการเรียก setActiveBootSlot() การทำเครื่องหมายช่องที่ไม่ได้ใช้ว่าใช้งานอยู่ไม่ได้หมายความว่าจะบูตเสร็จสิ้น bootloader (หรือตัวระบบเอง) สามารถสลับช่องที่ใช้งานอยู่กลับได้ หากอ่านสถานะไม่สำเร็จ
8 หลังการติดตั้ง (อธิบายไว้ด้านล่าง) เกี่ยวข้องกับการเรียกใช้โปรแกรมจากเวอร์ชัน "อัปเดตใหม่" ในขณะที่ยังคงทำงานในเวอร์ชันเก่า หากกำหนดไว้ในแพ็คเกจ OTA ขั้นตอนนี้ถือเป็น ข้อบังคับ และโปรแกรมจะต้องส่งคืนพร้อมโค้ดออก 0 ; มิฉะนั้นการอัปเดตจะล้มเหลว
9 หลังจากที่ระบบบู๊ตเข้าไปในช่องใหม่ได้มากพอและเสร็จสิ้นการตรวจสอบหลังการรีบูต ช่องปัจจุบันในปัจจุบัน (เดิมเรียกว่า "ช่องเป้าหมาย") จะถูกทำเครื่องหมายว่าสำเร็จโดยการเรียก markBootSuccessful()

หลังการติดตั้ง

สำหรับทุกพาร์ติชันที่มีการกำหนดขั้นตอนหลังการติดตั้ง update_engine จะเมาท์พาร์ติชันใหม่ในตำแหน่งเฉพาะ และรันโปรแกรมที่ระบุใน OTA ที่สัมพันธ์กับพาร์ติชันที่เมาท์ ตัวอย่างเช่น หากโปรแกรมหลังการติดตั้งถูกกำหนดเป็น usr/bin/postinstall ในพาร์ติชันระบบ พาร์ติชันนี้จากสล็อตที่ไม่ได้ใช้จะถูกเมาท์ในตำแหน่งคงที่ (เช่น /postinstall_mount ) และ /postinstall_mount/usr/bin/postinstall คำสั่ง /postinstall_mount/usr/bin/postinstall จะถูกดำเนินการ

เพื่อให้หลังการติดตั้งสำเร็จ เคอร์เนลเก่าจะต้องสามารถ:

  • เมานต์รูปแบบระบบไฟล์ใหม่ ประเภทระบบไฟล์ไม่สามารถเปลี่ยนแปลงได้เว้นแต่จะมีการรองรับในเคอร์เนลเก่า รวมถึงรายละเอียด เช่น อัลกอริธึมการบีบอัดที่ใช้หากใช้ระบบไฟล์ที่ถูกบีบอัด (เช่น SquashFS)
  • ทำความเข้าใจรูปแบบโปรแกรมหลังการติดตั้งของพาร์ติชันใหม่ หากใช้ไบนารี Executable และ Linkable Format (ELF) ควรเข้ากันได้กับเคอร์เนลเก่า (เช่น โปรแกรมใหม่ 64 บิตที่ทำงานบนเคอร์เนล 32 บิตเก่า หากสถาปัตยกรรมเปลี่ยนจากบิลด์ 32- เป็น 64 บิต) ยกเว้นในกรณีที่ตัวโหลด ( ld ) ได้รับคำสั่งให้ใช้พาธอื่นหรือสร้างไบนารีแบบคงที่ ไลบรารีจะถูกโหลดจากอิมเมจระบบเก่า ไม่ใช่อิมเมจใหม่

ตัวอย่างเช่น คุณสามารถใช้เชลล์สคริปต์เป็นโปรแกรมหลังการติดตั้งซึ่งตีความโดยเชลล์ไบนารีของระบบเก่าด้วย #! เครื่องหมายที่ด้านบน) จากนั้นตั้งค่าเส้นทางไลบรารีจากสภาพแวดล้อมใหม่เพื่อดำเนินการโปรแกรมหลังการติดตั้งไบนารีที่ซับซ้อนมากขึ้น หรือคุณสามารถรันขั้นตอนหลังการติดตั้งจากพาร์ติชันที่มีขนาดเล็กกว่าโดยเฉพาะ เพื่อเปิดใช้งานรูปแบบระบบไฟล์ในพาร์ติชันระบบหลักที่จะอัพเดตได้โดยไม่เกิดปัญหาความเข้ากันได้แบบย้อนหลังหรือการอัพเดตขั้นบันได สิ่งนี้จะทำให้ผู้ใช้สามารถอัปเดตเป็นเวอร์ชันล่าสุดได้โดยตรงจากอิมเมจจากโรงงาน

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

โปรแกรมหลังการติดตั้งที่เลือกจะทำงานในบริบท postinstall SELinux ไฟล์ทั้งหมดในพาร์ติชันที่เมาท์ใหม่จะถูกแท็กด้วย postinstall_file โดยไม่คำนึงว่าแอตทริบิวต์ของไฟล์เหล่านั้นจะเป็นอย่างไรหลังจากรีบูตเข้าสู่ระบบใหม่นั้น การเปลี่ยนแปลงแอตทริบิวต์ SELinux ในระบบใหม่จะไม่ส่งผลกระทบต่อขั้นตอนหลังการติดตั้ง หากโปรแกรมหลังการติดตั้งต้องการสิทธิ์เพิ่มเติม จะต้องเพิ่มสิทธิ์เหล่านั้นในบริบทหลังการติดตั้ง

หลังจากรีบูต

หลังจากรีบูต update_verifier จะทริกเกอร์การตรวจสอบความสมบูรณ์โดยใช้ dm-verity การตรวจสอบนี้เริ่มต้นก่อนไซโกตเพื่อหลีกเลี่ยงบริการ Java ที่ทำการเปลี่ยนแปลงที่ไม่สามารถย้อนกลับได้ซึ่งจะป้องกันการย้อนกลับอย่างปลอดภัย ในระหว่างกระบวนการนี้ bootloader และเคอร์เนลอาจทริกเกอร์การรีบูตหากการบูตที่ตรวจสอบแล้วหรือ dm-verity ตรวจพบความเสียหายใดๆ หลังจากการตรวจสอบเสร็จสิ้น update_verifier จะทำเครื่องหมายว่าการบูตสำเร็จ

update_verifier จะอ่านเฉพาะบล็อกที่แสดงอยู่ใน /data/ota_package/care_map.txt ซึ่งรวมอยู่ในแพ็คเกจ A/B OTA เมื่อใช้โค้ด AOSP ไคลเอ็นต์การอัปเดตระบบ Java เช่น GmsCore จะแตก care_map.txt ตั้งค่าสิทธิ์การเข้าถึงก่อนที่จะรีบูตอุปกรณ์ และลบไฟล์ที่แตกออกมาหลังจากที่ระบบบูทเป็นเวอร์ชันใหม่ได้สำเร็จ