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

כדי ליצור עדכונים, מטמיעים את FullOTA_GetBlockDifferences() ואת IncrementalOTA_GetBlockDifferences() במודול Python המורחב. שתי הפונקציות האלה מחזירות רשימה של אובייקטים מסוג 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()]

תהליך העדכון

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

  • 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