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

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

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

بالنسبة إلى الأجهزة غير المزوّدة بميزة A/B، يتم تطبيق تحديث OTA للأقسام الديناميكية باستخدام updater داخل حزمة التحديث.

تعديل الأجهزة المخصّصة لإطلاق التطبيق

ينطبق هذا القسم على الأجهزة غير المزوّدة بميزة A/B والتي تعمل بدعم المساحة التخزينية الديناميكية، ويتم ترقيتها من Android 10 إلى إصدارات أحدث.

إنشاء حِزم تحديثات

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

التحديثات المتزايدة عبر الهواء

تستخدِم التحديثات المتزايدة عبر اتصال لاسلكي المنطق التالي:

  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

التحديث عبر الهواء بالكامل

تستخدم تحديثات "عبر الهواء" الكاملة المنطق التالي:

  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