نظرة عامة على اختبارات A/B الافتراضية

‫Virtual A/B هو آلية التحديث الرئيسية في Android. يستند Virtual A/B إلى تحديثات A/B القديمة (راجِع تحديثات نظام A/B) وتحديثات غير A/B التي تم إيقافها في الإصدار 15 لتقليل المساحة الإضافية التي تشغلها التحديثات.

لا يتضمّن Virtual A/B فعليًا مساحة إضافية للأقسام الديناميكية، راجِع الأقسام الديناميكية. بدلاً من ذلك، يتم تسجيل التغييرات في لقطة، ثم يتم دمجها في القسم الأساسي بعد التأكّد من نجاح عملية التشغيل. يستخدم Virtual A/B تنسيق لقطة خاصًا بنظام Android. راجِع تنسيق COW للقطات المضغوطة الذي يسمح بضغط اللقطات ويقلّل من استخدام مساحة القرص. في عملية التحديث الكامل عبر الهواء (OTA)، يتم تقليل حجم اللقطة بنسبة% 45 تقريبًا باستخدام الضغط، ويتم تقليل حجم لقطة التحديث التراكمي عبر الهواء (OTA) بنسبة %55 تقريبًا.

يتيح Android 12 خيار ضغط Virtual A/B لضغط الأقسام التي تم أخذ لقطات لها. يوفّر Virtual A/B ما يلي:

  • تكون تحديثات Virtual A/B سلسة (يتم التحديث بالكامل في الخلفية أثناء تشغيل الجهاز) مثل تحديثات A/B. تقلّل تحديثات Virtual A/B من الوقت الذي يكون فيه الجهاز غير متصل بالإنترنت وغير قابل للاستخدام.
  • يمكن التراجع عن تحديثات Virtual A/B. إذا تعذّر تشغيل نظام التشغيل الجديد، يتم تلقائيًا التراجع عن التغييرات على الأجهزة واستعادة الإصدار السابق.
  • تستخدم تحديثات Virtual A/B مساحة إضافية قليلة جدًا من خلال تكرار الأقسام التي يستخدمها برنامج الإقلاع فقط. يتم أخذ لقطات للأقسام الأخرى القابلة للتحديث snapshotted.

الخلفية والمصطلحات

يحدّد هذا القسم المصطلحات ويصف التكنولوجيا التي تتيح استخدام Virtual A/B. أثناء تثبيت التحديث عبر الهواء (OTA)، يتم تسجيل بيانات نظام التشغيل الجديد إما في مساحته الجديدة للأقسام الفعلية، أو في جهاز COW خاص بنظام Android. بعد إعادة تشغيل الجهاز، يتم دمج بيانات القسم الديناميكي مرة أخرى في الجهاز الأساسي من خلال استخدام برنامج dm-user الخفي وsnapuserd. تتم هذه العملية بالكامل في مساحة المستخدم.

Device-mapper

‫Device-mapper هي طبقة حظر افتراضية في Linux تُستخدم غالبًا في Android. باستخدام الأقسام الديناميكية، تكون الأقسام مثل /system عبارة عن مجموعة من الأجهزة الطبقية:

  • في أسفل المجموعة، يوجد قسم super الفعلي (على سبيل المثال، /dev/block/by-name/super).
  • في المنتصف، يوجد جهاز dm-linear يحدّد البلوكات في قسم super التي تشكّل القسم الديناميكي المحدّد. يظهر هذا القسم على أنّه /dev/block/mapper/system_[a|b] على جهاز A/B، أو /dev/block/mapper/system على جهاز غير A/B.
  • في الأعلى، يوجد جهاز dm-verity تم إنشاؤه للأقسام التي تم التحقّق منها. يتحقّق هذا الجهاز من توقيع البلوكات بشكل صحيح على جهاز dm-linear. يظهر هذا الجهاز على أنّه /dev/block/mapper/system-verity وهو مصدر نقطة التحميل /system

يوضّح الشكل 1 شكل المجموعة تحت نقطة التحميل /system.

تقسيم التجميع أسفل النظام

الشكل 1: المجموعة تحت نقطة التحميل /system

اللقطات المضغوطة

في Android 12 والإصدارات الأحدث، يمكنك تفعيل اللقطات المضغوطة في الإصدار لمعالجة متطلبات المساحة الأعلى لقسم /data، لأنّ متطلبات المساحة في هذا القسم يمكن أن تكون عالية./data

تستند اللقطات المضغوطة في Virtual A/B إلى المكوّنات التالية المتوفّرة في Android 12 والإصدارات الأحدث:

  • dm-user، وهي وحدة kernel مشابهة لـ FUSE تسمح لمساحة المستخدم بتنفيذ أجهزة البلوكات.
  • snapuserd، وهو برنامج خفي في مساحة المستخدم لتنفيذ تنسيق لقطة جديد.

تتيح هذه المكوّنات عملية الضغط. تظهر التغييرات الضرورية الأخرى التي تم إجراؤها لتنفيذ إمكانات اللقطات المضغوطة في الأقسام التالية: تنسيق COW للقطات المضغوطة، dm-user، وsnapuserd.

تنسيق COW للقطات المضغوطة

في Android 12 والإصدارات الأحدث، تستخدم اللقطات المضغوطة تنسيق COW خاصًا بنظام Android. يحتوي تنسيق COW على بيانات وصفية حول التحديث عبر الهواء (OTA) ويتضمّن مخازن مؤقتة مميّزة تحتوي على عمليات COW وبيانات نظام التشغيل الجديد. مقارنةً بتنسيق لقطة kernel الذي كان يسمح فقط بعمليات الاستبدال (استبدال البلوك X في الصورة الأساسية بمحتويات البلوك Y في اللقطة)، يكون تنسيق COW للقطات المضغوطة في Android أكثر تعبيرًا ويدعم العمليات التالية:

  • النسخ: يجب استبدال البلوك X في الجهاز الأساسي بالبلوك Y في الجهاز الأساسي.
  • الاستبدال: يجب استبدال البلوك X في الجهاز الأساسي بمحتويات البلوك Y في اللقطة. يتم ضغط كل من هذه البلوكات باستخدام gz.
  • الصفر: يجب استبدال البلوك X في الجهاز الأساسي بجميع الأصفار.
  • XOR: يخزّن جهاز COW وحدات البايت المضغوطة باستخدام XOR بين البلوك X و البلوك Y. (تتوفّر هذه الميزة في Android 13 والإصدارات الأحدث.)

تتألّف تحديثات التحديث الكامل عبر الهواء (OTA) من عمليات الاستبدال والصفر فقط. يمكن أن تتضمّن تحديثات التحديث التراكمي عبر الهواء (OTA) عمليات النسخ بالإضافة إلى ذلك.

يبدو تنسيق اللقطة الكاملة على القرص على النحو التالي:

تنسيق البقرة

الشكل 2: تنسيق COW في Android على القرص

dm-user

تتيح وحدة kernel dm-user لـ userspace تنفيذ أجهزة البلوكات في device-mapper. ينشئ إدخال جدول dm-user جهازًا متنوعًا ضمن /dev/dm-user/<control-name>. يمكن لعملية userspace إجراء استطلاع للجهاز لتلقّي طلبات القراءة والكتابة من kernel. يتضمّن كل طلب مخزنًا مؤقتًا مرتبطًا به لكي تملأه مساحة المستخدم (لعملية القراءة) أو تنشره (لعملية الكتابة).

توفّر وحدة kernel dm-user واجهة جديدة مرئية للمستخدم في kernel وليست جزءًا من قاعدة رموز kernel.org الرئيسية. إلى أن يتم ذلك، تحتفظ Google بالحق في تعديل واجهة dm-user في Android.

snapuserd

ينفّذ مكوّن snapuserd في مساحة المستخدم لـ dm-user عملية ضغط Virtual A/B. ‫Snapuserd هو برنامج خفي في مساحة المستخدم مسؤول عن كتابة وقراءة أجهزة COW في Android. يجب أن تمر جميع عمليات الإدخال والإخراج إلى اللقطة من خلال هذه الخدمة. أثناء تثبيت التحديث عبر الهواء (OTA)، يتم تسجيل بيانات نظام التشغيل الجديد في اللقطة من خلال snapuserd (مع الضغط). تتم أيضًا هنا عملية تحليل البيانات الوصفية وفك ضغط بيانات البلوكات الجديدة.

ضغط XOR

بالنسبة إلى الأجهزة التي يتم إطلاقها باستخدام Android 13 والإصدارات الأحدث، تتيح ميزة ضغط XOR، المفعّلة تلقائيًا، للقطات في مساحة المستخدم تخزين وحدات البايت المضغوطة باستخدام XOR بين البلوكات القديمة والجديدة. عند تغيير عدد قليل من وحدات البايت في بلوك في تحديث Virtual A/B، يستخدم نظام تخزين الضغط XOR مساحة أقل من نظام التخزين التلقائي لأنّ اللقطات لا تخزّن وحدات البايت الكاملة البالغ عددها 4K. يمكن تقليل حجم اللقطة لأنّ بيانات XOR تحتوي على العديد من الأصفار ويسهل ضغطها أكثر من بيانات البلوكات الأولية. على أجهزة Pixel، يقلّل ضغط XOR حجم اللقطة بنسبة تتراوح بين% 25 و%40.

بالنسبة إلى الأجهزة التي يتم ترقيتها إلى Android 13 والإصدارات الأحدث، يجب تفعيل ضغط XOR. لمعرفة التفاصيل، راجِع ضغط XOR.

دمج اللقطة

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

في ما يلي وصف لعملية ضغط Virtual A/B:

  1. يربط إطار العمل قسم /system من جهاز dm-verity، الذي يتم تجميعه فوق جهاز dm-user. هذا يعني أنّه يتم توجيه كل عملية إدخال وإخراج من نظام الملفات الجذر إلى dm-user.
  2. يوجه dm-user عمليات الإدخال والإخراج إلى البرنامج الخفي snapuserd في مساحة المستخدم، الذي يعالج طلب الإدخال والإخراج.
  3. عند اكتمال عملية الدمج، يقلّل الإطار dm-verity فوق dm-linear (system_base) ويزيل dm-user.

عملية ضغط A/B الافتراضية

الشكل 3: عملية ضغط Virtual A/B

يمكن إيقاف عملية دمج اللقطة. إذا تمت إعادة تشغيل الجهاز أثناء عملية الدمج، يتم استئناف عملية الدمج بعد إعادة التشغيل.

عمليات النقل الأولية

عند التشغيل باستخدام لقطات مضغوطة، يجب أن يبدأ برنامج init في المرحلة الأولى snapuserd لربط الأقسام. يطرح هذا مشكلة: عند تحميل sepolicy وتفعيله، يتم وضع snapuserd في السياق الخطأ، وتفشل طلبات القراءة، مع ظهور عمليات رفض من selinux.

لمعالجة هذه المشكلة، يتم نقل snapuserd بالتزامن مع init، على النحو التالي:

  1. يبدأ برنامج init في المرحلة الأولى snapuserd من ذاكرة الوصول العشوائي (ramdisk)، ويحفظ واصف ملف مفتوحًا له في متغيّر بيئة.
  2. يغيّر برنامج init في المرحلة الأولى نظام الملفات الجذر إلى قسم النظام، ثم ينفّذ نسخة النظام من init.
  3. تقرأ نسخة النظام من init سياسة الأمان المحسّنة (sepolicy) المدمجة في سلسلة.
  4. يستدعي Init الدالة mlock() على جميع الصفحات المستندة إلى ext4. ثم يوقف جميع جداول device-mapper لأجهزة اللقطات، ويتوقف عن استخدام snapuserd. بعد ذلك، يُحظر القراءة من الأقسام، لأنّ ذلك يؤدي إلى حدوث توقف تام.
  5. باستخدام الواصف المفتوح لنسخة ذاكرة الوصول العشوائي (ramdisk) من snapuserd، يعيد init تشغيل البرنامج الخفي باستخدام سياق selinux الصحيح. تتم إعادة تفعيل جداول device-mapper لأجهزة اللقطات.
  6. يستدعي Init الدالة munlockall()، ويمكن إجراء عمليات الإدخال والإخراج مرة أخرى بأمان.

استخدام المساحة

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

تأثير الحجم غير A/B A/B ‫Virtual A/B ‫Virtual A/B (مضغوط)
صورة المصنع الأصلية ‫4.5 غيغابايت super (صورة 3.8 غيغابايت + 700 ميغابايت محجوزة)1 ‫9 غيغابايت super (3.8 غيغابايت + 700 ميغابايت محجوزة، لمساحتَين) ‫4.5 غيغابايت super (صورة 3.8 غيغابايت + 700 ميغابايت محجوزة) ‫4.5 غيغابايت super (صورة 3.8 غيغابايت + 700 ميغابايت محجوزة)
الأقسام الثابتة الأخرى /cache بدون ما من خصومات بدون
مساحة التخزين الإضافية أثناء التحديث عبر الهواء (OTA) (المساحة التي يتم استردادها بعد تطبيق التحديث عبر الهواء (OTA)) ‫1.4 غيغابايت على /data 0 ‫3.8 غيغابايت2 على /data ‫2.1 غيغابايت2 على /data
إجمالي مساحة التخزين المطلوبة لتطبيق التحديث عبر الهواء (OTA) ‫5.9 غيغابايت3 (super والبيانات) ‫9 غيغابايت (super) ‫8.3 غيغابايت3 (super والبيانات) ‫6.6 غيغابايت3 (super والبيانات)

1يشير إلى التنسيق المفترض استنادًا إلى ربط Pixel.

2يفترض أنّ صورة النظام الجديدة لها الحجم نفسه للصورة الأصلية.

3متطلبات المساحة مؤقتة إلى حين إعادة التشغيل.

‫Virtual A/B في Android 11

في Android 11، كان Virtual A/B يسجّل في القسم الديناميكي باستخدام تنسيق COW في kernel. تم إيقاف هذا التنسيق في النهاية لأنّه لا يتيح الضغط.

‫Virtual A/B في Android 12

في Android 12، يتم دعم الضغط في شكل تنسيق COW خاص بنظام Android. تطلّب هذا الإصدار من Virtual A/B ترجمة تنسيق COW الخاص بنظام Android إلى تنسيق COW في kernel. تم استبدال ذلك في النهاية في Android 13 الذي أزال الاعتماد على تنسيق COW في kernel وأيضًا dm-snapshot.

لتنفيذ Virtual A/B أو استخدام إمكانات اللقطات المضغوطة، راجِع تنفيذ Virtual A/B