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

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

تنفيذ طبقة تجريد الأجهزة (HAL) الخاصة بالتحكّم في بدء التشغيل

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

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

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

إعداد النواة

لتنفيذ تحديثات النظام من النوع أ/ب، اتّبِع الخطوات التالية:

  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. إذا كانت شهادة ‎ .X509 منسَّقة كملف .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 معايير متغيرات الإصدار التالية:

يجب تحديد هدف اختبار أ/ب
  • 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 بعد التثبيت (ولكن قبل إعادة التشغيل) الموضّحة في الترجمة البرمجية.
يُنصح بشدة باستخدامه لاستهداف اختبار أ/ب
  • تعريف TARGET_NO_RECOVERY := true
  • تعريف BOARD_USES_RECOVERY_AS_BOOT := true
  • لا تحدِّد BOARD_RECOVERYIMAGE_PARTITION_SIZE
لا يمكن تحديد استهداف اختبار أ/ب
  • 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، تم استخدام قسم ذاكرة التخزين المؤقت لتخزين حِزم التحديثات عبر الهواء التي تم تنزيلها ولتخزين الحِزم مؤقتًا أثناء تطبيق التحديثات. لم تكن هناك طريقة جيدة لتحديد حجم قسم ذاكرة التخزين المؤقت، إذ كان الحجم المطلوب يعتمد على التحديثات التي تريد تطبيقها. أسوأ الحالات هي أن يكون قسم ذاكرة التخزين المؤقت بحجم صورة النظام. مع تحديثات A/B، لا حاجة إلى تخزين الكتل (لأنّك تكتب دائمًا في قسم غير مستخدَم حاليًا)، ومع تحديثات A/B المتدفقة، لا حاجة إلى تنزيل حزمة OTA بأكملها قبل تطبيقها.

الاسترداد

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

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

Fstab

يجب أن تكون الوسيطة slotselect في السطر الخاص بالأقسام التي تم اختبارها باستخدام اختبار أ/ب. مثلاً:

<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 لتثبيت الحزمة في الفتحة التي تم تمريرها كمعلَمة
  • --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). يتم ضبط قائمة الأقسام التي يحدّد مولّد الحمولة تحديثًا لها من خلال المتغيّر AB_OTA_PARTITIONS make.

على سبيل المثال، إذا تم تضمين زوج من الأقسام 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 عند التشغيل الأول.