หน้านี้อธิบายการเปลี่ยนแปลงที่เพิ่มใน AOSP เพื่อลดการเปลี่ยนแปลงไฟล์ที่ไม่จำเป็นระหว่างบิลด์ ผู้ปรับใช้อุปกรณ์ที่ดูแลระบบบิลด์ของตนเองสามารถใช้ข้อมูลนี้เป็นแนวทางในการลดขนาดการอัปเดตแบบ over-the-air (OTA)
การอัปเดต OTA ของ Android ในบางครั้งอาจมีไฟล์ที่เปลี่ยนแปลงซึ่งไม่สอดคล้องกับการเปลี่ยนแปลงโค้ด พวกเขากำลังสร้างสิ่งประดิษฐ์ของระบบ สิ่งนี้สามารถเกิดขึ้นได้เมื่อโค้ดเดียวกัน สร้างในเวลาต่างกัน จากไดเร็กทอรีที่ต่างกัน หรือบนเครื่องที่ต่างกันสร้างไฟล์ที่เปลี่ยนแปลงจำนวนมาก ไฟล์ส่วนเกินดังกล่าวจะเพิ่มขนาดของแพตช์ OTA และทำให้ยากต่อการพิจารณาว่าโค้ดใดที่เปลี่ยนแปลง
เพื่อให้เนื้อหาของ OTA มีความโปร่งใสมากขึ้น AOSP ได้รวมการเปลี่ยนแปลงระบบบิลด์ที่ออกแบบมาเพื่อลดขนาดของแพตช์ OTA การเปลี่ยนแปลงไฟล์ที่ไม่จำเป็นระหว่างบิลด์ได้ถูกกำจัดออกไปแล้ว และมีเพียงไฟล์ที่เกี่ยวข้องกับแพตช์เท่านั้นที่จะอยู่ในการอัปเดต OTA AOSP ยังมี เครื่องมือ build diff ซึ่งกรองการเปลี่ยนแปลงไฟล์ที่เกี่ยวข้องกับบิลด์ทั่วไปออกเพื่อให้ไฟล์บิลด์สะอาดขึ้น และ เครื่องมือสร้างแผนที่บล็อก ซึ่งช่วยให้คุณจัดสรรบล็อกให้สอดคล้องกัน
ระบบบิลด์สามารถสร้างแพตช์ขนาดใหญ่โดยไม่จำเป็นได้หลายวิธี เพื่อลดปัญหานี้ ใน Android 8.0 ขึ้นไป จึงมีการนำคุณลักษณะใหม่มาใช้เพื่อลดขนาดแพตช์สำหรับแต่ละไฟล์ที่แตกต่างกัน การปรับปรุงที่ลดขนาดแพ็คเกจการอัปเดต OTA มีดังต่อไปนี้:
- การใช้ Brotli ซึ่งเป็นอัลกอริธึมการบีบอัดแบบไม่สูญเสียข้อมูลสำหรับวัตถุประสงค์ทั่วไปสำหรับรูปภาพแบบเต็มในการอัปเดตอุปกรณ์ที่ไม่ใช่ A/B สามารถปรับแต่ง Brotli เพื่อเพิ่มประสิทธิภาพการบีบอัดได้ ในการอัปเดตที่ใหญ่กว่าที่ประกอบด้วยสองบล็อกขึ้นไปในระบบไฟล์ (เช่น
system.img
) ผู้ผลิตอุปกรณ์หรือพันธมิตรสามารถเพิ่มอัลกอริธึมการบีบอัดของตนเองได้ และสามารถใช้อัลกอริธึมการบีบอัดที่แตกต่างกันในบล็อกต่างๆ ของการอัปเดตเดียวกัน - การใช้การบีบอัดซ้ำของ Puffin ซึ่งเป็นเครื่องมือการแพตช์ที่กำหนดได้สำหรับสตรีมแบบปล่อยลม ที่จัดการฟังก์ชันการบีบอัดและดิฟสำหรับการสร้างการอัปเดต A/B OTA
- การเปลี่ยนแปลงการใช้เครื่องมือสร้างเดลต้า เช่น วิธีการใช้ไลบรารี
bsdiff
สำหรับการบีบอัดแพตช์ ใน Android 9 ขึ้นไป เครื่องมือbsdiff
จะเลือกอัลกอริธึมการบีบอัดที่จะให้ผลการบีบอัดที่ดีที่สุดสำหรับแพตช์ - การปรับปรุง
update_engine
ส่งผลให้มีการใช้หน่วยความจำน้อยลงเมื่อใช้โปรแกรมแก้ไขสำหรับการอัปเดตอุปกรณ์ A/B - ปรับปรุงการแยกไฟล์ zip ขนาดใหญ่สำหรับการอัปเดต OTA แบบบล็อก โหมดใน
imgdiff
แบ่งไฟล์ APK ขนาดใหญ่ตามชื่อรายการ สิ่งนี้จะสร้างแพตช์ที่มีขนาดเล็กลงเมื่อเทียบกับการแยกไฟล์แบบเส้นตรงและใช้เครื่องมือbsdiff
เพื่อบีบอัดไฟล์เหล่านั้น
ส่วนต่อไปนี้จะกล่าวถึงปัญหาต่างๆ ที่ส่งผลต่อขนาดการอัปเดต OTA โซลูชัน และตัวอย่างการใช้งานใน AOSP
ลำดับไฟล์
ปัญหา : ระบบไฟล์ไม่รับประกันลำดับไฟล์เมื่อถูกถามถึงรายการไฟล์ในไดเร็กทอรี แม้ว่าโดยทั่วไปแล้วจะเหมือนกันสำหรับการเช็คเอาท์เดียวกัน เครื่องมือเช่น ls
เรียงลำดับผลลัพธ์ตามค่าเริ่มต้น แต่ฟังก์ชันไวด์การ์ดที่ใช้โดยคำสั่งเช่น find
และ make
don't sort ก่อนใช้เครื่องมือเหล่านี้ คุณต้องเรียงลำดับผลลัพธ์
วิธีแก้ไข : เมื่อคุณใช้เครื่องมือต่างๆ เช่น 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 build เป็นพาธสัมพัทธ์ ดังนั้น __FILE__
ใน C/C++ จึงไม่มีปัญหา อย่างไรก็ตาม สัญลักษณ์การดีบักจะเข้ารหัสชื่อพาธแบบเต็มโดยค่าเริ่มต้น และ .note.gnu.build-id
ถูกสร้างขึ้นจากการแฮชไบนารี่แบบ pre-stripped ดังนั้นจะเปลี่ยนหากสัญลักษณ์ดีบักเปลี่ยนไป
วิธีแก้ไข: AOSP สร้างเส้นทางการดีบักให้สัมพันธ์กัน สำหรับรายละเอียด โปรดดู CL: https://android.googlesource.com/platform/build/+/6a66a887baadc9eb3d0d60e26f748b8453e27a02
การประทับเวลา
ปัญหา: การ ประทับเวลาในเอาต์พุตของบิลด์ส่งผลให้เกิดการเปลี่ยนแปลงไฟล์โดยไม่จำเป็น มีแนวโน้มว่าจะเกิดขึ้นในสถานที่ต่อไปนี้:
-
__DATE__/__TIME__/__TIMESTAMP__
มาโครในโค้ด C หรือ C++ - การประทับเวลาในไฟล์เก็บถาวรแบบซิป
วิธีแก้ปัญหา/ตัวอย่าง: หากต้องการลบการประทับเวลาออกจากเอาต์พุตบิลด์ ให้ใช้คำแนะนำด้านล่างใน __DATE__/__TIME__/__TIMESTAMP__ ใน C/C++ และการ ประทับเวลาแบบฝังในที่เก็บถาวร
__DATE__/__TIME__/__TIMESTAMP__ ใน C/C++
มาโครเหล่านี้สร้างเอาต์พุตที่แตกต่างกันสำหรับบิลด์ที่ต่างกันเสมอ ดังนั้นอย่าใช้พวกมัน ต่อไปนี้คือตัวเลือกสองสามตัวในการกำจัดมาโครเหล่านี้:
- ลบออก ตัวอย่างเช่น อ้างถึง https://android.googlesource.com/platform/system/core/+/30622bbb209db187f6851e4cf0cdaa147c2fca9f
- หากต้องการระบุไบนารีที่ทำงานอยู่โดยไม่ซ้ำกัน ให้อ่าน build-id จากส่วนหัวของ ELF
- หากต้องการทราบว่าระบบปฏิบัติการถูกสร้างขึ้นเมื่อใด ให้อ่าน
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/+/master/tools/ziptime/
) รีเซ็ตการประทับเวลาปกติในส่วนหัวของ zip สำหรับรายละเอียด โปรดดูที่ ไฟล์ README
เครื่องมือ signapk
ตั้งค่าการประทับเวลาสำหรับไฟล์ APK ที่อาจแตกต่างกันไปตามเขตเวลาของเซิร์ฟเวอร์ สำหรับรายละเอียด โปรดดูที่ CL https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028
สตริงเวอร์ชัน
ปัญหา: สตริงเวอร์ชัน APK มักจะมี BUILD_NUMBER
ต่อท้ายเวอร์ชันฮาร์ดโค้ด แม้ว่าจะไม่มีอะไรเปลี่ยนแปลงใน APK ดังนั้น APK จะยังคงแตกต่างออกไป
วิธีแก้ไข: ลบหมายเลขบิลด์ออกจากสตริงเวอร์ชัน APK
วิธีแก้ไข: ลบหมายเลขบิลด์ออกจากสตริงเวอร์ชัน APK
ตัวอย่าง:
- https://android.googlesource.com/platform/packages/apps/Camera2/+/5e0f4cf699a4c7c95e2c38ae3babe6f20c258d27
- https://android.googlesource.com/platform/build/+/d75d893da8f97a5c7781142aaa7a16cf1dbb669c
เปิดใช้งานการคำนวณความจริงบนอุปกรณ์
หากอุปกรณ์ของคุณเปิดใช้งาน dm-verity เครื่องมือ OTA จะรับการกำหนดค่า verity ของคุณโดยอัตโนมัติ และเปิดใช้งานการคำนวณความถูกต้องบนอุปกรณ์ วิธีนี้ช่วยให้คำนวณบล็อก verity บนอุปกรณ์ Android แทนการจัดเก็บเป็นไบต์ดิบในแพ็คเกจ OTA ของคุณ บล็อก Verity สามารถใช้ประมาณ 16MB สำหรับพาร์ติชัน 2GB
อย่างไรก็ตาม การคำนวณจริงบนอุปกรณ์อาจใช้เวลานาน โดยเฉพาะอย่างยิ่ง รหัสแก้ไขข้อผิดพลาดการส่งต่ออาจใช้เวลานาน บนอุปกรณ์พิกเซล มักจะใช้เวลาถึง 10 นาที บนอุปกรณ์ระดับล่างอาจใช้เวลานานกว่านี้ หากคุณต้องการปิดใช้งานการคำนวณ verity บนอุปกรณ์ แต่ยังคงเปิดใช้งาน dm-verity คุณสามารถทำได้โดยส่ง ota_from_target_files
--disable_fec_computation
สร้างการอัปเดต OTA การตั้งค่าสถานะนี้ปิดใช้งานการคำนวณความถูกต้องบนอุปกรณ์ระหว่างการอัปเดต OTA ลดเวลาการติดตั้ง OTA แต่เพิ่มขนาดแพ็คเกจ OTA หากอุปกรณ์ของคุณไม่ได้เปิดใช้งาน dm-verity การส่งแฟล็กนี้จะไม่มีผลใดๆ
เครื่องมือสร้างที่สม่ำเสมอ
ปัญหา: เครื่องมือที่สร้างไฟล์ที่ติดตั้งจะต้องสอดคล้องกัน (อินพุตที่กำหนดควรให้ผลลัพธ์เดียวกันเสมอ)
วิธีแก้ปัญหา/ตัวอย่าง: จำเป็นต้องทำการเปลี่ยนแปลงในเครื่องมือสร้างต่อไปนี้:
- ประกาศ ผู้สร้างไฟล์ . ผู้สร้างไฟล์ NOTICE ถูกเปลี่ยนเพื่อสร้างคอลเล็กชัน NOTICE ที่ทำซ้ำได้ อ้างถึง CL: https://android.googlesource.com/platform/build/+/8ae4984c2c8009e7a08e2a76b1762c2837ad4f64
- Java Android Compiler Kit (แจ็ค) Jack toolchain จำเป็นต้องมีการอัปเดตเพื่อจัดการกับการเปลี่ยนแปลงในลำดับของ Constructor ที่สร้างขึ้นเป็นครั้งคราว เพิ่ม accessors ที่กำหนดสำหรับคอนสตรัคเตอร์ใน 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'd (.odex) ของแอปพลิเคชัน ไฟล์ pre-dexopt'd (.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 ที่ไม่จำเป็นสามารถเพิ่มพื้นที่จัดเก็บข้อมูลที่จำเป็นสำหรับการจัดเก็บสแน็ปช็อตการคัดลอกเมื่อเขียนได้อย่างมาก ในการอัปเดต OTA ที่ไม่ใช่ A/B การย้ายบล็อกไปรอบ ๆ สำหรับการอัปเดต 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 พวกเขาอาจมีแอปที่อัปเดตแล้วหรือเวอร์ชันที่ใหม่กว่าซึ่งได้รับโดยตรงจากร้านแอป