تنفيذ تعديلات اختبار أ/ب

على المصنّعين الأصليين للأجهزة ومورّدي المنظومة على الرقاقة (SoC) الذين يريدون تنفيذ تحديثات النظام A/B التأكّد من أنّ برنامج الإقلاع يطبّق واجهة HAL الخاصة بـ `boot_control` ويُمرِّر الـ مَعلمات الصحيحة إلى الـ نواة.

تنفيذ واجهة HAL الخاصة بـ `boot_control`

يجب أن تطبّق برامج الإقلاع المتوافقة مع A/B واجهة HAL الخاصة بـ boot_control في hardware/libhardware/include/hardware/boot_control.h. يمكنك اختبار عمليات التنفيذ باستخدام الأداة system/extras/bootctl و system/extras/tests/bootloader/.

عليك أيضًا تنفيذ آلة الحالة الموضّحة أدناه:

الشكل 1. آلة حالة برنامج الإقلاع

إعداد النواة

لتنفيذ تحديثات النظام A/B:

  1. اختَر سلسلة تصحيحات النواة التالية (إذا لزم الأمر):
  2. تأكَّد من أنّ وسيطات سطر أوامر النواة تحتوي على الوسيطات الإضافية التالية:
    skip_initramfs rootwait ro init=/init root="/dev/dm-0 dm=system none ro,0 1 android-verity <public-key-id> <path-to-system-partition>"
    ... حيث تكون قيمة <public-key-id> هي رقم تعريف المفتاح العام المستخدَم للتحقّق من توقيع جدول verity (للحصول على التفاصيل، اطّلِع على dm-verity).
  3. أضِف شهادة X .509 التي تحتوي على المفتاح العام إلى سلسلة مفاتيح النظام:
    1. انسَخ شهادة X.509 المنسَّقة بتنسيق .der إلى جذر دليل kernel إذا كانت شهادة X .509 منسَّقة كملف .pem، استخدِم أمر openssl التالي للتحويل من .pem إلى تنسيق .der:
      openssl x509 -in <x509-pem-certificate> -outform der -out <x509-der-certificate>
    2. أنشِئ zImage لتضمين الشهادة كجزء من سلسلة مفاتيح النظام. للتحقّق، اطّلِع على إدخال procfs (يتطلّب KEYS_CONFIG_DEBUG_PROC_KEYS تفعيل):
      angler:/# cat /proc/keys
      
      1c8a217e I------     1 perm 1f010000     0     0 asymmetri
      Android: 7e4333f9bba00adfe0ede979e28ed1920492b40f: X509.RSA 0492b40f []
      2d454e3e I------     1 perm 1f030000     0     0 keyring
      .system_keyring: 1/4
      يشير تضمين شهادة X .509 بنجاح إلى توفُّر المفتاح العام في سلسلة مفاتيح النظام (يشير التمييز إلى رقم تعريف المفتاح العام).
    3. استبدِل المسافة بـ # ومرِّرها كـ <public-key-id> في سطر أوامر النواة. على سبيل المثال، مرِّر Android:#7e4333f9bba00adfe0ede979e28ed1920492b40f بدلاً من <public-key-id>.

ضبط متغيرات الإصدار

يجب أن تستوفي برامج الإقلاع المتوافقة مع A/B معايير متغيرات الإصدار التالية:

يجب تحديدها للهدف A/B
  • AB_OTA_UPDATER := true
  • AB_OTA_PARTITIONS := \
      boot \
      system \
      vendor
    والأقسام الأخرى التي يتم تعديلها من خلال update_engine (الراديو وبرنامج الإقلاع، إلخ)
  • PRODUCT_PACKAGES += \
      update_engine \
      update_verifier
للاطّلاع على مثال، يُرجى الرجوع إلى /device/google/marlin/+/android-7.1.0_r1/device-common.mk. يمكنك اختياريًا إجراء خطوة dex2oat بعد التثبيت (ولكن قبل إعادة التشغيل) الموضّحة في التجميع.
يُنصح بشدة باستخدامها للهدف A/B
  • حدِّد TARGET_NO_RECOVERY := true
  • حدِّد BOARD_USES_RECOVERY_AS_BOOT := true
  • لا تحدِّد BOARD_RECOVERYIMAGE_PARTITION_SIZE
لا يمكن تحديدها للهدف A/B
  • BOARD_CACHEIMAGE_PARTITION_SIZE
  • BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE
اختياري لإصدارات تصحيح الأخطاء PRODUCT_PACKAGES_DEBUG += update_engine_client

ضبط الأقسام (الفتحات)

لا تحتاج أجهزة A/B إلى قسم استرداد أو قسم ذاكرة تخزين مؤقت لأنّ Android لم يعُد يستخدم هذه الأقسام. يُستخدم الآن قسم البيانات لحزمة OTA التي تم تنزيلها، ويكون رمز صورة استرداد الإعدادات الأصلية في قسم الإقلاع. يجب تسمية جميع الأقسام التي تمّت تهيئتها باستخدام A/B على النحو التالي (يتم دائمًا تسمية الفتحات a وb وما إلى ذلك): boot_a، boot_b، system_a، system_b، vendor_a، vendor_b

ذاكرة التخزين المؤقت

بالنسبة إلى التحديثات غير A/B، كان قسم ذاكرة التخزين المؤقت يُستخدم لتخزين حِزم OTA التي تم تنزيلها ولتخزين الكتل مؤقتًا أثناء تطبيق التحديثات. لم تكن هناك طريقة جيدة لتحديد حجم قسم ذاكرة التخزين المؤقت: كان حجمه المطلوب يعتمد على التحديثات التي أردت تطبيقها. في أسوأ الحالات، كان قسم ذاكرة التخزين المؤقت كبيرًا مثل صورة النظام. باستخدام تحديثات A/B، ما مِن حاجة إلى تخزين الكتل مؤقتًا (لأنّك تكتب دائمًا في قسم غير مستخدَم حاليًا)، وباستخدام A/B المستند إلى البث، ما مِن حاجة إلى تنزيل حزمة OTA بالكامل قبل تطبيقها.

الاسترداد

يحتوي الآن ملف boot.img على قرص RAM للاسترداد. عند الانتقال إلى وضع الاسترداد، لا يمكن لبرنامج الإقلاع وضع الخيار skip_initramfs في سطر أوامر النواة.

بالنسبة إلى التحديثات غير A/B، يحتوي قسم الاسترداد على الرمز المستخدَم لتطبيق التحديثات. يتم تطبيق تحديثات A/B من خلال update_engine الذي يعمل في صورة النظام التي تم إقلاعها بشكل عادي. لا يزال هناك وضع الاسترداد (Recovery mode) يُستخدم لتنفيذ إعادة الضبط على الإعدادات الأصلية وتحميل حِزم التحديث بشكل جانبي (وهو مصدر الاسم "الاسترداد"). يتم تخزين الرمز والبيانات لوضع الاسترداد يتم تخزين الرمز والبيانات لوضع الاسترداد في قسم الإقلاع العادي في قرص RAM. للإقلاع في صورة النظام، يطلب برنامج الإقلاع من النواة تخطّي قرص RAM (وإلا سيُقلِع الجهاز في وضع الاسترداد). وضع الاسترداد صغير (وكان جزء كبير منه موجودًا من قبل في قسم الإقلاع)، لذا لا يزيد حجم قسم الإقلاع.

Fstab

يجبslotselect أن تكون الوسيطة يجب في سطر الأقسام التي تمّت تهيئتها باستخدام A/B. على سبيل المثال:

<path-to-block-device>/vendor  /vendor  ext4  ro
wait,verify=<path-to-block-device>/metadata,slotselect

يجب ألا يتم تسمية أي قسم vendor. بدلاً من ذلك، سيتم اختيار القسم vendor_a أو vendor_b وتثبيته على نقطة التثبيت /vendor.

وسيطات فتحة النواة

يجب تمرير لاحقة الفتحة الحالية إما من خلال عقدة شجرة جهاز (DT) معيّنة (/firmware/android/slot_suffix) أو من خلال androidboot.slot_suffix سطر أوامر النواة أو وسيطة bootconfig.

تلقائيًا، يثبِّت fastboot الفتحة الحالية على جهاز A/B. إذا كانت حزمة التحديث تحتوي أيضًا على صور للفتحة الأخرى غير الحالية، يثبِّت fastboot هذه الصور أيضًا. تشمل الخيارات المتاحة ما يلي:

  • --slot SLOT. تجاوز السلوك التلقائي واطلب من Fastboot تثبيت ذاكرة ROM للفتحة التي يتم تمريرها كـ معلَمة.
  • --set-active [SLOT]. اضبط الفتحة على نشطة. إذا لم يتم تحديد أي وسيطة اختيارية يتم ضبط الفتحة الحالية على نشطة.
  • fastboot --help: اطّلِع على تفاصيل الأوامر.

إذا كان برنامج الإقلاع يطبّق fastboot، يجب أن يتيح الأمر set_active <slot> الذي يضبط الفتحة النشطة الحالية على الفتحة المحدّدة (يجب أن يؤدي ذلك أيضًا إلى محو العلامة غير القابلة للإقلاع لهذه الفتحة وإعادة ضبط عدد محاولات إعادة المحاولة على القيم التلقائية ). يجب أن يتيح برنامج الإقلاع أيضًا المتغيرات التالية:

  • has-slot:<partition-base-name-without-suffix>. تعرِض "yes" إذا كان القسم المحدّد يتيح الفتحات، و"no" بخلاف ذلك.
  • current-slot: تعرِض لاحقة الفتحة التي سيتم الإقلاع منها في المرة التالية.
  • slot-count: تعرِض عددًا صحيحًا يمثّل عدد الفتحات المتاحة. حاليًا، يتم دعم فتحتَين، لذا تكون هذه القيمة 2.
  • slot-successful:<slot-suffix>. تعرِض "yes" إذا تم وضع علامة على الفتحة المحدّدة بأنّها تُقلِع بنجاح، و"no" بخلاف ذلك.
  • slot-unbootable:<slot-suffix>. تعرِض "yes" إذا تم وضع علامة على الفتحة المحدّدة بأنّها غير قابلة للإقلاع ، و"no" بخلاف ذلك.
  • slot-retry-count:<slot-suffix>. عدد محاولات إعادة المحاولة المتبقية لمحاولة إقلاع الفتحة المحدّدة.

لعرض جميع المتغيرات، شغِّل fastboot getvar all.

إنشاء حِزم OTA

تتّبع أدوات حِزم OTA الأوامر نفسها التي تتّبعها الأوامر للأجهزة غير A/B. يجب إنشاء ملف target_files.zip من خلال تحديد متغيرات الإصدار للهدف A/B. تحدِّد أدوات حِزم OTA تلقائيًا الحِزم وتنشئها بالتنسيق الخاص بأداة التعديل A/B.

أمثلة:

  • لإنشاء حزمة OTA كاملة:
    ./build/make/tools/releasetools/ota_from_target_files \
        dist_output/tardis-target_files.zip \
        ota_update.zip
    
  • لإنشاء حزمة OTA إضافية:
    ./build/make/tools/releasetools/ota_from_target_files \
        -i PREVIOUS-tardis-target_files.zip \
        dist_output/tardis-target_files.zip \
        incremental_ota_update.zip
    

ضبط الأقسام

يمكن أن تعدِّل update_engine أي زوج من أقسام A/B محدّدة في القرص نفسه. يحتوي زوج الأقسام على بادئة مشتركة (مثل system أو boot) ولاحقة لكل فتحة (مثل _a). يتم ضبط قائمة الأقسام التي يحدِّد منشئ الحمولة تحديثًا لها من خلال متغير make‏ AB_OTA_PARTITIONS.

على سبيل المثال، إذا تم تضمين زوج من الأقسام bootloader_a و booloader_b (_a و_b هما لاحقتا الفتحة)، يمكنك تعديل هذه الأقسام من خلال تحديد ما يلي في إعدادات المنتج أو اللوحة:

AB_OTA_PARTITIONS := \
  boot \
  system \
  bootloader

يجب ألا يتم تعديل جميع الأقسام التي يتم تعديلها من خلال update_engine من قِبل بقية الـ نظام. أثناء التحديثات الإضافية أو دلتا، تُستخدم البيانات الثنائية من الفتحة الحالية لإنشاء البيانات في الفتحة الجديدة. قد يؤدي أي تعديل إلى تعذُّر التحقّق من بيانات الفتحة الجديدة أثناء عملية التحديث، وبالتالي تعذُّر التحديث.

ضبط ما بعد التثبيت

يمكنك ضبط خطوة ما بعد التثبيت بشكل مختلف لكل قسم تم تعديله باستخدام مجموعة من أزواج المفتاح والقيمة. لتشغيل برنامج موجود في /system/usr/bin/postinst في صورة جديدة ، حدِّد المسار النسبي إلى جذر نظام الملفات في قسم النظام.

على سبيل المثال، يكون usr/bin/postinst هو system/usr/bin/postinst (إذا لم يتم استخدام قرص RAM). بالإضافة إلى ذلك، حدِّد نوع نظام الملفات لتمريره إلى استدعاء النظام mount(2). أضِف ما يلي إلى ملفات المنتج أو الجهاز .mk (إذا كان ذلك منطبقًا):

AB_OTA_POSTINSTALL_CONFIG += \
  RUN_POSTINSTALL_system=true \
  POSTINSTALL_PATH_system=usr/bin/postinst \
  FILESYSTEM_TYPE_system=ext4

تجميع التطبيقات

يمكن تجميع التطبيقات في الخلفية قبل إعادة التشغيل باستخدام صورة النظام الجديدة. لتجميع التطبيقات في الخلفية، أضِف ما يلي إلى إعدادات جهاز المنتج (في ملف device.mk الخاص بالمنتج):

  1. ضمِّن المكوّنات الأصلية في الإصدار لضمان تجميع نص التجميع والملفات الثنائية و تضمينها في صورة النظام.
      # A/B OTA dexopt package
      PRODUCT_PACKAGES += otapreopt_script
    
  2. اربط نص التجميع بـ update_engine بحيث يتم تشغيله كخطوة ما بعد التثبيت.
      # A/B OTA dexopt update_engine hookup
      AB_OTA_POSTINSTALL_CONFIG += \
        RUN_POSTINSTALL_system=true \
        POSTINSTALL_PATH_system=system/bin/otapreopt_script \
        FILESYSTEM_TYPE_system=ext4 \
        POSTINSTALL_OPTIONAL_system=true
    

للحصول على مساعدة في تثبيت الملفات التي تم تحسينها مسبقًا في قسم النظام الثاني غير المستخدَم، يُرجى الرجوع إلى تثبيت ملفات DEX_PREOPT عند الإقلاع الأول.