סקירת A/B וירטואלית

קל לארגן דפים בעזרת אוספים אפשר לשמור ולסווג תוכן על סמך ההעדפות שלך.

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

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

רקע ומינוח

סעיף זה מגדיר את הטרמינולוגיה ומתאר את הטכנולוגיה התומכת ב-A/B וירטואלי.

מיפוי התקנים

Device-mapper היא שכבת בלוק וירטואלית של לינוקס המשמשת לעתים קרובות באנדרואיד. עם מחיצות דינמיות , מחיצות כמו /system הן ערימה של התקנים שכבות:

  • בתחתית הערימה נמצאת מחיצת העל הפיזית (לדוגמה, /dev/block/by-name/super ).
  • באמצע נמצא התקן dm-linear , המציין אילו בלוקים במחיצת העל יוצרים את המחיצה הנתונה. זה מופיע בתור /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 .

Partition stacking underneath system

איור 1. ערימה מתחת לנקודת ההרכבה /system

dm-תצלום

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

  • ההתקן הבסיסי הוא המכשיר שצולם. בדף זה, התקן הבסיס הוא תמיד מחיצה דינמית, כגון מערכת או ספק.
  • התקן העתקה על כתיבה (COW), לרישום שינויים במכשיר הבסיס. זה יכול להיות בכל גודל, אבל זה חייב להיות גדול מספיק כדי להכיל את כל השינויים במכשיר הבסיס.
  • התקן תמונת המצב נוצר באמצעות יעד snapshot המצב. כתיבה למכשיר תמונת המצב נכתבת למכשיר COW. קורא מהתקן תמונת המצב קורא מהתקן הבסיס או התקן COW, תלוי אם הנתונים שאליהם הגישה השתנו על ידי תמונת המצב.
  • התקן המקור נוצר באמצעות יעד snapshot-origin . קורא למכשיר המקור הנקרא ישירות מהתקן הבסיס. כותב למכשיר המקור כותב ישירות למכשיר הבסיס, אך הנתונים המקוריים מגובים בכתיבה להתקן COW.

Device mapping for dm-snapshot

איור 2. מיפוי התקן עבור dm-snapshot

צילומי מצב דחוסים

ב-Android 12 ומעלה, מכיוון שדרישות השטח במחיצת /data יכולות להיות גבוהות, אתה יכול לאפשר צילומי מצב דחוסים ב-build שלך כדי לתת מענה לדרישות השטח הגבוהות יותר של מחיצת /data .

צילומי מצב דחוסים וירטואליים A/B ​​בנויים על גבי הרכיבים הבאים הזמינים באנדרואיד 12 ואילך:

  • dm-user , מודול ליבה דומה ל-FUSE המאפשר למרחב המשתמש ליישם התקני בלוק.
  • snapuserd , דמון מרחב משתמש ליישם פורמט חדש של תמונת מצב.

רכיבים אלו מאפשרים את הדחיסה. שאר השינויים ההכרחיים שנעשו כדי ליישם את יכולות צילומי המצב הדחוסים ניתנים בסעיפים הבאים: פורמט COW עבור צילומי מצב דחוסים , dm-user ו- Snapuserd .

פורמט COW עבור צילומי מצב דחוסים

באנדרואיד 12 ומעלה, צילומי מצב דחוסים משתמשים בפורמט COW. בדומה לפורמט המובנה של הליבה המשמש לצילומי מצב לא דחוסים, בפורמט COW עבור התמונות הדחוסות יש חלקים מתחלפים של מטא נתונים ונתונים. המטא נתונים של הפורמט המקורי מותרים רק עבור פעולות החלפה : החלף בלוק X בתמונת הבסיס בתוכן של בלוק Y בתמונת המצב. פורמט COW של צילומי מצב דחוסים יותר אקספרסיבי ותומך בפעולות הבאות:

  • העתק : יש להחליף את בלוק X בהתקן הבסיס בבלוק Y בהתקן הבסיס.
  • החלף : יש להחליף את בלוק X במכשיר הבסיס בתוכן של בלוק Y בתמונת המצב. כל אחד מהבלוקים האלה הוא gz דחוס.
  • אפס : יש להחליף את בלוק X בהתקן הבסיס בכל האפסים.
  • XOR : התקן COW מאחסן XOR בתים דחוסים בין בלוק X לבלוק Y. (זמין באנדרואיד 13 ומעלה.)

עדכוני OTA מלאים מורכבים מפעולות החלפה ואפס בלבד. עדכוני OTA מצטברים יכולים להיות בנוסף לפעולות העתקה .

dm-user באנדרואיד 12

מודול הקרנל dm-user מאפשר userspace המשתמש ליישם התקני בלוק-מיפוי התקנים. ערך טבלה של dm-user יוצר התקן שונה תחת /dev/dm-user/<control-name> . תהליך userspace יכול לסקור את המכשיר כדי לקבל בקשות קריאה וכתיבה מהקרנל. לכל בקשה יש מאגר משויך שמרחב המשתמשים יוכל לאכלס (לקריאה) או להפיץ (לכתיבה).

מודול הקרנל dm-user מספק ממשק חדש גלוי למשתמש לקרנל שאינו חלק מבסיס הקוד של kernel.org במעלה הזרם. עד שזה יקרה, גוגל שומרת לעצמה את הזכות לשנות את ממשק ה- dm-user באנדרואיד.

snapuserd

רכיב snapuserd ל- dm-user מיישם דחיסת A/B וירטואלית.

בגרסה הלא דחוסה של Virtual A/B, (או באנדרואיד 11 ומטה, או באנדרואיד 12 ללא אפשרות תמונת מצב דחוסה), מכשיר COW הוא קובץ גולמי. כאשר הדחיסה מופעלת, COW מתפקד במקום זאת כהתקן dm-user , המחובר למופע של הדמון snapuserd .

הקרנל אינו משתמש בפורמט COW החדש. אז רכיב snapuserd מתרגם בקשות בין פורמט אנדרואיד COW לפורמט המובנה של הליבה:

Snapuserd component translating requests between Android COW format and kernel built-in format

איור 3. דיאגרמת זרימה של snapuserd כמתרגם בין פורמטים של אנדרואיד ו-Kernel COW

תרגום ופירוק זה לעולם לא מתרחשים בדיסק. רכיב snapuserd מיירט את הקריאה והכתיבה של COW המתרחשות בליבה, ומיישם אותן באמצעות פורמט COW של Android.

דחיסת XOR

עבור מכשירים המופעלים עם אנדרואיד 13 ומעלה, תכונת הדחיסה של XOR, המופעלת כברירת מחדל, מאפשרת לצילומי מצב של מרחב המשתמש לאחסן בתים דחוסים של XOR בין בלוקים ישנים לבלוקים חדשים. כאשר רק כמה בתים בבלוק משתנים בעדכון וירטואלי A/B, ערכת אחסון הדחיסה של XOR משתמשת בפחות מקום מסכימת האחסון המוגדרת כברירת מחדל, מכיוון שתמונות מצב אינן מאחסנות בתים של 4K מלאים. הקטנה זו בגודל תמונת מצב אפשרי מכיוון שנתוני XOR מכילים אפסים רבים וקל יותר לדחוס מאשר נתוני בלוק גולמי. במכשירי Pixel, דחיסת XOR מפחיתה את גודל תמונת המצב ב-25% עד 40%.

עבור מכשירים שמשדרגים ל-Android 13 ומעלה, יש להפעיל דחיסת XOR. לפרטים, ראה דחיסת XOR .

תהליכי דחיסה וירטואליים A/B

סעיף זה מספק פרטים על תהליך דחיסת A/B וירטואלי בשימוש ב-Android 13 ו-Android 12.

קריאת מטא נתונים (אנדרואיד 12)

מטא נתונים נבנים על ידי דמון snapuserd . המטא נתונים הם בעיקר מיפוי של שני מזהים, 8 בתים כל אחד, המייצגים את המגזרים שיש למזג. ב- dm-snapshot זה נקרא disk_exception .

struct disk_exception {
    uint64_t old_chunk;
    uint64_t new_chunk;
};

חריג של דיסק משמש כאשר נתח ישן של נתונים מוחלף בחדש.

דמון snapuserd קורא את קובץ COW הפנימי דרך ספריית COW ובונה את המטא נתונים עבור כל אחת מפעולות COW הקיימות בקובץ COW.

קריאות מטא נתונים מופעלות מתמונת ה- dm-snapshot בליבה כאשר התקן dm- dm- snapshot נוצר.

האיור שלהלן מספק דיאגרמת רצף עבור נתיב ה-IO לבניית מטא נתונים.

Sequence diagram, IO path for metadata construction

איור 4. זרימת רצף עבור נתיב ה-IO בבניית מטא נתונים

מיזוג (אנדרואיד 12)

לאחר השלמת תהליך האתחול, מנוע העדכון מסמן את המשבצת כאתחול מוצלח ומתחיל את המיזוג על ידי החלפת יעד ה- dm-snapshot למטרה dm-snapshot-merge .

dm-snapshot עובר על המטא-נתונים ומתחיל מיזוג IO עבור כל חריג דיסק. סקירה ברמה גבוהה של נתיב המיזוג IO מוצג להלן.

Merge IO path

איור 5. סקירה כללית של נתיב IO

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

שכבות ממפה התקנים

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

להלן מתאר תהליך דחיסת A/B וירטואלי:

  1. המסגרת מעלה את מחיצת /system מתוך התקן dm-verity , אשר מוערם על גבי התקן dm-user . המשמעות היא שכל קלט/פלט ממערכת קבצי השורש מנותב ל- dm-user .
  2. dm-user מנתב את ה-I/O ל- snapuserd daemon, המטפל בבקשת ה-I/O.
  3. כאשר פעולת המיזוג הושלמה, המסגרת ממוטטת dm-verity על גבי dm-linear ( system_base ) ומסירה dm-user .

תהליך דחיסת A/B וירטואלי

איור 6. תהליך דחיסה וירטואלי A/B

תהליך מיזוג תמונת המצב יכול להיות מופרע. אם המכשיר מופעל מחדש במהלך תהליך המיזוג, תהליך המיזוג יתחדש לאחר אתחול מחדש.

פתח מעברים

בעת אתחול עם צילומי מצב דחוסים, ה-init בשלב הראשון חייב להתחיל את snapuserd כדי להעלות מחיצות. זה מציב בעיה: כאשר sepolicy נטען ונאכפת, snapuserd מוכנס להקשר הלא נכון, ובקשות הקריאה שלו נכשלות, עם הכחשות selinux.

כדי לטפל בזה, snapuserd עובר בשלב נעילה עם init , באופן הבא:

  1. init שלב ראשון מפעיל את snapuserd מה-ramdisk, ושומר לו מתאר קובץ פתוח במשתנה סביבה.
  2. init שלב ראשון מעביר את מערכת הקבצים הבסיסית למחיצת המערכת, ואז מבצע את עותק המערכת של init .
  3. עותק המערכת של init קורא את המדיניות המשולבת למחרוזת.
  4. Init מפעיל את mlock() בכל הדפים המגובים ב-ext4. לאחר מכן הוא משבית את כל טבלאות מיפוי המכשירים עבור התקני תמונת מצב, ומפסיק snapuserd . לאחר מכן חל איסור לקרוא ממחיצות, שכן פעולה זו גורמת למבוי סתום.
  5. באמצעות המתאר הפתוח לעותק ramdisk של snapuserd , init מפעיל מחדש את הדמון עם ההקשר הנכון של selinux. טבלאות מיפוי התקנים עבור התקני תמונת מצב מופעלות מחדש.
  6. Init מפעיל את munlockall() - זה בטוח לבצע שוב IO.

שימוש בחלל

הטבלה הבאה מספקת השוואה של שימוש בשטח עבור מנגנוני OTA שונים תוך שימוש בגדלים של מערכת ההפעלה וה-OTA של Pixel.

גודל השפעה לא A/B א/ב A/B וירטואלי A/B וירטואלי (דחוס)
תמונת מפעל מקורית סופר 4.5GB (תמונה 3.8G + 700M שמורות) 1 9GB סופר (3.8G + 700M שמורות, עבור שני חריצים) 4.5GB סופר (תמונה 3.8G + 700M שמורות) 4.5GB סופר (תמונה 3.8G + 700M שמורות)
מחיצות סטטיות אחרות /cache אף אחד אף אחד אף אחד
אחסון נוסף במהלך OTA (שטח שהוחזר לאחר החלת OTA) 1.4GB על /data 0 3.8GB 2 על /data 2.1GB 2 על /data
נפח האחסון הכולל הנדרש כדי להחיל OTA 5.9GB 3 (סופר ונתונים) 9GB (סופר) 8.3GB 3 (סופר ונתונים) 6.6GB 3 (סופר ונתונים)

1 מציין פריסה משוערת המבוססת על מיפוי פיקסל.

2 מניח שתמונת מערכת חדשה זהה לגודל המקורי.

3 דרישת המקום היא חולפת עד לאתחול מחדש.

להטמעת A/B וירטואלית, או להשתמש ביכולות של תמונת מצב דחוסה, ראה הטמעת A/B וירטואלי