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

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

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

במכשירים שאינם A/B, עדכון ה-OTA למחיצות דינמיות מוחל באמצעות updater בתוך חבילת העדכון.

עדכון של מכשירי ההשקה

הקטע הזה רלוונטי למכשירים שאינם מסוג A/B שמופעלים עם תכונות דינמיות תמיכה במחיצות; מכשירים אלה משדרגים מ-Android מ-10 לגרסאות גבוהות יותר.

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

חבילות עדכון OTA נוצרות על ידי סקריפט ota_from_target_files, שנמצא תחת build/make/tools/releasetools. כברירת מחדל, הסקריפט יוצר חבילה שמעדכנת את המחיצות system ו-vendor. אם יש גורמים דינמיים נוספים מחיצות, כמו product, product_services או odm, יש ליצור עדכונים ספציפי למכשיר .

כדי ליצור עדכונים, במודול Python המורחב, FullOTA_GetBlockDifferences() והקבוצה IncrementalOTA_GetBlockDifferences(). שתי הפונקציות האלה מחזירות רשימה של אובייקטים מסוג BlockDifference, שבכל אחד מהם מתוארת תיקון העדכון שייושם על מחיצה. אין להשתמש במחיצות שמוחזרות על ידי שתי הפונקציות האלה שונה באופן ידני או בוצע אימות במקום אחר, לדוגמה *_InstallBegin() או *_InstallEnd().

דוגמה ליצירת עדכון:

# device/yoyodyne/tardis/releasetools.py

import os
from common import BlockDifference, EmptyImage, GetUserImage

# The joined list of user image partitions of source and target builds.
# - Items should be added to the list if new dynamic partitions are added.
# - Items should not be removed from the list even if dynamic partitions are
#   deleted. When generating an incremental OTA package, this script needs to
#   know that an image is present in source build but not in target build.
USERIMAGE_PARTITIONS = [
    "product",
    "odm",
]

def GetUserImages(input_tmp, input_zip):
  return {partition: GetUserImage(partition, input_tmp, input_zip)
          for partition in USERIMAGE_PARTITIONS
          if os.path.exists(os.path.join(input_tmp,
                                         "IMAGES", partition + ".img"))}

def FullOTA_GetBlockDifferences(info):
  images = GetUserImages(info.input_tmp, info.input_zip)
  return [BlockDifference(partition, image)
          for partition, image in images.items()]

def IncrementalOTA_GetBlockDifferences(info):
  source_images = GetUserImages(info.source_tmp, info.source_zip)
  target_images = GetUserImages(info.target_tmp, info.target_zip)

  # Use EmptyImage() as a placeholder for partitions that will be deleted.
  for partition in source_images:
    target_images.setdefault(partition, EmptyImage())

  # Use source_images.get() because new partitions are not in source_images.
  return [BlockDifference(partition, target_image, source_images.get(partition))
          for partition, target_image in target_images.items()]

תהליך עדכון

מאחורי הקלעים, הפונקציות הבאות מתווספות לתוכן סקריפט:

  • unmap_partition(name)
    • מבטלים את המיפוי של המחיצה אם היא ממופה, אחרת לא עושים כלום.
    • הפונקציה מחזירה את המחרוזת t אחרי ביצוע הפעולה, או מחרוזת ריקה מחרוזת בכשל.
  • map_partition(name)
    • ממפים את המחיצה, אם היא עדיין לא ממופה.
    • הפונקציה מחזירה את הנתיב המוחלט של מכשיר הבלוק הממופה אם הפעולה בוצעה בהצלחה, או מחרוזת ריקה אם הפעולה נכשלה.
  • update_dynamic_partitions(op_list)
    • החילו את רשימת הפעולות הנתונה על מטא-נתונים של מחיצות דינמיות, ביטול מיפוי של מחיצות במקרה הצורך.
    • הפונקציה מחזירה את הערך t במקרה של כשל, או מחרוזת ריקה במקרה של כשל.

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

  • resize partition-name size
    • מבטלים את מיפוי המחיצה ומשנים את הגודל שלה ל-size.
  • remove partition_name
    • מבטלים את המיפוי של המחיצה ומסירים אותה.
  • add partition-name group-name
    • הוספת מחיצה חדשה לקבוצה שצוינה.
    • אם הקבוצה לא קיימת או אם המחיצה כבר קיימת, צריך לבטל את הפעולה.
  • move partition-name group-name
    • מעבירים את המחיצה לקבוצה שצוינה.
    • יש לבטל אם הקבוצה לא קיימת או אם המחיצה לא קיימת.
  • add_group group-name maximum-size
    • מוסיפים קבוצה עם השם שצוין והגודל המקסימלי.
    • יש לבטל אם הקבוצה כבר קיימת.
    • המשמעות של maximum_size היא 0: אין מגבלות גודל על המחיצות בקבוצה. נדרשת בדיקה נוספת כדי לוודא שהמחיצות בקבוצה לא חורגות מהמקום הזמין במכשיר.
  • resize_group group-name maximum-size
    • משנים את גודל הקבוצה לגודל המקסימלי שצוין.
    • אם הקבוצה לא קיימת, צריך לבטל את הפעולה.
    • המשמעות של maximum_size היא 0: אין מגבלות גודל על המחיצות בקבוצה. נדרשות בדיקות נוספות כדי לוודא שהמחיצות בקבוצה לא חורגות לשטח הזמין במכשיר.
  • remove_group group-name
    • להסיר קבוצה.
    • ביטול אם יש מחיצות בקבוצה.
  • remove_all_groups
    • ביטול המיפוי של כל המחיצות בכלי המיפוי של המכשיר.
    • מסירים את כל המחיצות והקבוצות.

OTA מצטבר

בעדכוני OTA מצטברים נעשה שימוש בלוגיקה הבאה:

  1. כיווץ מחיצות/מחיקת מחיצות/העברת מחיצות מתוך קבוצה (כדי שיהיה מספיק מקום לכיווץ הקבוצות)
  2. כיווץ קבוצות (כדי שיהיה מספיק מקום להגדיל את הקבוצה)
  3. הרחבת הקבוצות (כדי שיהיה לנו מספיק מקום להרחיב או להוסיף מחיצות)
  4. הגדלת מחיצות/הוספת מחיצות/העברת מחיצות לקבוצה חדשה

בפירוט, הערך update-script נוצר לפי הלוגיקה הבאה:

for each shrinking partition:
    block_image_update(map_partition(name), …)

update_dynamic_partitions(op_list)

for each growing / adding partition:
    block_image_update(map_partition(name), …)

הקובץ op_list של update_dynamic_partitions נוצר באמצעות זה לוגיקה:

for each deleting partition:
    remove
for each partition that changes groups:
    move to "default"
for each shrinking partition:
    resize
for each shrinking / removing group:
    resize_group / remove_group
for each growing / adding group:
    resize_group / add_group
for each adding partition:
    add
for each growing / adding partition:
    resize
for each partition that changes groups:
    move to target group

OTA מלא

עדכוני OTA מלאים מבוססים על הלוגיקה הבאה:

  1. מחיקת כל המחיצות והקבוצות הקיימות
  2. צירוף קבוצות
  3. הוספת מחיצות

בפירוט, update-script נוצר באמצעות לוגיקה:

update_dynamic_partitions(op_list)

for each adding partition:
    block_image_update(map_partition(name), …)

קובץ op_list של update_dynamic_partitions נוצר לפי הלוגיקה הבאה:

remove_all_groups
for each adding group:
    add_group
for each adding partition:
    add
for each adding partition:
    resize