הטמעת עדכוני 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/ .

עליך ליישם גם את מכונת המצב המוצגת להלן:

איור 1. מכונת מצב של טוען האתחול

הגדרת הקרנל

כדי ליישם עדכוני מערכת A/B:

  1. Cherrypick את סדרת תיקוני הגרעין הבאה (במידת הצורך):
  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-ed צריכות לקבל את השמות הבאים (משבצות נקראות תמיד 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 . כאשר נכנסים לשחזור, טוען האתחול לא יכול לשים את אפשרות skip_initramfs בשורת הפקודה של הליבה.

עבור עדכונים שאינם A/B, מחיצת השחזור מכילה את הקוד המשמש להחלת עדכונים. עדכוני A/B מיושמים על ידי update_engine הפועל בתמונת המערכת הרגילה המאותחלת. עדיין קיים מצב שחזור המשמש ליישום איפוס נתוני היצרן וטעינת צד של חבילות עדכון (שממנו הגיע השם "שחזור"). הקוד והנתונים למצב שחזור מאוחסנים במחיצת האתחול הרגילה ב-ramdisk; כדי לאתחל לתוך תמונת המערכת, טוען האתחול אומר לקרנל לדלג על ה-ramdisk (אחרת המכשיר מאתחל למצב שחזור. מצב השחזור קטן (וחלק גדול ממנו כבר היה במחיצת האתחול), כך שמחיצת האתחול לא גדלה במידה.

Fstab

ארגומנט ה- 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 .

טיעוני משבצת ליבה

יש להעביר את סיומת החריץ הנוכחית דרך צומת עץ מכשיר ספציפי ( /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> . מחזירה "כן" אם המחיצה הנתונה תומכת בחריצים, "לא" אחרת.
  • current-slot . מחזירה את סיומת המשבצת שתאותחל מהבא.
  • slot-count . מחזירה מספר שלם המייצג את מספר המשבצות הזמינות. נכון לעכשיו, שני חריצים נתמכים כך שהערך הזה הוא 2 .
  • slot-successful:<slot-suffix> . מחזירה "כן" אם המשבצת הנתונה סומנה כאתחול בהצלחה, "לא" אחרת.
  • slot-unbootable:<slot-suffix> . מחזירה "כן" אם המשבצת הנתונה מסומנת כלא ניתנת לאתחול, "לא" אחרת.
  • slot-retry-count . מספר הניסיונות החוזרים שנותרו לניסיון לאתחל את המשבצת הנתונה.

כדי להציג את כל המשתנים, הפעל fastboot getvar all .

הפקת חבילות OTA

כלי החבילה של OTA פועלים לפי אותן פקודות כמו הפקודות עבור התקנים שאינם A/B. יש להפיק את הקובץ target_files.zip על ידי הגדרת משתני ה-build עבור יעד 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

קומפילציה

מטעמי אבטחה, system_server אינו יכול להשתמש בהידור של Just -in-Time (JIT) . משמעות הדבר היא שעליך להרכיב מראש קובצי odex עבור system_server והתלות שלו לכל הפחות; כל דבר אחר הוא אופציונלי.

כדי להרכיב אפליקציות ברקע, עליך להוסיף את הדברים הבאים לתצורת המכשיר של המוצר (ב-device.mk של המוצר):

  1. כלול את הרכיבים המקוריים ב-build כדי להבטיח שסקריפט קומפילציה וקבצים בינאריים יקומפלו ונכללים בתמונת המערכת.
      # 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 .