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

تولیدکنندگان اصلی تجهیزات (OEM) و فروشندگان SoC که می‌خواهند به‌روزرسانی‌های سیستم A/B را پیاده‌سازی کنند، باید مطمئن شوند که بوت‌لودر آنها boot_control HAL را پیاده‌سازی کرده و پارامترهای صحیح را به هسته منتقل می‌کند.

پیاده‌سازی کنترل بوت 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> در خط فرمان هسته وارد کنید. برای مثال، به جای <public-key-id> ، عبارت Android:#7e4333f9bba00adfe0ede979e28ed1920492b40f را وارد کنید.

متغیرهای ساخت را تنظیم کنید

بوت لودرهای دارای قابلیت 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 به پارتیشن ریکاوری یا پارتیشن کش نیازی ندارند زیرا اندروید دیگر از این پارتیشن‌ها استفاده نمی‌کند. پارتیشن داده اکنون برای بسته OTA دانلود شده استفاده می‌شود و کد تصویر ریکاوری روی پارتیشن بوت قرار دارد. تمام پارتیشن‌هایی که A/B-ed هستند باید به صورت زیر نامگذاری شوند (اسلات‌ها همیشه a ، b و غیره نامگذاری می‌شوند): boot_a ، boot_b ، system_a ، system_b ، vendor_a ، vendor_b .

حافظه پنهان

برای به‌روزرسانی‌های غیر A/B، از پارتیشن کش برای ذخیره بسته‌های OTA دانلود شده و ذخیره موقت بلوک‌ها هنگام اعمال به‌روزرسانی‌ها استفاده می‌شد. هیچ‌وقت روش خوبی برای اندازه‌گیری اندازه پارتیشن کش وجود نداشت: میزان بزرگی آن به به‌روزرسانی‌هایی که می‌خواستید اعمال کنید بستگی داشت. بدترین حالت، یک پارتیشن کش به بزرگی تصویر سیستم بود. با به‌روزرسانی‌های A/B نیازی به ذخیره بلوک‌ها نیست (زیرا شما همیشه در حال نوشتن روی پارتیشنی هستید که در حال حاضر استفاده نمی‌شود) و با پخش A/B نیازی به دانلود کل بسته OTA قبل از اعمال آن نیست.

بهبودی

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

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

فست‌تاب

آرگومان slotselect باید در خط مربوط به پارتیشن‌های A/B-ed باشد. برای مثال:

<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 منتقل شود.

به طور پیش‌فرض، فست‌بوت اسلات فعلی را روی دستگاه A/B فلش می‌کند. اگر بسته به‌روزرسانی شامل ایمیج‌هایی برای اسلات دیگر و غیر فعلی نیز باشد، فست‌بوت آن ایمیج‌ها را نیز فلش می‌کند. گزینه‌های موجود عبارتند از:

  • --slot SLOT . رفتار پیش‌فرض را نادیده می‌گیرد و از fastboot می‌خواهد که اسلاتی را که به عنوان آرگومان ارسال شده است، فلش کند.
  • --set-active [ SLOT ] .‎ اسلات را به عنوان فعال تنظیم می‌کند. اگر هیچ آرگومان اختیاری مشخص نشده باشد، اسلات فعلی به عنوان فعال تنظیم می‌شود.
  • fastboot --help . جزئیات مربوط به دستورات را دریافت کنید.

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

  • has-slot:<partition-base-name-without-suffix> در صورتی که پارتیشن مورد نظر از اسلات‌ها پشتیبانی کند، مقدار «yes» و در غیر این صورت مقدار «no» را برمی‌گرداند.
  • 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

کامپایل برنامه‌ها

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