הטמעת A/B וירטואלי

כדי להטמיע A/B וירטואלי במכשיר חדש, או כדי לתקן מכשיר חדש שהושק, עליך חייב לבצע שינויים בקוד ספציפי למכשיר.

יצירת דגלים

מכשירים שבהם נעשה שימוש ב-A/B וירטואלי חייבים להגדיר כ-A/B מכשיר וחייבת להפעיל באמצעות דינמי מחיצות קטנות.

במכשירים שמופעלים עם A/B וירטואלי, צריך להגדיר אותם לקבל בירושה את ה-A/B הווירטואלי תצורת בסיס המכשיר:

$(call inherit-product, \
    $(SRC_TARGET_DIR)/product/virtual_ab_ota.mk)

מכשירים שמופעלים עם A/B וירטואלי צריכים רק חצי מגודל הלוח BOARD_SUPER_PARTITION_SIZE כי משבצות B כבר לא ב-Super. כלומר, BOARD_SUPER_PARTITION_SIZE חייב להיות גדול מ- או שווה לו sum(size of update groups) + תקורה, שכתוצאה מכך חייבת להיות גדולה יותר מ- או שווה ל-sum(גודל המחיצות) + תקורה.

ב-Android מגרסה 13 ואילך, כדי להפעיל קובץ דחוס קובצי snapshot עם A/B וירטואלי יורשים את התצורה הבסיסית הבאה:

$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_ramdisk.mk)
$(call inherit-product, \
    $(SRC_TARGET_DIR)/product/virtual_ab_ota/android_t_baseline.mk)

כך ניתן ליצור תמונות מצב של מרחב המשתמשים באמצעות Virtual A/B תוך שימוש שיטת דחיסה. לאחר מכן אפשר להגדיר את שיטת הדחיסה לאחת methods נתמכות: gz, zstd ו-lz4.

PRODUCT_VIRTUAL_AB_COMPRESSION_METHOD := lz4

ב-Android 12, כדי להפעיל תמונות מצב דחוסות עם תכונת A/B וירטואלית תירש את ההגדרה הבסיסית הבאה:

$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_ramdisk.mk)
$(call inherit-product, \
    $(SRC_TARGET_DIR)/product/virtual_ab_ota/compression.mk)

דחיסת XOR

במכשירים שמשדרגים ל-Android 13 ואילך, תכונת הדחיסה XOR לא מופעלת כברירת מחדל. כדי להפעיל דחיסת XOR, צריך להוסיף את הפרטים הבאים קובץ .mk.

PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.compression.xor.enabled=true

דחיסת XOR מופעלת כברירת מחדל במכשירים שיורשים מ- android_t_baseline.mk

מיזוג מרחב משתמשים

במכשירים שמשדרגים ל-Android 13 ואילך, תהליך המיזוג של מרחב המשתמשים כפי שמתואר במאמר מיפוי מכשירים שכבות לא מופעלות על ידי כברירת מחדל. כדי להפעיל מיזוג של מרחב משתמשים, צריך להוסיף את השורה הבאה ל.mk של המכשיר file:

PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.userspace.snapshots.enabled=true

מיזוג מרחבי משתמשים מופעל כברירת מחדל במכשירים שמופעלים עם 13 ומעלה.

HAL של בקרת הפעלה

אמצעי הבקרה לאתחול HAL מספקת ממשק ללקוחות OTA לשליטה במשבצות האתחול. בדיקת A/B וירטואלית נדרש שדרוג גרסה משנית של בקרת האתחול HAL כי ממשקי API נוספים כדי להבטיח שתוכנת האתחול תהיה מוגנת במהלך ההבהוב או האיפוס להגדרות המקוריות. צפייה IBootControl.hal וגם types.hal לגרסה העדכנית ביותר של הגדרת HAL.

// hardware/interfaces/boot/1.1/types.hal
enum MergeStatus : uint8_t {
    NONE, UNKNOWN, SNAPSHOTTED, MERGING, CANCELLED };

// hardware/interfaces/boot/1.1/IBootControl.hal
package android.hardware.boot@1.1;
interface IBootControl extends @1.0::IBootControl {
    setSnapshotMergeStatus(MergeStatus status)
        generates (bool success);
    getSnapshotMergeStatus()
        generates (MergeStatus status);
}
// Recommended implementation

Return<bool> BootControl::setSnapshotMergeStatus(MergeStatus v) {
    // Write value to persistent storage
    // e.g. misc partition (using libbootloader_message)
    // bootloader rejects wipe when status is SNAPSHOTTED
    // or MERGING
}

שינויים ב-Fstab

התקינות של מחיצת המטא-נתונים היא חיונית לתהליך האתחול, במיוחד מיד לאחר החלת עדכון OTA. לכן, מחיצת המטא-נתונים צריך לבדוק לפני ש-first_stage_init יטען אותו. כדי להבטיח שזה יקרה, צריך להוסיף את check דגל fs_mgr לרשומה עבור /metadata. הפונקציה הבאה מספקת דוגמה:

/dev/block/by-name/metadata /metadata ext4 noatime,nosuid,nodev,discard,sync wait,formattable,first_stage_mount,check

דרישות ליבה (kernel)

כדי להפעיל יצירת תמונות מצב, צריך להגדיר את CONFIG_DM_SNAPSHOT לערך true.

במכשירים שמשתמשים ב-F2FS, צריך לכלול את הסימון f2fs: export FS_NOCOW_FL אל תיקון ליבה (kernel) של משתמש כדי לתקן את הצמדת הקובץ. מוסיפים את ה-f2fs: תמיכה מוצמדת ומוצמדת תיקון ליבה (kernel).

ביצוע A/B וירטואלי מסתמך על תכונות שנוספו בגרסת ליבה (kernel) 4.3: אפשרויות נוספות הסטטוס של היעדים snapshot ו-snapshot-merge. כל המכשירים מופעלים עם Android 9 ואילך, צריכה להיות ליבה (kernel) 4.4 ומעלה.

כדי להפעיל קובצי snapshot דחוסים, גרסת הליבה המינימלית הנתמכת היא 4.19. מגדירים את CONFIG_DM_USER=m או CONFIG_DM_USER=y. אם אתם משתמשים במודול הקודם (מודול), צריך לטעון את המודול ב-ramdisk בשלב הראשון. כדי לעשות את זה, מוסיפים את השורה הבאה לקובץ ה-Makefile של המכשיר:

BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD := dm-user.ko

תיקון מכשירים שמשדרגים ל-Android 11

כשמשדרגים ל-Android 11, מכשירים שהופעלו עם מחיצות דינמיות אופציונלי: אפשר לתקן A/B וירטואלי. תהליך העדכון זהה ברובו לתהליך של במכשירים שמושקים עם A/B וירטואלי, עם כמה הבדלים קלים:

  • המיקום של קובצי COW – במכשירי הפעלה, לקוח OTA משתמש את כל השטח הריק הזמין במחיצת העל לפני השימוש בנפח /data. עבור מכשירים לשדרוג, תמיד יש מספיק מקום מחיצה, כך שקובץ COW לא ייווצר ב-/data.

  • סימונים על פיצ'רים בזמן build – במכשירים שמחזירים לפעילות את ה-A/B הווירטואליים, גם PRODUCT_VIRTUAL_AB_OTA וגם PRODUCT_VIRTUAL_AB_OTA_RETROFIT מוגדרים אל true, כפי שמוצג באופן הבא:

    (call inherit-product, \
      (SRC_TARGET_DIR)/product/virtual_ab_ota_retrofit.mk)
    
  • גודל גדול של מחיצות — מכשירים שמופעלים עם A/B וירטואלי עלולים BOARD_SUPER_PARTITION_SIZE במחצית כי משבצות B לא נמצאות ב מחיצה. מכשירים שמותקנות בהם מעבדי A/B וירטואליים משאירים את מחיצת העל הישנה גודל, כך ש-BOARD_SUPER_PARTITION_SIZE גדול מ- או שווה ל-2 * amount(size של update groups) + תקורה, שבתורה גדולה מ-2 * amount(גודל המחיצות) + או שווה לו. תקורה.

שינויים בתוכנת האתחול

במהלך שלב המיזוג של עדכון, /data מכיל את המופע המלא היחיד של מערכת ההפעלה Android. לאחר שההעברה תתחיל, השדות system, vendor וגם product מחיצות לא הושלמו עד שההעתקה תסתיים. אם המכשיר איפוס להגדרות המקוריות במהלך התהליך הזה, על ידי שחזור או דרך המערכות בתיבת הדו-שיח של ההגדרות, לא ניתן יהיה להפעיל את המכשיר.

לפני המחיקה של /data, צריך לסיים את המיזוג בתהליך שחזור או החזרה, בהתאם מצב המכשיר:

  • אם ה-build החדש הופעל לפני כן, מסיימים את ההעברה.
  • אם לא, חוזרים למיקום הקודם:
    • למחיצות דינמיות, צריך לחזור למצב הקודם.
    • למחיצות סטטיות, צריך להגדיר את החריץ הפעיל לחריץ הישן.

גם תוכנת האתחול וגם fastbootd יכולים למחוק את המחיצה /data אם שהמכשיר לא נעול. fastbootd יכול לאלץ את השלמת ההעברה, אבל תוכנת האתחול לא יכולה. תוכנת האתחול לא יודעת אם לבצע מיזוג או אילו חסימות ב-/data מרכיבים את מחיצות מערכת ההפעלה. המכשירים חייבים למנוע מהמשתמש ללא כוונה להשבית את המכשיר (לבנים) על ידי לבצע את הפעולות הבאות:

  1. הטמעת HAL של בקרת האתחול כדי שתוכנת האתחול תוכל לקרוא את הערך שהוגדר באמצעות השיטה setSnapshotMergeStatus().
  2. אם סטטוס המיזוג הוא MERGING או אם סטטוס המיזוג הוא SNAPSHOTTED והמשבצת שונתה למיקום החדש שעודכן, ואז נשלח בקשה לאיפוס נתונים userdata, metadata או המחיצה שמאחסנת את סטטוס המיזוג חייבים להיות נדחתה בתוכנת האתחול.
  3. הטמעת הפקודה fastboot snapshot-update cancel כדי שהמשתמשים יוכלו לתוכנת האתחול שהוא רוצה לעקוף את מנגנון ההגנה הזה.
  4. שינוי סקריפטים או כלים להבהוב בהתאמה אישית כדי שיגרמו ל-fastboot snapshot-update cancel בהבהוב של המכשיר כולו. אפשר לדווח על זה כי שדרוג של כל המכשיר מסיר את ה-OTA. כלים יכולים לזהות את הפקודה הזו בזמן הריצה, באמצעות הטמעה של fastboot getvar snapshot-update-status. הזה עוזר להבחין בין תנאי שגיאה.

דוגמה

struct VirtualAbState {
    uint8_t StructVersion;
    uint8_t MergeStatus;
    uint8_t SourceSlot;
};

bool ShouldPreventUserdataWipe() {
    VirtualAbState state;
    if (!ReadVirtualAbState(&state)) ...
    return state.MergeStatus == MergeStatus::MERGING ||
           (state.MergeStatus == MergeStatus::SNAPSHOTTED &&
            state.SourceSlot != CurrentSlot()));
}

שינויים בכלים לאתחול מהיר

ב-Android 11 מתבצעים השינויים הבאים בהפעלה המהירה פרוטוקול:

  • getvar snapshot-update-status – מחזירה את הערך שהאתחול בקרת HAL שמועברת לתוכנת האתחול:
    • אם המצב הוא MERGING, תוכנת האתחול צריכה להחזיר merging.
    • אם המצב הוא SNAPSHOTTED, תוכנת האתחול צריכה להחזיר snapshotted.
    • אחרת, תוכנת האתחול חייבת להחזיר none.
  • snapshot-update merge – משלים פעולת מיזוג, אתחול אל שחזור/Fastbootd אם יש צורך. הפקודה הזו תקפה רק אם snapshot-update-status הוא merging, והוא נתמך רק ב-fastbootd.
  • snapshot-update cancel — מגדיר את סטטוס המיזוג של בקרת האתחול כ- CANCELLED. פקודה זו לא חוקית כשהמכשיר נעול.
  • erase או wipeerase או wipe מתוך metadata, userdata, או מחיצה שמחזיקה את סטטוס המיזוג של בקרת האתחול HAL צריכה לבדוק את סטטוס המיזוג של תמונת המצב. אם הסטטוס הוא MERGING או SNAPSHOTTED, המכשיר אמור לבטל את הפעולה.
  • set_active – פקודת set_active שמשנה את המיקום הפעיל צריך לבדוק את סטטוס המיזוג של תמונת המצב. אם הסטטוס הוא MERGING, המכשיר אמור לבטל את הפעולה. אפשר לשנות את יחידת הקיבולת בבטחה מצב SNAPSHOTTED.

השינויים האלה נועדו למנוע מצב שבו המכשיר לא יהיה ניתן לאתחול בטעות, אבל הן עלולות להפריע לשימוש בכלים אוטומטיים. כשהפקודות משמשות רכיב של הבהוב כל המחיצות, כמו הרצת fastboot flashall, מומלץ להשתמש בתהליך הבא:

  1. שאילתה getvar snapshot-update-status.
  2. אם מדובר ב-merging או ב-snapshotted, גיליון snapshot-update cancel.
  3. ממשיכים בשלבים ההבהוב.

הפחתת דרישות האחסון

מכשירים שלא מוקצה להם אחסון A/B מלא ב-Super, וצפויים כדי להשתמש ב-/data לפי הצורך, מומלץ מאוד להשתמש במיפוי הבלוקים של Google. כלי מיפוי הבלוקים שומר על עקביות בהקצאת הבלוקים בין גרסאות build, לצמצם פעולות כתיבה מיותרות בקובץ ה-snapshot. הדבר מתועד בקטע צמצום גודל OTA.

שיטות דחיסה OTA

ניתן לכוונן חבילות OTA לפי מדדי ביצועים שונים. מערכת Android מספקת יש כמה שיטות דחיסה נתמכות (gz, lz4, zstd ו-none) יש יחסי גומלין בין זמן התקנה, שימוש בשטח COW, זמן הפעלה ותמונת מצב בזמן המיזוג. אפשרות ברירת המחדל המופעלת עבור Ab וירטואלי עם דחיסה היא gz compression method (הערה: ביצועים יחסיים בין שיטות הדחיסה משתנה בהתאם למהירות המעבד (CPU) ולתפוקת האחסון, שעשויים להשתנות בהתאם במכשיר. כל חבילות ה-OTA שנוצרות למטה מושבתות ב-PostInstall, וכך היא תאט קצת את זמן האתחול. הגודל הכולל של המחיצה הדינמית של ערך ota מלא ללא דחיסה הוא 4.81GB.

OTA מצטבר ב-Pixel 6 Pro

שעת ההתקנה ללא השלב לאחר ההתקנה שימוש בשטח COW זמן אתחול OTA של פרסום זמן המיזוג של תמונת המצב
gz 24 דקות 1.18 GB 40.2 שנ' 45.5 שנ'
lz4 13 דקות 1.49 GB 37.4 שניות 37.1 שנ'
ללא 13 דקות 2.90 GB 37.6 שניות 40.7 שנ'

OTA מלא ב-Pixel 6 Pro

שעת ההתקנה ללא השלב לאחר ההתקנה שימוש בחלל COW זמן אתחול OTA של פרסום זמן המיזוג של תמונת המצב
gz 23 דק' 2.79 GB 24.9 שניות 41.7 שניות
lz4 12 דקות 3.46 GB 20.0 שנ' 25.3 שנ'
ללא 10 דקות 4.85 GB 20.6 שנ' 29.8 שנ'