التحديث عبر الهواء للأجهزة غير المزوّدة بميزة A/B التي تتضمّن أقسامًا ديناميكية

يتوافق نظام التشغيل Android 10 مع الأقسام الديناميكية، وهو نظام تقسيم لمساحة المستخدم يتيح إنشاء الأقسام وتغيير حجمها وإزالتها أثناء إجراء التحديثات عبر الهواء (OTA).

توضّح هذه الصفحة كيفية تغيير حجم الأقسام الديناميكية من خلال برامج OTA أثناء التحديث للأجهزة التي لا تستخدم نظام التشغيل A/B.

بالنسبة إلى الأجهزة التي لا تستخدم نظام التشغيل A/B، يتم تطبيق التحديث عبر اتصال لاسلكي للأقسام الديناميكية باستخدام 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
    • أضِف مجموعة بالاسم والحجم الأقصى المحدّدَين.
    • إيقاف العملية إذا كانت المجموعة متوفّرة.
    • تشير القيمة 0 في maximum_size إلى عدم وجود حدود لحجم الأقسام في المجموعة. يجب إجراء اختبارات إضافية للتأكّد من أنّ الأقسام في المجموعة لا تتجاوز المساحة المتاحة على الجهاز.
  • resize_group group-name maximum-size
    • تغيير حجم المجموعة إلى الحد الأقصى المحدّد
    • إيقاف العملية إذا لم تكن المجموعة متوفّرة
    • تشير القيمة 0 في maximum_size إلى عدم وجود حدود لحجم الأقسام في المجموعة. يجب إجراء اختبارات إضافية للتأكّد من أنّ الأقسام في المجموعة لا تتجاوز المساحة المتاحة على الجهاز.
  • remove_group group-name
    • إزالة مجموعة
    • يجب إيقاف العملية إذا كانت هناك أقسام في المجموعة.
  • remove_all_groups
    • إلغاء ربط جميع الأقسام من أداة ربط الأجهزة
    • إزالة جميع الأقسام والمجموعات

Incremental 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 الكاملة المنطق التالي:

  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