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

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

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

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

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

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

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

  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