עדכון OTA למכשירי A/B ללא מחיצות דינמיות

Android 10 תומך במחיצות דינמיות, מערכת מחיצות במרחב המשתמש שאפשר ליצור בה מחיצות, לשנות את הגודל שלהן ולהשמיד אותן במהלך עדכונים אופליין (OTA).

בדף הזה מוסבר איך לקוחות OTA משנים את הגודל של מחיצות דינמיות במהלך עדכון למכשירי A/B שהושקו ללא תמיכה במחיצות דינמיות, ואיך לקוחות OTA משדרגים ל-Android 10.

רקע

במהלך עדכון של מכשיר A/B לתמיכה במחיצות דינמיות, טבלת המחיצות של GUID‏ (GPT) במכשיר נשמרת, כך שאין במכשיר מחיצה מסוג super. המטא-נתונים נשמרים ב-system_a וב-system_b, אבל אפשר לשנות את BOARD_SUPER_PARTITION_METADATA_DEVICE כדי להתאים אישית את המיקום.

בכל אחד ממכשירי הבלוק יש שני משבצות מטא-נתונים. נעשה שימוש רק בחריץ אחד של מטא-נתונים בכל מכשיר בלוקים. לדוגמה, המטא-נתונים 0 ב-system_a והמטא-נתונים 1 ב-system_b תואמים למחיצות בחריצי A ו-B, בהתאמה. בזמן הריצה, לא משנה איזה חריץ מתעדכן.

בדף הזה, חריצי המטא-נתונים נקראים Metadata S (מקור) ו-Metadata T (יעד). באופן דומה, המחיצות נקראות system_s,‏ vendor_t וכן הלאה.

מידע נוסף על הגדרות של מערכת build זמין במאמר שדרוג מכשירים.

למידע נוסף על האופן שבו מחיצות שייכות לקבוצות עדכון, ראו שינויים בהגדרות הלוח במכשירים חדשים.

דוגמה למטא-נתונים במכשיר:

  • התקן בלוקים פיזי system_a
    • מטא-נתונים 0
      • קבוצה foo_a
        • מחיצה לוגית (דינמית) system_a
        • מחיצה לוגית (דינמית) product_services_a
        • מחיצות אחרות שעודכנו על ידי Foo
      • קבוצה bar_a
        • מחיצה לוגית (דינמית) vendor_a
        • מחיצה לוגית (דינמית) product_a
        • מחיצות אחרות שעודכנו על ידי Bar
    • מטא-נתונים 1 (לא בשימוש)
  • התקן בלוקים פיזי system_b
    • מטא-נתונים 0 (לא בשימוש)
    • מטא-נתונים 1
      • קבוצה foo_b
        • מחיצה לוגית (דינמית) system_b
        • מחיצה לוגית (דינמית) product_services_b
        • מחיצות אחרות שעודכנו על ידי Foo
      • קבוצה bar_b
        • מחיצה לוגית (דינמית) vendor_b
        • מחיצה לוגית (דינמית) product_b
        • מחיצות אחרות שעודכנו על ידי Bar

אפשר להשתמש בכלי lpdump בקטע system/extras/partition_tools כדי לדגום את המטא-נתונים במכשיר. לדוגמה:

lpdump --slot 0 /dev/block/by-name/system_a
lpdump --slot 1 /dev/block/by-name/system_b

עדכון רטרופייט

במכשירים עם Android 9 וגרסאות קודמות, לקוח ה-OTA במכשיר לא תומך במיפוי של מחיצות דינמיות לפני העדכון. נוצרת קבוצה נוספת של תיקונים כדי שניתן יהיה להחיל את המיפוי ישירות על המחיצות הפיזיות הקיימות.

ה-OTA generator יוצר את קובץ ה-super.img הסופי שמכיל את התוכן של כל המחיצות הדינמיות, ולאחר מכן מפצל את התמונה למספר תמונות בהתאם לגדלים של מכשירי הבלוק הפיזיים התואמים למערכת, לספק וכו'. השמות של התמונות האלה הם super_system.img,‏ super_vendor.img וכן הלאה. לקוח ה-OTA מחיל את התמונות האלה על המחיצות הפיזיות, במקום להחיל את התמונות על המחיצות הלוגיות (הדינמיות).

מכיוון שלקוח ה-OTA לא יודע למפות מחיצות דינמיות, כל השלבים שלאחר ההתקנה מושבתים באופן אוטומטי במחיצות האלה כשחבילת העדכון נוצרת. פרטים נוספים זמינים במאמר הגדרה לאחר ההתקנה.

תהליך העדכון זהה לתהליך ב-Android 9.

לפני העדכון:

ro.boot.dynamic_partitions=
ro.boot.dynamic_partitions_retrofit=

אחרי העדכון:

ro.boot.dynamic_partitions=true
ro.boot.dynamic_partitions_retrofit=true

עדכונים עתידיים לאחר שדרוג

אחרי עדכון ההתאמה לאחור, לקוח ה-OTA מתעדכן לעבודה עם מחיצות דינמיות. היקפי המידע של מחיצות המקור אף פעם לא נפרסים על פני מחיצות פיזיות של יעד.

תהליך העדכון באמצעות חבילת עדכון רגילה

  1. מאתחלים את המטא-נתונים של מחיצה super.
    1. יצירה של מטא-נתונים חדשים (M) ממטא-נתונים קיימים (S, מטא-נתוני המקור). לדוגמה, אם המטא-נתונים S משתמשים ב-[system_s,‏ vendor_s, ‏ product_s] כמכשירי חסימה, אז המטא-נתונים החדשים M משתמשים ב-[system_t,‏ vendor_t, ‏ product_t] כמכשירי חסימה. כל הקבוצות והמחיצות נמחקות ב-M.
    2. מוסיפים קבוצות יעד ומחיצות בהתאם לשדה dynamic_partition_metadata במניפסט העדכון. הגודל של כל מחיצה מופיע בקובץ new_partition_info.
    3. כתיבת M למטא-נתונים T.
    4. ממפים את המחיצות שנוספו בממפה של המכשיר כמחיצות לכתיבה.
  2. מחילים את העדכון במכשירים שחוסמו.
    1. במידת הצורך, ממפים את המחיצות של המקור בממפה של המכשיר בתור קריאה בלבד. הדבר נחוץ להעלאה צדדית כי מחיצות המקור לא ממפות לפני העדכון.
    2. החלת עדכון מלא או עדכון דלתא על כל מכשירי החסימה בחריץ היעד.
    3. מחברים את המחיצות כדי להריץ את הסקריפט שלאחר ההתקנה, ואז מנתקים את המחיצות.
  3. ביטול המיפוי של המחיצות היעד

תהליך העדכון באמצעות חבילת עדכון ל-retrofit

אם חבילת העדכון של ה-retrofit חלה על מכשיר שכבר מופעל בו חלוקה דינמית למחיצות, לקוח ה-OTA מחיל את הקובץ המפוצל super.img ישירות על מכשירי בלוק. תהליך העדכון דומה לעדכון של ציוד משומש. פרטים נוספים זמינים במאמר התאמה לאחור של עדכון.

לדוגמה, נניח את הפרטים הבאים:

  • חריץ A הוא החריץ הפעיל.
  • system_a מכיל את המטא-נתונים הפעילים בחריץ 0.
  • system_a,‏ vendor_a ו-product_a משמשים כהתקני בלוקים.

כשלקוח OTA מקבל חבילת עדכון להתקנה חוזרת, היא חלה על super_system.img במכשיר הפיזי system_b, על super_vendor.img במכשיר הפיזי vendor_b ועל super_product.img במכשיר הפיזי product_b. מכשיר הבלוק הפיזי system_b מכיל את המטא-נתונים הנכונים למיפוי של system_b,‏ vendor_b ו-product_b הלוגיים בזמן האתחול.

יצירת חבילות עדכון

OTA מצטבר

כשיוצרים עדכוני OTA מצטברים למכשירים מותאמים, העדכונים תלויים בכך שהגדרות PRODUCT_USE_DYNAMIC_PARTITIONS ו-PRODUCT_RETROFIT_DYNAMIC_PARTITIONS מוגדרות בגרסה הבסיסית או לא.

  • אם המשתנים לא מוגדרים ב-build הבסיסי , זהו עדכון למערכות קיימות. חבילת העדכון מכילה את הקובץ המפוצל super.img ומשביתה את השלב שלאחר ההתקנה.
  • אם המשתנים מוגדרים ב-build הבסיסי, זה זהה לעדכון רגיל עם מחיצות דינמיות. חבילת העדכון מכילה את התמונות של המחיצות הלוגיות (הדינמיות). אפשר להפעיל את השלב שלאחר ההתקנה.

OTA מלא

שתי חבילות OTA מלאות נוצרות למכשירים מותאמים.

  • $(PRODUCT)-ota-retrofit-$(TAG).zip תמיד מכיל את הפיצול super.img ומשבית את השלב שלאחר ההתקנה לעדכון של ציוד קיים.
    • הוא נוצר עם ארגומנט נוסף --retrofit_dynamic_partitions לסקריפט ota_from_target_files.
    • אפשר להחיל אותו על כל הגרסאות הבנויות.
  • $(PRODUCT)-ota-$(TAG).zip מכיל תמונות לוגיות לעדכונים עתידיים.
    • יש להחיל את ההגדרה הזו רק על גרסאות build שבהן מופעלות מחיצות דינמיות. בהמשך מוסבר איך אנחנו אוכפים את המדיניות הזו.

דחייה של עדכון שלא ניתן להתאמה לאחור בגרסאות build ישנות

יש להחיל את חבילת ה-OTA המלאה הרגילה רק על גרסאות build שבהן מופעלים מחיצות דינמיות. אם שרת ה-OTA מוגדר בצורה שגויה ומעביר את החבילות האלה למכשירים עם Android מגרסה 9 ומטה, המכשירים לא יוכלו להפעיל את עצמם. לקוח ה-OTA בגרסאות Android 9 ואילך לא יכול להבדיל בין חבילת OTA מותאמת לבין חבילת OTA מלאה רגילה, ולכן הלקוח לא ידחה את החבילה המלאה.

כדי למנוע מהמכשיר לקבל את חבילת ה-OTA המלאה, אפשר לדרוש שלב לאחר ההתקנה כדי לבדוק את ההגדרות הקיימות במכשיר. לדוגמה:

device/device_name/dynamic_partitions/check_dynamic_partitions

#!/system/bin/sh
DP_PROPERTY_NAME="ro.boot.dynamic_partitions"
DP_RETROFIT_PROPERTY_NAME="ro.boot.dynamic_partitions_retrofit"

DP_PROPERTY=$(getprop ${DP_PROPERTY_NAME})
DP_RETROFIT_PROPERTY=$(getprop ${DP_RETROFIT_PROPERTY_NAME})

if [ "${DP_PROPERTY}" != "true" ] || [ "${DP_RETROFIT_PROPERTY}" != "true" ] ; then
    echo "Error: applied non-retrofit update on build without dynamic" \
         "partitions."
    echo "${DP_PROPERTY_NAME}=${DP_PROPERTY}"
    echo "${DP_RETROFIT_PROPERTY_NAME}=${DP_RETROFIT_PROPERTY}"
    exit 1
fi

device/device_name/dynamic_partitions/Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE:= check_dynamic_partitions
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_SRC_FILES := check_dynamic_partitions
LOCAL_PRODUCT_MODULE := true
include $(BUILD_PREBUILT)

device/device_name/device.mk

PRODUCT_PACKAGES += check_dynamic_partitions

# OPTIONAL=false so that the error in check_dynamic_partitions will be
# propagated to OTA client.
AB_OTA_POSTINSTALL_CONFIG += \
    RUN_POSTINSTALL_product=true \
    POSTINSTALL_PATH_product=bin/check_dynamic_partitions \
    FILESYSTEM_TYPE_product=ext4 \
    POSTINSTALL_OPTIONAL_product=false \

כשחבילת ה-OTA הרגילה חלה על מכשיר בלי מחיצות דינמיות מופעלות, לקוח ה-OTA מפעיל את check_dynamic_partitions כשלב לאחר ההתקנה ומסרב לעדכון.