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
      • Group bar_b
        • חלוקה לוגית (דינמית) vendor_b
        • מחיצה לוגית (דינמית) product_b
        • מחיצות אחרות שעודכנו על ידי הסרגל

אפשר להשתמש בכלי 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 בונה את קובץ 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

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