تقليل حجم OTA

تصف هذه الصفحة التغييرات المضافة إلى 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 أخرى). للحصول على التفاصيل، راجع ما يلي:

بناء الدليل

المشكلة: قد يؤدي تغيير الدليل الذي تم إنشاء الأشياء فيه إلى اختلاف الثنائيات. معظم المسارات في إصدار 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++

تنتج وحدات الماكرو هذه دائمًا مخرجات مختلفة للبنيات المختلفة، لذا لا تستخدمها. فيما يلي بعض الخيارات لإزالة وحدات الماكرو هذه:

الطوابع الزمنية المضمنة في الأرشيفات (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.

أمثلة:

تمكين حساب الحقيقة على الجهاز

إذا تم تمكين dm-verity على جهازك، فستقوم أدوات OTA تلقائيًا بالتقاط تكوين التحقق الخاص بك، وتمكين حساب التحقق على الجهاز. يسمح هذا بحساب كتل الحقيقة على أجهزة Android، بدلاً من تخزينها كبايتات أولية في حزمة OTA الخاصة بك. يمكن أن تستخدم كتل Verity حوالي 16 ميجابايت لقسم سعة 2 جيجابايت.

ومع ذلك، يمكن أن تستغرق عملية حساب الحقيقة على الجهاز وقتًا طويلاً. على وجه الخصوص، يمكن أن يستغرق رمز تصحيح الخطأ الأمامي وقتًا طويلاً. على أجهزة البكسل، يستغرق الأمر ما يصل إلى 10 دقائق. على الأجهزة المنخفضة الجودة، قد يستغرق الأمر وقتًا أطول. إذا كنت تريد تعطيل حساب الحقيقة على الجهاز، مع الاستمرار في تمكين dm-verity، فيمكنك القيام بذلك عن طريق تمرير --disable_fec_computation إلى أداة ota_from_target_files عند إنشاء تحديث عبر الهواء. تعمل هذه العلامة على تعطيل حساب الحقيقة على الجهاز أثناء تحديثات OTA. إنه يقلل من وقت تثبيت OTA، ولكنه يزيد من حجم حزمة OTA. إذا لم يكن dm-verity ممكّنًا على جهازك، فلن يكون لتمرير هذه العلامة أي تأثير.

أدوات البناء المتسقة

المشكلة: يجب أن تكون الأدوات التي تنشئ الملفات المثبتة متسقة (يجب أن ينتج المدخلات المحددة نفس المخرجات دائمًا).

الحلول/الأمثلة: كانت التغييرات مطلوبة في أدوات الإنشاء التالية:

استخدم أداة بناء الفرق

بالنسبة للحالات التي لا يكون فيها من الممكن التخلص من تغييرات الملفات المرتبطة بالإنشاء، يتضمن 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، قد يكون لديهم بالفعل التطبيق المحدث، أو إصدار أحدث، تم استلامه مباشرة من متاجر التطبيقات.