ลดขนาด OTA

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

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

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

ระบบบิลด์สร้างแพตช์ขนาดใหญ่โดยไม่จำเป็นได้หลายวิธี เพื่อลดปัญหานี้ ใน Android 8.0 ขึ้นไป เราได้ใช้ฟีเจอร์ใหม่เพื่อลดขนาดแพตช์สำหรับส่วนต่างของแต่ละไฟล์ การปรับปรุงที่ช่วยลดขนาดแพ็กเกจการอัปเดตผ่าน OTA มีดังนี้

  • การใช้ ZSTD ซึ่งเป็นอัลกอริทึมการบีบอัดแบบไม่สูญเสียข้อมูลอเนกประสงค์สำหรับรูปภาพแบบเต็ม ในการอัปเดตอุปกรณ์ที่ไม่ใช่ A/B ZSTD สามารถปรับแต่งเพื่อให้อัตราส่วนการบีบอัดสูงขึ้น ได้โดยการเพิ่มระดับการบีบอัด ระดับการบีบอัดจะตั้งค่าในระหว่างเวลาสร้าง OTA และตั้งค่าได้โดยส่งแฟล็ก --vabc_compression_param=zstd,$COMPRESSION_LEVEL
  • การเพิ่มขนาดหน้าต่างการบีบอัดที่ใช้ระหว่าง OTA คุณตั้งค่าขนาดหน้าต่างการบีบอัดสูงสุด ได้โดยการปรับแต่งพารามิเตอร์บิลด์ในไฟล์ .mk ของอุปกรณ์ ตัวแปรนี้ ตั้งค่าเป็น PRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR := 262144
  • การใช้การบีบอัดซ้ำของ Puffin ซึ่งเป็นเครื่องมือแก้ไขที่กำหนดได้สำหรับสตรีม deflate ซึ่งจัดการฟังก์ชันการบีบอัดและฟังก์ชัน diff สำหรับการสร้างการอัปเดต OTA แบบ A/B
  • การเปลี่ยนแปลงการใช้งานเครื่องมือสร้างเดลต้า เช่น วิธีใช้ไลบรารี bsdiff สำหรับการบีบอัดแพตช์ ใน Android 9 ขึ้นไป เครื่องมือ bsdiff จะเลือกอัลกอริทึมการบีบอัดที่จะให้ ผลลัพธ์การบีบอัดที่ดีที่สุดสำหรับแพตช์
  • การปรับปรุง update_engine ส่งผลให้ใช้หน่วยความจำน้อยลงเมื่อใช้แพตช์สำหรับการอัปเดตอุปกรณ์ A/B

ส่วนต่อไปนี้จะกล่าวถึงปัญหาต่างๆ ที่ส่งผลต่อขนาดการอัปเดต OTA วิธีแก้ปัญหา และตัวอย่างการใช้งานใน AOSP

ลำดับไฟล์

ปัญหา: ระบบไฟล์ไม่รับประกันลำดับไฟล์เมื่อขอรายการไฟล์ในไดเรกทอรี แม้ว่าโดยทั่วไปแล้วลำดับไฟล์จะเหมือนกันสำหรับการชำระเงินเดียวกัน เครื่องมือต่างๆ เช่น ls จะจัดเรียงผลลัพธ์ตามค่าเริ่มต้น แต่ฟังก์ชันไวลด์การ์ดที่ใช้โดยคำสั่งต่างๆ เช่น find และ make จะไม่จัดเรียง ก่อนใช้เครื่องมือเหล่านี้ คุณต้องจัดเรียง เอาต์พุต

วิธีแก้ปัญหา: เมื่อใช้เครื่องมือต่างๆ เช่น find และ make กับฟังก์ชันไวลด์การ์ด ให้จัดเรียงเอาต์พุตของคำสั่งเหล่านี้ก่อนที่จะใช้ คำสั่งดังกล่าว เมื่อใช้ $(wildcard) หรือ $(shell find) ในไฟล์ Android.mk ให้จัดเรียงด้วย เครื่องมือบางอย่าง เช่น Java จะจัดเรียงอินพุต ดังนั้นก่อนจัดเรียงไฟล์ ให้ตรวจสอบว่าเครื่องมือที่คุณใช้ยังไม่ได้จัดเรียง

ตัวอย่าง: มีการแก้ไขอินสแตนซ์จำนวนมากในระบบบิลด์หลักโดยใช้มาโคร all-*-files-under ในตัว ซึ่งรวมถึง all-cpp-files-under (เนื่องจากมีการกระจายคำจำกัดความหลายรายการในไฟล์ Makefile อื่นๆ) ดูรายละเอียดได้ที่

ไดเรกทอรีบิลด์

ปัญหา: การเปลี่ยนไดเรกทอรีที่สร้างสิ่งต่างๆ อาจทำให้ไบนารีแตกต่างกัน เส้นทางส่วนใหญ่ในการสร้าง Android เป็นเส้นทางแบบสัมพัทธ์ ดังนั้น __FILE__ ใน C/C++ จึงไม่ใช่ปัญหา อย่างไรก็ตาม สัญลักษณ์การแก้ไขข้อบกพร่องจะเข้ารหัสเส้นทางแบบเต็ม โดยค่าเริ่มต้น และ .note.gnu.build-id จะสร้างขึ้นจากการแฮช ไบนารีที่ยังไม่ได้ลบ ดังนั้น .note.gnu.build-id จะเปลี่ยนหากสัญลักษณ์การแก้ไขข้อบกพร่องเปลี่ยน

วิธีแก้ไข: ตอนนี้ AOSP ทำให้เส้นทางการแก้ไขข้อบกพร่องเป็นแบบสัมพัทธ์แล้ว ดูรายละเอียดได้ที่ CL: https://android.googlesource.com/platform/build/+/6a66a887baadc9eb3d0d60e26f748b8453e27a02

การประทับเวลา

ปัญหา: การประทับเวลาในเอาต์พุตการสร้างทำให้เกิดการเปลี่ยนแปลงไฟล์ที่ไม่จำเป็น ซึ่งมีแนวโน้มที่จะเกิดขึ้นในพื้นที่ต่อไปนี้

  • __DATE__/__TIME__/__TIMESTAMP__ มาโครในโค้ด C หรือ C++
  • การประทับเวลาที่ฝังอยู่ในไฟล์เก็บถาวรแบบ Zip

วิธีแก้ปัญหา/ตัวอย่าง: หากต้องการนำการประทับเวลาออกจากเอาต์พุตการสร้าง ให้ใช้ วิธีการที่ระบุไว้ด้านล่างใน __DATE__/__TIME__/__TIMESTAMP__ ใน C/C++ และ การประทับเวลาที่ฝังอยู่ในที่เก็บ

__DATE__/__TIME__/__TIMESTAMP__ ใน C/C++

มาโครเหล่านี้จะสร้างเอาต์พุตที่แตกต่างกันเสมอสำหรับการสร้างที่แตกต่างกัน ดังนั้นจึงไม่ควรใช้ ตัวเลือกบางส่วนในการนำมาโครเหล่านี้ออกมีดังนี้

การประทับเวลาที่ฝังอยู่ในไฟล์เก็บถาวร (zip, jar)

Android 7.0 แก้ปัญหาการประทับเวลาที่ฝังอยู่ในไฟล์ ZIP โดยการเพิ่ม -X ในการใช้คำสั่ง zip ทั้งหมด ซึ่งจะนำ UID/GID ของ บิลเดอร์และการประทับเวลา Unix แบบขยายออกจากไฟล์ ZIP

เครื่องมือใหม่ ziptime (อยู่ใน /platform/build/+/android16-qpr2-release/tools/ziptime/) จะรีเซ็ตการประทับเวลาปกติในส่วนหัวของไฟล์ ZIP โปรดดูรายละเอียดในไฟล์ README

signapk เครื่องมือจะตั้งค่าการประทับเวลาสำหรับไฟล์ APK ซึ่งอาจแตกต่างกันไปตามเขตเวลาของเซิร์ฟเวอร์ ดูรายละเอียดได้ที่ CL https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028

signapk เครื่องมือจะตั้งค่าการประทับเวลาสำหรับไฟล์ APK ซึ่งอาจแตกต่างกันไปตามเขตเวลาของเซิร์ฟเวอร์ ดูรายละเอียดได้ที่ CL https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028

สตริงเวอร์ชัน

ปัญหา: สตริงเวอร์ชัน APK มักมี BUILD_NUMBER ต่อท้าย เวอร์ชันที่ฮาร์ดโค้ด แม้ว่าจะไม่มีการเปลี่ยนแปลงอื่นใดใน APK แต่ผลลัพธ์ที่ได้คือ APK จะยังคงแตกต่างกัน

วิธีแก้ปัญหา: นำหมายเลขบิลด์ออกจากสตริงเวอร์ชัน APK

ตัวอย่าง

เปิดใช้การคำนวณความถูกต้องในอุปกรณ์

หากเปิดใช้ dm-verity ในอุปกรณ์ เครื่องมือ OTA จะเลือกการกำหนดค่าความถูกต้องโดยอัตโนมัติ และเปิดใช้การคำนวณความถูกต้องในอุปกรณ์ ซึ่งจะช่วยให้คำนวณบล็อกความถูกต้องในอุปกรณ์ Android ได้แทนที่จะจัดเก็บเป็นไบต์ดิบในแพ็กเกจ OTA บล็อก Verity สามารถใช้พื้นที่ประมาณ 16MB สำหรับพาร์ติชันขนาด 2GB

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

เครื่องมือสร้างที่สอดคล้องกัน

ปัญหา: เครื่องมือที่สร้างไฟล์ที่ติดตั้งต้องมีความสอดคล้องกัน (อินพุตที่กำหนดควรสร้างเอาต์พุตเดียวกันเสมอ)

โซลูชัน/ตัวอย่าง: ต้องมีการเปลี่ยนแปลงในเครื่องมือบิลด์ต่อไปนี้

ใช้เครื่องมือเปรียบเทียบบิลด์

ในกรณีที่ไม่สามารถหลีกเลี่ยงการเปลี่ยนแปลงไฟล์ที่เกี่ยวข้องกับการบิลด์ได้ AOSP จะมี เครื่องมือเปรียบเทียบการบิลด์ target_files_diff.py ไว้ใช้ในการเปรียบเทียบแพ็กเกจไฟล์ 2 รายการ เครื่องมือนี้จะทำการเปรียบเทียบแบบเรียกซ้ำระหว่างบิลด์ 2 รายการ โดยไม่รวมการเปลี่ยนแปลงไฟล์ที่เกี่ยวข้องกับบิลด์ทั่วไป เช่น

  • การเปลี่ยนแปลงที่คาดไว้ในเอาต์พุตการสร้าง (เช่น เนื่องจากการเปลี่ยนแปลงหมายเลขบิลด์)
  • การเปลี่ยนแปลงเนื่องจากปัญหาที่ทราบในระบบบิลด์ปัจจุบัน

หากต้องการใช้เครื่องมือเปรียบเทียบบิลด์ ให้เรียกใช้คำสั่งต่อไปนี้

target_files_diff.py dir1 dir2

dir1 และ dir2 คือไดเรกทอรีฐานที่มีไฟล์เป้าหมายที่แยกออกมา สำหรับการสร้างแต่ละครั้ง

รักษาการจัดสรรบล็อกให้สอดคล้องกัน

แม้ว่าเนื้อหาของไฟล์จะยังคงเหมือนเดิมระหว่าง 2 บิลด์ แต่บล็อกจริง ที่เก็บข้อมูลอาจมีการเปลี่ยนแปลง ด้วยเหตุนี้ โปรแกรมอัปเดตจึงต้องดำเนินการ I/O ที่ไม่จำเป็น เพื่อย้ายบล็อกไปมาสำหรับการอัปเดต OTA

ในการอัปเดต OTA แบบเสมือน A/B, I/O ที่ไม่จำเป็นอาจเพิ่มพื้นที่เก็บข้อมูลที่จำเป็นอย่างมาก เพื่อจัดเก็บสแนปชอตแบบคัดลอกเมื่อมีการแก้ไข ในการอัปเดต OTA ที่ไม่ใช่ A/B การย้ายบล็อกไปมาเพื่อ การอัปเดต OTA จะทำให้เวลาในการอัปเดตนานขึ้นเนื่องจากมีการรับส่งข้อมูลมากขึ้นจากการย้ายบล็อก

ใน Android 7.0 Google ได้ขยายmake_ext4fsเครื่องมือสำหรับ การจัดสรรบล็อกให้สอดคล้องกันในทุกบิลด์เพื่อแก้ไขปัญหานี้ make_ext4fs เครื่องมือนี้ยอมรับ -d base_fs แฟล็กที่ไม่บังคับซึ่งพยายามจัดสรรไฟล์ไปยังบล็อกเดียวกัน เมื่อสร้างอิมเมจ ext4 คุณสามารถแยกไฟล์การแมปบล็อก (เช่น ไฟล์แมป base_fs) จากไฟล์ zip ของไฟล์เป้าหมายของบิลด์ก่อนหน้า สำหรับแต่ละ ext4 พาร์ติชัน จะมีไฟล์ .map ในไดเรกทอรี IMAGES (เช่น IMAGES/system.map สอดคล้องกับพาร์ติชัน system) จากนั้นจะเช็คอินbase_fsไฟล์เหล่านี้และ ระบุผ่าน PRODUCT_<partition>_BASE_FS_PATH ได้ ดังตัวอย่างนี้

  PRODUCT_SYSTEM_BASE_FS_PATH := path/to/base_fs_files/base_system.map
  PRODUCT_SYSTEM_EXT_BASE_FS_PATH := path/to/base_fs_files/base_system_ext.map
  PRODUCT_VENDOR_BASE_FS_PATH := path/to/base_fs_files/base_vendor.map
  PRODUCT_PRODUCT_BASE_FS_PATH := path/to/base_fs_files/base_product.map
  PRODUCT_ODM_BASE_FS_PATH := path/to/base_fs_files/base_odm.map

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

หลีกเลี่ยงการอัปเดตแอป

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