پیاده‌سازی به‌روزرسانی‌های A/B

«سازندگان اصلی محصول» و فروشندگان SoC که می‌خواهند به‌روزرسانی‌های سیستم A/B را پیاده‌سازی کنند باید مطمئن شوند که بارکننده آن‌ها «لایه انتزاعی سخت‌افزار» boot_control را پیاده‌سازی می‌کند و پارامترهای صحیح را به هسته ارسال می‌کند.

پیاده‌سازی HAL کنترل راه‌اندازی

راه‌اندازهای سیستم با قابلیت A/B باید boot_control HAL را در hardware/libhardware/include/hardware/boot_control.h پیاده‌سازی کنند. می‌توانید پیاده‌سازی‌ها را بااستفاده از system/extras/bootctl ابزار و system/extras/tests/bootloader/ آزمایش کنید.

همچنین باید ماشین حالت نشان‌داده‌شده در زیر را پیاده‌سازی کنید:

شکل ۱. ماشین حالت راه‌انداز سیستم

راه‌اندازی هسته

برای پیاده‌سازی به‌روزرسانی‌های سیستم 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> شناسه کلید عمومی استفاده‌شده برای درستی‌سنجی امضای جدول درستی است (برای جزئیات، به dm-verity مراجعه کنید).
  3. گواهی .X509 حاوی کلید عمومی را به حلقه‌کلید سیستم اضافه کنید:
    1. گواهینامه .X509 قالب‌بندی‌شده در قالب .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
      افزودن موفقیت‌آمیز گواهینامه .X509 نشان‌دهنده وجود کلید عمومی در حلقه کلید سیستم است (رنگ زرد نشان‌دهنده شناسه کلید عمومی است).
    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 را قبل‌از اعمال کردن آن بارگیری کنید.

بازیابی

دیسک RAM بازیابی اکنون در فایل boot.img قرار دارد. وقتی وارد حالت بازیابی می‌شوید، bootloader نمی‌تواند گزینه skip_initramfs را در خط فرمان هسته قرار دهد.

برای به‌روزرسانی‌های غیر A/B، پارتیشن بازیابی حاوی کدی است که برای اعمال به‌روزرسانی‌ها استفاده می‌شود. به‌روزرسانی‌های A/B توسط update_engine که در تصویر سیستم راه‌اندازی‌شده معمولی اجرا می‌شود اعمال می‌شوند. هنوز حالت بازیابی‌ای وجود دارد که برای اجرای بازنشانی کارخانه‌ای و بارگیری جانبی بسته‌های به‌روزرسانی استفاده می‌شود (نام «بازیابی» از اینجا آمده است). کد و داده‌های حالت بازیابی در پارتیشن بوت معمولی در ramdisk ذخیره می‌شود؛ برای بوت کردن در تصویر سیستم، bootloader به هسته می‌گوید ramdisk را رد کند (درغیراین‌صورت دستگاه در حالت بازیابی بوت می‌شود). حالت بازیابی کوچک است (و بخش زیادی از آن قبلاً در پارتیشن راه‌اندازی بوده است)، بنابراین اندازه پارتیشن راه‌اندازی افزایش نمی‌یابد.

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 بخواهید شکافی را که به‌عنوان آرگومان ارسال شده است فلش کند.
  • --set-active [SLOT]. جایگاه را به‌عنوان فعال تنظیم کنید. اگر هیچ آرگومان اختیاری مشخص نشده باشد، جایگاه فعلی به‌عنوان فعال تنظیم می‌شود.
  • fastboot --help. جزئیات فرمان‌ها را دریافت کنید.

اگر bootloader از fastboot استفاده می‌کند، باید از فرمان set_active <slot> که جایگاه فعال فعلی را روی جایگاه داده‌شده تنظیم می‌کند پشتیبانی کند (این فرمان باید پرچم غیرقابل‌راه‌اندازی را برای آن جایگاه پاک کند و تعداد تلاش مجدد را به مقادیر پیش‌فرض بازنشانی کند). بارکننده باید از متغیرهای زیر نیز پشتیبانی کند:

  • has-slot:<partition-base-name-without-suffix>. اگر بخش داده‌شده از جایگاه‌ها پشتیبانی کند، «بله» و درغیراین‌صورت «نه» برمی‌گرداند.
  • current-slot. پسوند شکافی را که دفعه بعد از آن راه‌اندازی خواهد شد برمی‌گرداند.
  • slot-count. عدد صحیحی را برمی‌گرداند که نشان‌دهنده تعداد جایگاه‌های دردسترس است. درحال‌حاضر، از دو جایگاه پشتیبانی می‌شود، بنابراین این مقدار 2 است.
  • slot-successful:<slot-suffix>. اگر جایگاه داده‌شده به‌عنوان بوت موفق علامت‌گذاری شده باشد، «بله» و درغیراین‌صورت «نه» برمی‌گرداند.
  • slot-unbootable:<slot-suffix>. اگر جایگاه داده‌شده به‌عنوان غیرقابل‌راه‌اندازی علامت‌گذاری شده باشد، «بله» و درغیراین‌صورت «نه» را برمی‌گرداند.
  • 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

ترجمه برنامه‌ها

برنامه‌ها را می‌توان قبل‌از راه‌اندازی مجدد با تصویر سیستم جدید در پس‌زمینه کامپایل کرد. برای گردآوری برنامه‌ها در پس‌زمینه، موارد زیر را به پیکربندی دستگاه محصول (در دستگاه محصول.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 در اولین راه‌اندازی مراجعه کنید.