หน้านี้อธิบายการเปลี่ยนแปลงที่เพิ่มใน AOSP เพื่อลดการเปลี่ยนแปลงไฟล์ที่ไม่จำเป็นระหว่างบิลด์ ผู้ใช้อุปกรณ์ที่ดูแลระบบการสร้างของตนเองสามารถใช้ข้อมูลนี้เป็นแนวทางในการลดขนาดของการอัปเดตแบบ over-the-air (OTA)
การอัปเดต Android OTA บางครั้งมีไฟล์ที่เปลี่ยนแปลงซึ่งไม่สอดคล้องกับการเปลี่ยนแปลงโค้ด จริงๆ แล้วพวกเขากำลังสร้างสิ่งประดิษฐ์ของระบบ กรณีนี้อาจเกิดขึ้นเมื่อโค้ดเดียวกัน สร้างในเวลาต่างกัน จากไดเร็กทอรีต่างกัน หรือบนเครื่องอื่นทำให้เกิดไฟล์ที่เปลี่ยนแปลงจำนวนมาก ไฟล์ส่วนเกินดังกล่าวจะเพิ่มขนาดของแพตช์ OTA และทำให้ยากต่อการระบุว่าโค้ดใดที่เปลี่ยนแปลง
เพื่อให้เนื้อหาของ OTA โปร่งใสยิ่งขึ้น AOSP ได้รวมการเปลี่ยนแปลงระบบที่สร้างขึ้นที่ออกแบบมาเพื่อลดขนาดของแพตช์ OTA การเปลี่ยนแปลงไฟล์ที่ไม่จำเป็นระหว่างบิลด์ต่างๆ ได้ถูกกำจัดออกไปแล้ว และมีเพียงไฟล์ที่เกี่ยวข้องกับแพตช์เท่านั้นที่จะอยู่ในการอัปเดต OTA AOSP ยังมี เครื่องมือ build diff ซึ่งจะกรองการเปลี่ยนแปลงไฟล์ที่เกี่ยวข้องกับบิลด์ทั่วไปออก เพื่อให้ไฟล์บิลด์ที่สะอาดกว่า และ เครื่องมือการแมปบล็อก ซึ่งช่วยให้คุณรักษาการจัดสรรบล็อกให้สอดคล้องกัน
ระบบบิลด์สามารถสร้างแพตช์ขนาดใหญ่โดยไม่จำเป็นได้หลายวิธี เพื่อบรรเทาปัญหานี้ ใน Android 8.0 และสูงกว่า จึงมีการนำฟีเจอร์ใหม่มาใช้เพื่อลดขนาดแพตช์สำหรับแต่ละไฟล์ที่ต่างกัน การปรับปรุงที่ลดขนาดแพ็คเกจการอัพเดต OTA มีดังต่อไปนี้:
- การใช้ Brotli ซึ่งเป็นอัลกอริธึมการบีบอัดแบบไม่สูญเสียข้อมูลทั่วไปสำหรับรูปภาพเต็มในการอัปเดตอุปกรณ์ที่ไม่ใช่ A/B Brotli สามารถปรับแต่งเพื่อเพิ่มประสิทธิภาพการบีบอัดได้ ในการอัปเดตขนาดใหญ่ที่ประกอบด้วยบล็อกตั้งแต่สองบล็อกขึ้นไปในระบบไฟล์ (เช่น
system.img
) ผู้ผลิตอุปกรณ์หรือคู่ค้าสามารถเพิ่มอัลกอริธึมการบีบอัดของตนเอง และสามารถใช้อัลกอริธึมการบีบอัดที่แตกต่างกันบนบล็อกที่แตกต่างกันของการอัพเดตเดียวกันได้ - การใช้การบีบอัดใหม่ของ Puffin ซึ่งเป็นเครื่องมือแพตช์ที่กำหนดขึ้นสำหรับสตรีมแบบยุบ ที่จัดการฟังก์ชันการบีบอัดและ 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
(เนื่องจากคำจำกัดความหลายคำกระจายอยู่ใน makefiles อื่น ๆ ) สำหรับรายละเอียด ให้อ้างอิงกับต่อไปนี้:
- 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
การประทับเวลา
ปัญหา: การประทับเวลาในเอาต์พุตของ build ส่งผลให้เกิดการเปลี่ยนแปลงไฟล์ที่ไม่จำเป็น สิ่งนี้น่าจะเกิดขึ้นในสถานที่ต่อไปนี้:
-
__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
- หากต้องการทราบว่าระบบปฏิบัติการถูกสร้างขึ้นเมื่อใด โปรดอ่าน
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
เปิดใช้งานการคำนวณ Verity บนอุปกรณ์
หากเปิดใช้งาน dm-verity บนอุปกรณ์ของคุณ เครื่องมือ OTA จะรับการกำหนดค่า Verity ของคุณโดยอัตโนมัติ และเปิดใช้งานการคำนวณ Verity บนอุปกรณ์ ซึ่งช่วยให้สามารถคำนวณบล็อก Verity บนอุปกรณ์ Android แทนที่จะจัดเก็บเป็นไบต์ดิบในแพ็คเกจ OTA ของคุณ บล็อก Verity สามารถใช้พื้นที่ประมาณ 16MB สำหรับพาร์ติชัน 2GB
อย่างไรก็ตาม การประมวลผลข้อมูลจริงบนอุปกรณ์อาจใช้เวลานาน โดยเฉพาะรหัสแก้ไขข้อผิดพลาดการส่งต่ออาจใช้เวลานาน บนอุปกรณ์พิกเซล อาจใช้เวลานานถึง 10 นาที สำหรับอุปกรณ์ระดับล่างอาจใช้เวลานานกว่านั้น หากคุณต้องการปิดใช้งานการคำนวณ Verity บนอุปกรณ์ แต่ยังคงเปิดใช้งาน dm-verity คุณสามารถทำได้โดยส่ง --disable_fec_computation
ไปยังเครื่องมือ ota_from_target_files
เมื่อสร้างการอัปเดต OTA การตั้งค่าสถานะนี้จะปิดใช้งานการคำนวณความถูกต้องบนอุปกรณ์ระหว่างการอัปเดต OTA ลดเวลาในการติดตั้ง OTA แต่เพิ่มขนาดแพ็คเกจ OTA หากอุปกรณ์ของคุณไม่ได้เปิดใช้งาน dm-verity การส่งแฟล็กนี้จะไม่มีผลใดๆ
เครื่องมือสร้างที่สอดคล้องกัน
ปัญหา: เครื่องมือที่สร้างไฟล์ที่ติดตั้งจะต้องสอดคล้องกัน (อินพุตที่กำหนดควรให้ผลลัพธ์เดียวกันเสมอ)
วิธีแก้ไข/ตัวอย่าง: จำเป็นต้องมีการเปลี่ยนแปลงในเครื่องมือสร้างต่อไปนี้:
- ประกาศผู้สร้างไฟล์ . ผู้สร้างไฟล์ประกาศถูกเปลี่ยนเพื่อสร้างคอลเลกชันประกาศที่ทำซ้ำได้ อ้างถึง CL: https://android.googlesource.com/platform/build/+/8ae4984c2c8009e7a08e2a76b1762c2837ad4f64
- ชุดคอมไพเลอร์ Android Java (แจ็ค) Jack toolchain จำเป็นต้องมีการอัปเดตเพื่อจัดการกับการเปลี่ยนแปลงเป็นครั้งคราวในลำดับ Constructor ที่สร้างขึ้น ตัวเข้าถึงที่กำหนดสำหรับตัวสร้างถูกเพิ่มไปยัง 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
ใช้เครื่องมือ build diff
สำหรับกรณีที่ไม่สามารถกำจัดการเปลี่ยนแปลงไฟล์ที่เกี่ยวข้องกับบิลด์ได้ 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 ได้โดยการยกเว้นการอัปเดตสำหรับแอปที่ได้รับการอัปเดตผ่าน App Store APK มักจะประกอบด้วยส่วนสำคัญของพาร์ติชั่นต่างๆ บนอุปกรณ์ การรวมแอปเวอร์ชันล่าสุดที่ได้รับการอัปเดตโดย App Store ในการอัปเดต OTA อาจมีผลกระทบในขนาดใหญ่ต่อแพ็คเกจ OTA และให้ประโยชน์แก่ผู้ใช้เพียงเล็กน้อย เมื่อถึงเวลาที่ผู้ใช้ได้รับแพ็คเกจ OTA พวกเขาอาจมีแอปที่อัปเดตแล้วหรือเวอร์ชันที่ใหม่กว่านั้น ซึ่งได้รับโดยตรงจาก App Store