หน้านี้อธิบายการเปลี่ยนแปลงที่เพิ่มใน AOSP เพื่อลดการเปลี่ยนแปลงไฟล์ที่ไม่จำเป็นระหว่างบิลด์ ผู้ดำเนินการอุปกรณ์ที่ดูแลระบบบิลด์ของตนเองสามารถใช้ข้อมูลนี้เป็นแนวทางในการลดขนาดการอัปเดตแบบ over-the-air (OTA)
บางครั้งการอัปเดต Android OTA จะมีไฟล์ที่เปลี่ยนแปลงซึ่งไม่สอดคล้องกับการเปลี่ยนแปลงรหัส พวกเขากำลังสร้างสิ่งประดิษฐ์ของระบบ กรณีนี้อาจเกิดขึ้นเมื่อรหัสเดียวกัน สร้างในเวลาต่างกัน จากไดเร็กทอรีต่างกัน หรือในเครื่องอื่นสร้างไฟล์ที่เปลี่ยนแปลงจำนวนมาก ไฟล์ส่วนเกินดังกล่าวจะเพิ่มขนาดของแพตช์ OTA และทำให้ยากต่อการระบุรหัสที่เปลี่ยนแปลง
เพื่อทำให้เนื้อหาของ OTA มีความโปร่งใสมากขึ้น AOSP ได้รวมการเปลี่ยนแปลงระบบการสร้างที่ออกแบบมาเพื่อลดขนาดของแพตช์ OTA การเปลี่ยนแปลงไฟล์ที่ไม่จำเป็นระหว่างบิลด์ถูกกำจัดออกไปแล้ว และมีเพียงไฟล์ที่เกี่ยวข้องกับแพตช์เท่านั้นที่มีในการอัปเดต OTA AOSP ยังมี เครื่องมือ build diff ซึ่งกรองการเปลี่ยนแปลงไฟล์ที่เกี่ยวข้องกับ build ทั่วไปเพื่อให้ไฟล์ build diff สะอาดขึ้น และ เครื่องมือการแมปบล็อก ซึ่งช่วยให้คุณจัดสรรบล็อกให้สอดคล้องกัน
ระบบบิลด์สามารถสร้างแพตช์ขนาดใหญ่โดยไม่จำเป็นได้หลายวิธี เพื่อลดปัญหานี้ ใน Android 8.0 และสูงกว่า มีการใช้คุณสมบัติใหม่เพื่อลดขนาดแพตช์สำหรับความแตกต่างของไฟล์แต่ละไฟล์ การปรับปรุงที่ลดขนาดแพ็คเกจการอัปเดต OTA รวมถึงสิ่งต่อไปนี้:
- การใช้ Brotli ซึ่งเป็นอัลกอริธึมการบีบอัดแบบไม่สูญเสียข้อมูลเพื่อจุดประสงค์ทั่วไปสำหรับรูปภาพแบบเต็มในการอัปเดตอุปกรณ์ที่ไม่ใช่ A/B สามารถปรับแต่ง Brotli เพื่อเพิ่มประสิทธิภาพการบีบอัด ในการอัปเดตขนาดใหญ่ที่ประกอบด้วยสองบล็อกขึ้นไปในระบบไฟล์ (เช่น
system.img
) ผู้ผลิตอุปกรณ์หรือคู่ค้าสามารถเพิ่มอัลกอริทึมการบีบอัดของตนเองได้ และสามารถใช้อัลกอริทึมการบีบอัดที่แตกต่างกันในบล็อกต่างๆ ของการอัปเดตเดียวกัน - การใช้ Puffin recompression ซึ่งเป็นเครื่องมือการแพตช์เชิงกำหนดสำหรับการยุบสตรีม ที่จัดการฟังก์ชันการบีบอัดและ diff สำหรับการสร้างการอัปเดต A/B OTA
- การเปลี่ยนแปลงการใช้เครื่องมือสร้างเดลต้า เช่น วิธีการใช้ไลบรารี
bsdiff
สำหรับการบีบอัดแพตช์ ใน Android 9 ขึ้นไป เครื่องมือbsdiff
จะเลือกอัลกอริทึมการบีบอัดที่จะให้ผลลัพธ์การบีบอัดที่ดีที่สุดสำหรับแพตช์ - การปรับปรุง
update_engine
ทำให้ใช้หน่วยความจำน้อยลงเมื่อมีการใช้แพตช์สำหรับการอัปเดตอุปกรณ์ A/B - การปรับปรุงการแยกไฟล์ zip ขนาดใหญ่สำหรับการอัปเดต OTA แบบบล็อก โหมดใน
imgdiff
แยกไฟล์ APK ขนาดใหญ่ตามชื่อรายการ สิ่งนี้สร้างแพตช์ที่เล็กกว่าเมื่อเทียบกับการแยกไฟล์แบบเส้นตรงและใช้เครื่องมือbsdiff
เพื่อบีบอัดไฟล์
ส่วนต่อไปนี้จะกล่าวถึงปัญหาต่างๆ ที่ส่งผลต่อขนาดการอัปเดต OTA วิธีแก้ไข และตัวอย่างการใช้งานใน AOSP
ลำดับไฟล์
ปัญหา : ระบบไฟล์ไม่รับประกันลำดับไฟล์เมื่อถูกถามถึงรายการไฟล์ในไดเร็กทอรี แม้ว่าโดยทั่วไปจะเหมือนกันสำหรับการเช็คเอาต์เดียวกัน เครื่องมือเช่น ls
จัดเรียงผลลัพธ์ตามค่าเริ่มต้น แต่ฟังก์ชันตัวแทนที่ใช้โดยคำสั่งเช่น find
และ make
ไม่เรียงลำดับ ก่อนใช้เครื่องมือเหล่านี้ คุณต้องเรียงลำดับผลลัพธ์
วิธีแก้ไข : เมื่อคุณใช้เครื่องมือ เช่น find
และ make
ด้วยฟังก์ชันไวด์การ์ด ให้เรียงลำดับเอาต์พุตของคำสั่งเหล่านี้ก่อนใช้งาน เมื่อใช้ $(wildcard)
หรือ $(shell find)
ในไฟล์ Android.mk
ให้จัดเรียงด้วย เครื่องมือบางอย่าง เช่น Java ทำการเรียงลำดับอินพุต ดังนั้นก่อนที่คุณจะจัดเรียงไฟล์ ให้ตรวจสอบว่าเครื่องมือที่คุณใช้ยังไม่ได้ดำเนินการดังกล่าว
ตัวอย่าง: หลายอินสแตนซ์ได้รับการแก้ไขในระบบบิลด์หลักโดยใช้มาโครในตัว all-*-files-under
ซึ่งรวมถึง all-cpp-files-under
(เนื่องจากคำจำกัดความหลายรายการถูกกระจายออกไปใน makefile อื่นๆ) สำหรับรายละเอียด โปรดดูต่อไปนี้:
- https://android.googlesource.com/platform/build/+/4d66adfd0e6d599d8502007e4ea9aaf82e95569f
- https://android.googlesource.com/platform/build/+/379f9f9cec4fe1c66b6d60a6c19fecb81b9eb410
- https://android.googlesource.com/platform/build/+/7c3e3f8314eec2c053012dd97d2ae649ebeb5653
- https://android.googlesource.com/platform/build/+/5c64b4e81c1331cab56d8a8c201f26bb263b630c
สร้างไดเร็กทอรี
ปัญหา: การเปลี่ยนไดเร็กทอรีที่สร้างสิ่งต่าง ๆ อาจทำให้ไบนารีแตกต่างกัน เส้นทางส่วนใหญ่ในบิลด์ Android เป็นเส้นทางสัมพัทธ์ ดังนั้น __FILE__
ใน C/C++ จึงไม่ใช่ปัญหา อย่างไรก็ตาม สัญลักษณ์การดีบักจะเข้ารหัสชื่อพาธแบบเต็มตามค่าเริ่มต้น และ .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++
มาโครเหล่านี้สร้างผลลัพธ์ที่แตกต่างกันสำหรับรุ่นต่างๆ เสมอ ดังนั้นอย่าใช้มาโครเหล่านี้ ต่อไปนี้คือตัวเลือกบางส่วนสำหรับการกำจัดมาโครเหล่านี้:
- ลบออก ตัวอย่างเช่น โปรดดู https://android.googlesource.com/platform/system/core/+/30622bbb209db187f6851e4cf0cdaa147c2fca9f
- หากต้องการระบุไบนารีที่กำลังทำงานอยู่โดยเฉพาะ ให้อ่าน build-id จากส่วนหัวของ ELF
- หากต้องการทราบว่า OS ถูกสร้างขึ้นเมื่อใด โปรดอ่าน
ro.build.date
(วิธีนี้ใช้ได้กับทุกอย่างยกเว้นการสร้างส่วนเพิ่ม ซึ่งอาจไม่อัปเดตวันที่นี้) ตัวอย่างเช่น โปรดดู https://android.googlesource.com/platform/external/libchrome/+/8b7977eccc94f6b3a3896cd13b4aeacbfa1e0f84
การประทับเวลาแบบฝังในไฟล์เก็บถาวร (zip, jar)
Android 7.0 แก้ไขปัญหาการประทับเวลาแบบฝังในไฟล์ zip โดยเพิ่ม -X
ให้กับการใช้คำสั่ง zip
ทั้งหมด สิ่งนี้จะลบ UID/GID ของตัวสร้างและการประทับเวลา Unix ที่ขยายออกจากไฟล์ zip
เครื่องมือใหม่ ziptime
(อยู่ใน /platform/build/+/main/tools/ziptime/
) จะรีเซ็ตการประทับเวลาปกติในส่วนหัวของ zip สำหรับรายละเอียด โปรดดูที่ ไฟล์ README
เครื่องมือ signapk
ตั้งค่าการประทับเวลาสำหรับไฟล์ APK ที่อาจแตกต่างกันไปขึ้นอยู่กับเขตเวลาของเซิร์ฟเวอร์ สำหรับรายละเอียด โปรดดู CL https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028
สตริงเวอร์ชัน
ปัญหา: สตริงเวอร์ชัน APK มักจะมี BUILD_NUMBER
ต่อท้ายเวอร์ชันฮาร์ดโค้ด แม้ว่าจะไม่มีอะไรเปลี่ยนแปลงใน APK ดังนั้น APK จะยังคงแตกต่างออกไป
วิธีแก้ไข: ลบหมายเลขบิลด์ออกจากสตริงเวอร์ชัน APK
ตัวอย่าง:
- https://android.googlesource.com/platform/packages/apps/Camera2/+/5e0f4cf699a4c7c95e2c38ae3babe6f20c258d27
- https://android.googlesource.com/platform/build/+/d75d893da8f97a5c7781142aaa7a16cf1dbb669c
เปิดใช้งานการคำนวณความถูกต้องบนอุปกรณ์
หากเปิดใช้งาน dm-verity ในอุปกรณ์ของคุณ เครื่องมือ OTA จะรับการกำหนดค่า verity ของคุณโดยอัตโนมัติ และเปิดใช้งานการคำนวณ verity ในอุปกรณ์ สิ่งนี้ทำให้สามารถคำนวณ verity block บนอุปกรณ์ Android แทนที่จะจัดเก็บเป็นไบต์ดิบในแพ็คเกจ OTA ของคุณ บล็อก Verity สามารถใช้ประมาณ 16MB สำหรับพาร์ติชัน 2GB
อย่างไรก็ตาม ความถูกต้องของการประมวลผลบนอุปกรณ์อาจใช้เวลานาน โดยเฉพาะอย่างยิ่ง รหัสแก้ไขข้อผิดพลาดในการส่งต่ออาจใช้เวลานาน บนอุปกรณ์พิกเซล มักจะใช้เวลาถึง 10 นาที สำหรับอุปกรณ์ระดับล่าง อาจใช้เวลานานกว่านั้น หากคุณต้องการปิดใช้งานการคำนวณความถูกต้องบนอุปกรณ์ แต่ยังคงเปิดใช้งาน dm-verity คุณสามารถทำได้โดยส่ง --disable_fec_computation
ไปยังเครื่องมือ ota_from_target_files
เมื่อสร้างการอัปเดต OTA การตั้งค่าสถานะนี้จะปิดใช้งานการคำนวณความถูกต้องบนอุปกรณ์ระหว่างการอัปเดต OTA ลดเวลาในการติดตั้ง OTA แต่เพิ่มขนาดแพ็คเกจ OTA หากอุปกรณ์ของคุณไม่ได้เปิดใช้งาน dm-verity การส่งแฟล็กนี้จะไม่มีผลใดๆ
เครื่องมือสร้างที่สอดคล้องกัน
ปัญหา: เครื่องมือที่สร้างไฟล์ที่ติดตั้งต้องสอดคล้องกัน (อินพุตที่กำหนดควรสร้างเอาต์พุตเดียวกันเสมอ)
วิธีแก้ไข/ตัวอย่าง: จำเป็นต้องมีการเปลี่ยนแปลงในเครื่องมือสร้างต่อไปนี้:
- ผู้สร้างไฟล์ NOTICE . ผู้สร้างไฟล์ประกาศถูกเปลี่ยนเพื่อสร้างคอลเลกชันประกาศที่ทำซ้ำได้ อ้างถึง CL: https://android.googlesource.com/platform/build/+/8ae4984c2c8009e7a08e2a76b1762c2837ad4f64
- ชุดคอมไพเลอร์ Java Android (แจ็ค) Jack toolchain ต้องการการอัปเดตเพื่อจัดการการเปลี่ยนแปลงเป็นครั้งคราวในลำดับตัวสร้างที่สร้างขึ้น มีการเพิ่มตัวเข้าถึงเชิงกำหนดสำหรับตัวสร้างใน toolchain: https://android.googlesource.com/toolchain/jack/+/056a5425b3ef57935206c19ecb198a89221ca64b
- คอมไพเลอร์ ART AOT (dex2oat) . ไบนารีคอมไพเลอร์ ART ได้รับการอัปเดตที่เพิ่มตัวเลือกในการสร้างอิมเมจเชิงกำหนด: https://android.googlesource.com/platform/art/+/ace0dc1dd5480ad458e622085e51583653853fb9
- ไฟล์ libpac.so (V8) ทุกบิลด์สร้างไฟล์
/system/lib/libpac.so
ที่แตกต่างกัน เนื่องจากสแน็ปช็อต V8 เปลี่ยนไปสำหรับแต่ละบิลด์ วิธีแก้ไขคือลบสแนปชอต: https://android.googlesource.com/platform/external/v8/+/e537f38c36600fd0f3026adba6b3f4cbcee1fb29 - ไฟล์แอปพลิเคชัน pre-dexopt (.odex) ไฟล์ pre-dexopt (.odex) มีช่องว่างภายในที่ไม่ได้กำหนดค่าเริ่มต้นไว้บนระบบ 64 บิต สิ่งนี้ได้รับการแก้ไข: https://android.googlesource.com/platform/art/+/34ed3afc41820c72a3c0ab9770be66b6668aa029
ใช้เครื่องมือสร้างความแตกต่าง
สำหรับกรณีที่ไม่สามารถกำจัดการเปลี่ยนแปลงไฟล์ที่เกี่ยวข้องกับบิลด์ได้ AOSP จะมีเครื่องมือ build diff, target_files_diff.py
เพื่อใช้ในการเปรียบเทียบแพ็คเกจไฟล์สองไฟล์ เครื่องมือนี้ดำเนินการผลต่างแบบเรียกซ้ำระหว่างสองบิลด์ โดยไม่รวมการเปลี่ยนแปลงไฟล์ที่เกี่ยวข้องกับบิลด์ทั่วไป เช่น
- การเปลี่ยนแปลงที่คาดหวังในเอาต์พุตของบิลด์ (เช่น เนื่องจากการเปลี่ยนแปลงหมายเลขบิลด์)
- การเปลี่ยนแปลงเนื่องจากปัญหาที่ทราบในระบบการสร้างปัจจุบัน
ในการใช้เครื่องมือ build diff ให้รันคำสั่งต่อไปนี้:
target_files_diff.py dir1 dir2
dir1
และ dir2
เป็นไดเร็กทอรีพื้นฐานที่มีไฟล์เป้าหมายที่แตกออกมาสำหรับแต่ละบิลด์
รักษาการจัดสรรบล็อกให้สอดคล้องกัน
สำหรับไฟล์ที่กำหนด แม้ว่าเนื้อหาจะยังคงเหมือนเดิมระหว่างสองบิลด์ แต่บล็อกจริงที่เก็บข้อมูลอาจมีการเปลี่ยนแปลง เป็นผลให้ตัวอัปเดตต้องทำ I/O ที่ไม่จำเป็นเพื่อย้ายบล็อกไปรอบๆ สำหรับการอัปเดต OTA
ในการอัปเดต Virtual A/B OTA I/O ที่ไม่จำเป็นสามารถเพิ่มพื้นที่เก็บข้อมูลที่จำเป็นอย่างมากในการจัดเก็บสแน็ปช็อตแบบคัดลอกเมื่อเขียน ในการอัปเดตแบบ non-A/B OTA การย้ายบล็อกไปรอบๆ สำหรับการอัปเดต OTA จะทำให้มีเวลาอัปเดตเนื่องจากมี I/O มากขึ้นเนื่องจากการย้ายบล็อก
เพื่อแก้ไขปัญหานี้ ใน 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 สำหรับการอัปเดต Virtual A/B จะลดจำนวนพื้นที่จัดเก็บที่ต้องใช้ OTA ลงอย่างมาก
หลีกเลี่ยงการอัปเดตแอป
นอกจากการลดความแตกต่างของบิวด์แล้ว คุณยังสามารถลดขนาดการอัปเดต OTA ได้โดยไม่รวมการอัปเดตสำหรับแอปที่ได้รับการอัปเดตผ่านร้านแอป APK มักจะประกอบด้วยส่วนสำคัญของพาร์ติชันต่างๆ บนอุปกรณ์ การรวมแอพเวอร์ชันล่าสุดที่อัปเดตโดยร้านแอพในการอัปเดต OTA อาจส่งผลกระทบขนาดใหญ่ต่อแพ็คเกจ OTA และให้ประโยชน์แก่ผู้ใช้เพียงเล็กน้อย เมื่อผู้ใช้ได้รับแพ็คเกจ OTA พวกเขาอาจมีแอปที่อัปเดตแล้วหรือเวอร์ชันที่ใหม่กว่าซึ่งได้รับโดยตรงจากร้านแอป