หน้านี้อธิบายการเปลี่ยนแปลงที่เพิ่มลงใน AOSP เพื่อลดการเปลี่ยนแปลงไฟล์ที่ไม่จำเป็นระหว่างบิลด์ ผู้ติดตั้งใช้งานอุปกรณ์ที่ดูแลระบบบิลด์ของตนเองสามารถใช้ข้อมูลนี้เป็นแนวทางในการลดขนาดการอัปเดตผ่านอากาศ (OTA)
การอัปเดต OTA ของ Android บางครั้งจะมีไฟล์ที่มีการเปลี่ยนแปลงซึ่งไม่สอดคล้องกับการเปลี่ยนแปลงโค้ด จริงๆ แล้วเป็นอาร์ติแฟกต์ของระบบการสร้าง ปัญหานี้อาจเกิดขึ้นเมื่อโค้ดเดียวกันซึ่งสร้างขึ้นในเวลาที่ต่างกัน จากไดเรกทอรีอื่น หรือในเครื่องอื่นสร้างไฟล์ที่มีการเปลี่ยนแปลงจำนวนมาก ไฟล์ส่วนเกินดังกล่าวจะเพิ่มขนาดของแพตช์ OTA และทำให้ระบุโค้ดที่เปลี่ยนแปลงได้ยาก
AOSP มีการรวมการเปลี่ยนแปลงระบบบิลด์ที่ออกแบบมาเพื่อลดขนาดแพตช์ OTA เพื่อให้เนื้อหาของ OTA มีความโปร่งใสมากขึ้น ระบบได้ตัดการเปลี่ยนแปลงไฟล์ที่ไม่จำเป็นระหว่างบิวด์ออกแล้ว และจะมีเฉพาะไฟล์ที่เกี่ยวข้องกับแพตช์เท่านั้นที่จะรวมอยู่ในการอัปเดต OTA AOSP ยังมีเครื่องมือเปรียบเทียบบิลด์ที่กรองการเปลี่ยนแปลงไฟล์ทั่วไปที่เกี่ยวข้องกับบิลด์ออกเพื่อให้การเปรียบเทียบไฟล์บิลด์สะอาดขึ้น และเครื่องมือการแมปบล็อกที่ช่วยให้คุณจัดสรรบล็อกได้อย่างสอดคล้องกัน
ระบบบิลด์สามารถสร้างแพตช์ขนาดใหญ่โดยไม่จำเป็นได้หลายวิธี เพื่อลดปัญหานี้ ใน Android 8.0 ขึ้นไป เราจึงได้ติดตั้งใช้งานฟีเจอร์ใหม่ๆ เพื่อลดขนาดแพตช์สำหรับไฟล์แต่ละไฟล์ที่ต่างกัน การปรับปรุงที่ช่วยลดขนาดแพ็กเกจการอัปเดต OTA มีดังนี้
-
การใช้ ZSTD ซึ่งเป็นอัลกอริทึมการบีบอัดแบบไม่สูญเสียข้อมูลสำหรับวัตถุประสงค์ทั่วไปสำหรับรูปภาพขนาดเต็มในการอัปเดตอุปกรณ์ที่ไม่ใช่ A/B ZSTD สามารถปรับแต่งให้อัตราส่วนการบีบอัดสูงขึ้นได้โดยการเพิ่มความเข้มงวดในการบีบอัด ระดับการบีบอัดจะตั้งค่าในระหว่างการสร้าง OTA และสามารถตั้งค่าได้โดยส่ง Flag
--vabc_compression_param=zstd,$COMPRESSION_LEVEL
-
การเพิ่มขนาดกรอบเวลาการบีบอัดที่ใช้ระหว่าง OTA คุณตั้งค่าขนาดกรอบเวลาการบีบอัดสูงสุดได้โดยการกําหนดค่าพารามิเตอร์การสร้างในไฟล์
.mk
ของอุปกรณ์ ตัวแปรนี้ตั้งค่าเป็นPRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR := 262144
- การใช้การบีบอัดซ้ำของ Puffin ซึ่งเป็นเครื่องมือการปะแก้แบบกำหนดได้สำหรับสตรีม deflate ที่จัดการฟังก์ชันการบีบอัดและ Diff เพื่อสร้างการอัปเดต OTA ของ A/B
-
การเปลี่ยนแปลงการใช้งานเครื่องมือสร้าง Delta เช่น วิธีใช้ไลบรารีเพื่อบีบอัดแพตช์
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
(เนื่องจากคําจํากัดความหลายรายการกระจายอยู่ในไฟล์ Make อื่นๆ)
ดูรายละเอียดได้ที่หัวข้อต่อไปนี้
- 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
จะสร้างขึ้นจากการแฮชไบนารีที่ผ่านการถอดข้อมูลส่วนหน้าแล้ว ดังนั้น .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
- หากต้องการระบุไบนารีที่ทำงานอยู่โดยไม่ซ้ำกัน ให้อ่านรหัสบิลด์จากส่วนหัว 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/+/android16-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
ตัวอย่าง
- https://android.googlesource.com/platform/packages/apps/Camera2/+/5e0f4cf699a4c7c95e2c38ae3babe6f20c258d27
- https://android.googlesource.com/platform/build/+/d75d893da8f97a5c7781142aaa7a16cf1dbb669c
เปิดใช้การคํานวณ Verity ในอุปกรณ์
หากเปิดใช้ dm-verity ในอุปกรณ์ เครื่องมือ OTA จะรับการกำหนดค่า Verity โดยอัตโนมัติ และเปิดใช้การคํานวณ Verity ในอุปกรณ์ ซึ่งจะช่วยให้ระบบคำนวณบล็อกการยืนยันในอุปกรณ์ Android ได้ แทนที่จะจัดเก็บเป็นไบต์ดิบในแพ็กเกจ OTA บล็อก Verity สามารถใช้พื้นที่ประมาณ 16 MB สำหรับพาร์ติชัน 2 GB
อย่างไรก็ตาม การคำนวณความถูกต้องในอุปกรณ์อาจใช้เวลานาน โดยเฉพาะอย่างยิ่ง การส่งต่อโค้ดแก้ไขข้อผิดพลาดอาจใช้เวลานาน ในอุปกรณ์ Pixel มักจะใช้เวลาถึง 10 นาที ในอุปกรณ์ระดับล่างอาจใช้เวลานานกว่านั้น หากต้องการปิดใช้การคํานวณ Verity ในอุปกรณ์ แต่ยังคงเปิดใช้ dm-verity ให้ทําได้โดยส่ง --disable_fec_computation
ไปยังเครื่องมือ ota_from_target_files
เมื่อสร้างการอัปเดต OTA Flag นี้จะปิดใช้การคํานวณความถูกต้องในอุปกรณ์ระหว่างการอัปเดต OTA
ซึ่งจะลดเวลาในการติดตั้ง OTA แต่เพิ่มขนาดแพ็กเกจ OTA หากอุปกรณ์ไม่ได้เปิดใช้ dm-verity การส่ง Flag นี้จะไม่มีผล
เครื่องมือสร้างที่สอดคล้องกัน
ปัญหา: เครื่องมือที่สร้างไฟล์ที่ติดตั้งต้องสอดคล้องกัน (อินพุตหนึ่งๆ ควรให้เอาต์พุตเดียวกันเสมอ)
วิธีแก้ปัญหา/ตัวอย่าง: จำเป็นต้องทำการเปลี่ยนแปลงในเครื่องมือสร้างต่อไปนี้
- เครื่องมือสร้างไฟล์ประกาศ เครื่องมือสร้างไฟล์ประกาศมีการเปลี่ยนแปลงเพื่อสร้างคอลเล็กชันประกาศที่ซ้ำกันได้ โปรดดู CL: https://android.googlesource.com/platform/build/+/8ae4984c2c8009e7a08e2a76b1762c2837ad4f64
- Java Android Compiler Kit (Jack) เครื่องมือทางเทคนิคของ Jack จำเป็นต้องมีการอัปเดตเพื่อจัดการกับการเปลี่ยนแปลงที่เกิดขึ้นเป็นครั้งคราวในลําดับการสร้างที่สร้างขึ้น เพิ่มตัวรับค่าแบบกำหนดให้กับตัวสร้างลงในชุดเครื่องมือ https://android.googlesource.com/toolchain/jack/+/056a5425b3ef57935206c19ecb198a89221ca64b
- คอมไพเลอร์ AOT ของ ART (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) ของแอปพลิเคชัน ไฟล์ก่อนการ Dexopt (.odex) มีการเพิ่มพื้นที่ว่างที่ไม่ได้เริ่มต้นในระบบ 64 บิต รายการนี้ได้รับการแก้ไขแล้ว https://android.googlesource.com/platform/art/+/34ed3afc41820c72a3c0ab9770be66b6668aa029
ใช้เครื่องมือเปรียบเทียบบิลด์
ในกรณีที่ไม่สามารถนําการเปลี่ยนแปลงไฟล์ที่เกี่ยวข้องกับบิลด์ออก 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 จะส่งผลต่อเวลาอัปเดตเนื่องจากมี I/O มากขึ้นเนื่องจากการย้ายบล็อก
Google ได้ขยายmake_ext4fs
เครื่องมือสำหรับการรักษาการจัดสรรบล็อกให้สอดคล้องกันในบิลด์ต่างๆ เพื่อแก้ไขปัญหานี้ใน Android 7.0 เครื่องมือ make_ext4fs
ยอมรับ Flag -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 โดยตรง