تصف هذه الصفحة التغييرات المضافة إلى AOSP لتقليل تغييرات الملفات غير الضرورية بين الإصدارات. يمكن لمنفذي الأجهزة الذين يحتفظون بأنظمة البناء الخاصة بهم استخدام هذه المعلومات كدليل لتقليل حجم التحديثات عبر الهواء (OTA) الخاصة بهم.
تحتوي تحديثات Android OTA أحيانًا على ملفات تم تغييرها ولا تتوافق مع تغييرات التعليمات البرمجية. إنهم في الواقع يقومون ببناء القطع الأثرية للنظام. يمكن أن يحدث هذا عندما ينتج نفس الكود، الذي تم إنشاؤه في أوقات مختلفة، من أدلة مختلفة، أو على أجهزة مختلفة، عددًا كبيرًا من الملفات التي تم تغييرها. تؤدي هذه الملفات الزائدة إلى زيادة حجم تصحيح OTA، وتجعل من الصعب تحديد الكود الذي تم تغييره.
لجعل محتويات OTA أكثر شفافية، يتضمن AOSP تغييرات في نظام البناء مصممة لتقليل حجم تصحيحات OTA. تم التخلص من التغييرات غير الضرورية في الملفات بين الإصدارات، وتم تضمين الملفات المرتبطة بالتصحيح فقط في تحديثات OTA. يتضمن AOSP أيضًا أداة إنشاء فرق ، والتي تعمل على تصفية تغييرات الملفات الشائعة المتعلقة بالبناء لتوفير فرق أكثر وضوحًا لملف البناء، وأداة تعيين الكتل ، التي تساعدك في الحفاظ على اتساق تخصيص الكتلة.
يمكن لنظام البناء إنشاء تصحيحات كبيرة غير ضرورية بعدة طرق. للتخفيف من ذلك، في نظام Android 8.0 والإصدارات الأحدث، تم تطبيق ميزات جديدة لتقليل حجم التصحيح لكل اختلاف في الملف. تتضمن التحسينات التي أدت إلى تقليل أحجام حزمة التحديث عبر الهواء ما يلي:
- استخدام Brotli ، وهي خوارزمية ذات أغراض عامة وغير قابلة للضغط للحصول على صور كاملة على تحديثات الأجهزة غير A/B. يمكن تخصيص Brotli لتحسين الضغط. في التحديثات الأكبر التي تتكون من كتلتين أو أكثر في نظام الملفات (على سبيل المثال،
system.img
)، يمكن لمصنعي الأجهزة أو الشركاء إضافة خوارزميات الضغط الخاصة بهم، ويمكنهم استخدام خوارزميات ضغط مختلفة على كتل مختلفة من نفس التحديث. - استخدام إعادة ضغط Puffin ، وهي أداة تصحيح حتمية للتدفقات المفرغة، والتي تتعامل مع وظائف الضغط والفرق لإنشاء تحديث A/B OTA.
- تغييرات على استخدام أداة إنشاء دلتا، مثل كيفية استخدام مكتبة
bsdiff
لضغط التصحيحات. في نظام Android 9 والإصدارات الأحدث، تحدد أداةbsdiff
خوارزمية الضغط التي من شأنها أن تعطي أفضل نتائج الضغط للتصحيح. - أدت التحسينات التي تم إدخالها على
update_engine
إلى تقليل استهلاك الذاكرة عند تطبيق التصحيحات على تحديثات جهاز A/B. - تحسينات على تقسيم الملفات المضغوطة الكبيرة لتحديثات 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 .
الطوابع الزمنية
المشكلة: تؤدي الطوابع الزمنية في مخرجات الإنشاء إلى تغييرات غير ضرورية في الملف. من المحتمل أن يحدث هذا في المواقع التالية:
-
__DATE__/__TIME__/__TIMESTAMP__
وحدات الماكرو في كود C أو C++. - الطوابع الزمنية مضمنة في الأرشيفات المستندة إلى الرمز البريدي.
الحلول/الأمثلة: لإزالة الطوابع الزمنية من مخرجات البناء، استخدم الإرشادات الواردة أدناه في __DATE__/__TIME__/__TIMESTAMP__ في C/C++. والطوابع الزمنية المضمنة في الأرشيف .
__DATE__/__TIME__/__الطابع الزمني__ في 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 من الملف المضغوط.
أداة جديدة، ziptime
(الموجودة في /platform/build/+/main/tools/ziptime/
) تعيد تعيين الطوابع الزمنية العادية في رؤوس الملفات المضغوطة. للحصول على التفاصيل، راجع ملف 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 تلقائيًا بالتقاط تكوين التحقق الخاص بك، وتمكين حساب التحقق على الجهاز. يسمح هذا بحساب كتل الحقيقة على أجهزة Android، بدلاً من تخزينها كبايتات أولية في حزمة OTA الخاصة بك. يمكن أن تستخدم كتل Verity حوالي 16 ميجابايت لقسم سعة 2 جيجابايت.
ومع ذلك، يمكن أن تستغرق عملية حساب الحقيقة على الجهاز وقتًا طويلاً. على وجه الخصوص، يمكن أن يستغرق رمز تصحيح الخطأ الأمامي وقتًا طويلاً. على أجهزة البكسل، يستغرق الأمر ما يصل إلى 10 دقائق. على الأجهزة المنخفضة الجودة، قد يستغرق الأمر وقتًا أطول. إذا كنت تريد تعطيل حساب الحقيقة على الجهاز، مع الاستمرار في تمكين dm-verity، فيمكنك القيام بذلك عن طريق تمرير --disable_fec_computation
إلى أداة ota_from_target_files
عند إنشاء تحديث عبر الهواء. تعمل هذه العلامة على تعطيل حساب الحقيقة على الجهاز أثناء تحديثات OTA. إنه يقلل من وقت تثبيت OTA، ولكنه يزيد من حجم حزمة OTA. إذا لم يكن dm-verity ممكّنًا على جهازك، فلن يكون لتمرير هذه العلامة أي تأثير.
أدوات البناء المتسقة
المشكلة: يجب أن تكون الأدوات التي تنشئ الملفات المثبتة متسقة (يجب أن ينتج المدخلات المحددة نفس المخرجات دائمًا).
الحلول/الأمثلة: كانت التغييرات مطلوبة في أدوات الإنشاء التالية:
- إشعار ملف الخالق . تم تغيير منشئ ملف NOTICE لإنشاء مجموعات NOTICE قابلة للتكرار. ارجع إلى CL: https://android.googlesource.com/platform/build/+/8ae4984c2c8009e7a08e2a76b1762c2837ad4f64 .
- مجموعة مترجم جافا أندرويد (جاك) . تتطلب سلسلة أدوات Jack تحديثًا للتعامل مع التغييرات العرضية في ترتيب المنشئ الذي تم إنشاؤه. تمت إضافة أدوات الوصول الحتمية للمنشئين إلى سلسلة الأدوات: 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 . - تطبيق ما قبل dexopt (.odex) الملفات . تحتوي ملفات pre-dexopt (.odex) على حشوة غير مهيأة على أنظمة 64 بت. تم تصحيح هذا: https://android.googlesource.com/platform/art/+/34ed3afc41820c72a3c0ab9770be66b6668aa029 .
استخدم أداة بناء الفرق
بالنسبة للحالات التي لا يكون فيها من الممكن التخلص من تغييرات الملفات المرتبطة بالإنشاء، يتضمن AOSP أداة إنشاء فرق، target_files_diff.py
لاستخدامها في مقارنة حزمتين من الملفات. تقوم هذه الأداة بإجراء فرق متكرر بين نسختين، باستثناء تغييرات الملفات الشائعة المرتبطة بالبناء، مثل
- التغييرات المتوقعة في مخرجات البناء (على سبيل المثال، بسبب تغيير رقم البناء).
- التغييرات بسبب المشكلات المعروفة في نظام البناء الحالي.
لاستخدام أداة إنشاء الفرق، قم بتشغيل الأمر التالي:
target_files_diff.py dir1 dir2
dir1
و dir2
هما دليلان أساسيان يحتويان على الملفات المستهدفة المستخرجة لكل إصدار.
حافظ على اتساق تخصيص الكتلة
بالنسبة لملف معين، على الرغم من أن محتوياته تظل كما هي بين نسختين، فقد تكون الكتل الفعلية التي تحتوي على البيانات قد تغيرت. ونتيجة لذلك، يجب على المُحدِّث إجراء عمليات إدخال/إخراج غير ضرورية لتحريك الكتل من أجل تحديث عبر الهواء.
في تحديث Virtual A/B OTA، يمكن أن يؤدي الإدخال/الإخراج غير الضروري إلى زيادة مساحة التخزين المطلوبة لتخزين لقطة النسخ عند الكتابة بشكل كبير. في تحديث غير A/B عبر الهواء، يساهم نقل الكتل لتحديث OTA في وقت التحديث نظرًا لوجود المزيد من عمليات الإدخال/الإخراج بسبب تحركات الكتل.
لمعالجة هذه المشكلة، قامت Google في Android 7.0 بتوسيع أداة make_ext4fs
للحفاظ على اتساق تخصيص الكتلة عبر الإصدارات. تقبل أداة make_ext4fs
علامة -d base_fs
الاختيارية التي تحاول تخصيص الملفات لنفس الكتل عند إنشاء صورة ext4
. يمكنك استخراج ملفات تعيين الكتلة (مثل ملفات خريطة base_fs
) من الملف المضغوط للملفات المستهدفة للبناء السابق. لكل قسم 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 عن طريق تقليل مقدار الإدخال/الإخراج. بالنسبة لتحديثات A/B الافتراضية، فإنها تقلل بشكل كبير من مقدار مساحة التخزين اللازمة لتطبيق OTA.
تجنب تحديث التطبيقات
بالإضافة إلى تقليل اختلافات البناء، يمكنك تقليل أحجام تحديثات OTA عن طريق استبعاد تحديثات التطبيقات التي تحصل على التحديثات من خلال متاجر التطبيقات. غالبًا ما تشتمل ملفات APK على جزء كبير من الأقسام المختلفة على الجهاز. إن تضمين أحدث إصدارات التطبيقات التي يتم تحديثها بواسطة متاجر التطبيقات في تحديث عبر الهواء قد يكون له تأثير كبير الحجم على حزم عبر الهواء، ولا يوفر سوى القليل من الفائدة للمستخدم. بحلول الوقت الذي يتلقى فيه المستخدمون حزمة OTA، قد يكون لديهم بالفعل التطبيق المحدث، أو إصدار أحدث، تم استلامه مباشرة من متاجر التطبيقات.