עדכון 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()]

עדכון תהליך העבודה

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

Full 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