หน้านี้อธิบายการเปลี่ยนแปลงที่เพิ่มลงใน 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 อื่นๆ)
ดูรายละเอียดได้ที่
- 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
- หากต้องการระบุไบนารีที่ทำงานอยู่โดยไม่ซ้ำกัน ให้อ่าน 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/+/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
เปิดใช้การคำนวณความถูกต้องในอุปกรณ์
หากเปิดใช้ dm-verity ในอุปกรณ์ เครื่องมือ OTA จะเลือกการกำหนดค่าความถูกต้องโดยอัตโนมัติ และ เปิดใช้การคำนวณความถูกต้องในอุปกรณ์ ซึ่งจะช่วยให้คำนวณบล็อกความถูกต้องในอุปกรณ์ Android ได้แทนที่จะจัดเก็บเป็นไบต์ดิบในแพ็กเกจ OTA บล็อกความถูกต้องจะใช้พื้นที่ประมาณ 16MB สำหรับพาร์ติชัน 2GB
อย่างไรก็ตาม การคำนวณความจริงบนอุปกรณ์อาจใช้เวลานาน โดยเฉพาะอย่างยิ่ง รหัสการแก้ไขข้อผิดพลาดแบบส่งต่อ
อาจใช้เวลานาน ในอุปกรณ์ Pixel โดยปกติแล้วจะใช้เวลาไม่เกิน 10 นาที ในอุปกรณ์ระดับล่างอาจใช้เวลานานกว่านั้น หากต้องการปิดใช้การคำนวณความถูกต้องในอุปกรณ์ แต่ยังคงเปิดใช้ dm-verity คุณสามารถทำได้โดยส่ง --disable_fec_computation
ไปยังเครื่องมือ ota_from_target_files
เมื่อสร้างการอัปเดต OTA ฟีเจอร์นี้จะปิดใช้การคำนวณความถูกต้องในอุปกรณ์ระหว่างการอัปเดต OTA
ซึ่งจะช่วยลดเวลาในการติดตั้ง OTA แต่จะเพิ่มขนาดแพ็กเกจ OTA หากอุปกรณ์ไม่ได้เปิดใช้ dm-verity การส่งแฟล็กนี้จะไม่มีผล
เครื่องมือสร้างที่สอดคล้องกัน
ปัญหา: เครื่องมือที่สร้างไฟล์ที่ติดตั้งต้องสอดคล้องกัน (อินพุตที่กำหนดควรสร้างเอาต์พุตเดียวกันเสมอ)
วิธีแก้ปัญหา/ตัวอย่าง: ต้องมีการเปลี่ยนแปลงในเครื่องมือบิลด์ต่อไปนี้
- ผู้สร้างไฟล์ NOTICE เราได้เปลี่ยนผู้สร้างไฟล์ NOTICE เพื่อสร้าง คอลเล็กชัน NOTICE ที่ทำซ้ำได้ ดู CL ได้ที่ https://android.googlesource.com/platform/build/+/8ae4984c2c8009e7a08e2a76b1762c2837ad4f64
- ชุดคอมไพเลอร์ Java สำหรับ Android (Jack) Toolchain ของ Jack ต้องได้รับการอัปเดตเพื่อ จัดการการเปลี่ยนแปลงเป็นครั้งคราวในการจัดลำดับตัวสร้างที่สร้างขึ้น เพิ่มตัวช่วยเข้าถึงที่กำหนดได้สำหรับ ตัวสร้างลงใน 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 - ไฟล์การเพิ่มประสิทธิภาพล่วงหน้าของแอปพลิเคชัน (.odex) ไฟล์ pre-dexopt (.odex) มี Padding ที่ไม่ได้เริ่มต้นในระบบ 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 จะทำให้เวลาในการอัปเดตนานขึ้นเนื่องจากมีการรับส่งข้อมูลมากขึ้นจากการย้ายบล็อก
Google ได้ขยายmake_ext4fs
เครื่องมือสำหรับ
การจัดสรรบล็อกให้สอดคล้องกันในทุกบิลด์ใน Android 7.0 เพื่อแก้ไขปัญหานี้ 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 โดยตรง