Virtual A/B הוא מנגנון העדכון העיקרי של Android. בניית בדיקות A/B וירטואליות מתבססת על עדכוני A/B מדור קודם (ראו עדכוני מערכת A/B) ועל עדכונים שאינם A/B, שהוצאו משימוש בגרסה 15 כדי לצמצם את התקורה של העדכונים.
למעשה, בבדיקות A/B וירטואליות אין משבצת נוספת למחיצות דינמיות. מידע נוסף על מחיצות דינמיות במקום זאת, הדלתא נכתבת לתמונת מצב, ואז היא ממוזגת למחיצת הבסיס אחרי אישור של הפעלה מוצלחת. בבדיקות A/B וירטואליות נעשה שימוש בפורמט ספציפי של תמונת מצב ל-Android. אפשר לעיין במאמר בנושא פורמט COW לדחיסת קובצי snapshot, שמאפשר לדחוס קובצי snapshot ולצמצם את השימוש במקום בדיסק. ב-OTA מלא, גודל התמונה מצטמצם בכ-45% באמצעות דחיסה, וב-OTA מצטבר, גודל התמונה מצטמצם בכ-55%.
ב-Android 12 יש אפשרות לדחיסת A/B וירטואלית כדי לדחוס מחיצות של תמונות מצב. היתרונות של בדיקות A/B וירטואליות
- עדכוני A/B וירטואליים הם חלקים (העדכון מתבצע כולו ברקע בזמן שהמכשיר פועל). עדכוני A/B וירטואליים מצמצמים את הזמן שבו המכשיר במצב אופליין ולא ניתן לשימוש.
- אפשר לבטל עדכונים של בדיקות A/B וירטואליות. אם מערכת ההפעלה החדשה לא מצליחה לאתחל את המכשיר, המכשירים חוזרים אוטומטית לגרסה הקודמת.
- עדכוני A/B וירטואליים משתמשים במינימום של מקום נוסף כי הם משכפלים רק את המחיצות שמשמשות את טוען האתחול. מחיצות אחרות שאפשר לעדכן מצולמות.
רקע וטרמינולוגיה
בקטע הזה מוגדרת הטרמינולוגיה ומתואר הטכנולוגיה שתומכת בבדיקות A/B וירטואליות. במהלך התקנת OTA, נתוני מערכת ההפעלה החדשים נכתבים למחיצה הפיזית החדשה שלהם, או למכשיר COW ספציפי ל-Android. אחרי שמבצעים הפעלה מחדש של המכשיר, נתוני המחיצה הדינמית משולבים בחזרה במכשיר הבסיסי באמצעות השימוש ב-dm-user וב-snapuserd daemon. התהליך הזה מתבצע כולו במרחב המשתמש.
Device-mapper
Device-mapper היא שכבת בלוק וירטואלית של Linux שמשמשת לעיתים קרובות ב-Android. עם מחיצות דינמיות, מחיצות כמו /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 מוצג איך נראה ה-stack מתחת לנקודת ה-mount /system
.
איור 1. הערימה מתחת לנקודת הטעינה /system
תמונות מצב דחוסות
ב-Android מגרסה 12 ואילך, יכול להיות שדרישות המקום במחיצה /data
יהיו גבוהות. כדי לעמוד בדרישות האלה, אפשר להפעיל צילומי מצב דחוסים ב-build./data
תמונות מצב דחוסות של Virtual A/B מבוססות על הרכיבים הבאים שזמינים ב-Android מגרסה 12 ואילך:
-
dm-user
, מודול ליבה שדומה ל-FUSE ומאפשר למרחב המשתמש להטמיע התקני בלוקים. -
snapuserd
, דמון במרחב המשתמש ליישום פורמט חדש של תמונת מצב.
הרכיבים האלה מאפשרים את הדחיסה. בקטעים הבאים מפורטים השינויים הנוספים שצריך לבצע כדי להטמיע את היכולות של תמונות מצב דחוסות: פורמט COW לתמונות מצב דחוסות, dm-user ו-snapuserd.
פורמט COW לתמונות מצב דחוסות
ב-Android מגרסה 12 ואילך, תמונות מצב דחוסות משתמשות בפורמט COW ספציפי ל-Android. פורמט ה-COW מכיל מטא-נתונים לגבי ה-OTA, ויש בו מאגרי נתונים נפרדים שמכילים פעולות COW ונתונים חדשים של מערכת ההפעלה. לעומת פורמט תמונת המצב של הליבה שמאפשר רק פעולות החלפה (החלפת בלוק X בתמונת הבסיס בתוכן של בלוק Y בתמונת המצב), פורמט ה-COW של תמונות מצב דחוסות ב-Android הוא מפורט יותר ותומך בפעולות הבאות:
- העתקה: צריך להחליף את בלוק X במכשיר הבסיסי בבלוק Y במכשיר הבסיסי.
- החלפה: צריך להחליף את בלוק X במכשיר הבסיסי בתוכן של בלוק Y בתמונת המצב. כל אחד מהבלוקים האלה עובר דחיסה בפורמט gz.
- 0: החסימה של X במכשיר הבסיס צריכה להיות מוחלפת באפסים.
- XOR: מכשיר ה-COW מאחסן בייטים דחוסים של XOR בין בלוק X לבין בלוק Y. (זמין ב-Android מגרסה 13 ואילך).
עדכוני OTA מלאים כוללים רק פעולות replace ו-zero. עדכוני OTA מצטברים יכולים לכלול גם פעולות העתקה.
פריסת התמונה המלאה בדיסק נראית כך:
איור 2. פורמט COW של Android בכונן
dm-user
מודול הליבה dm-user מאפשר ל-userspace
ליישם מכשירי בלוק של מיפוי מכשירים. רשומה בטבלה dm-user יוצרת מכשיר שונה בקטע /dev/dm-user/<control-name>
. תהליך userspace
יכול לבצע סקר במכשיר כדי לקבל בקשות קריאה וכתיבה מהליבה. לכל בקשה יש מאגר משויך במרחב המשתמשים, שאפשר לאכלס (לקריאה) או להפיץ (לכתיבה).
מודול הליבה dm-user
מספק ממשק חדש שגלוי למשתמשים בליבה, שלא מהווה חלק מבסיס הקוד של upstream kernel.org. עד אז, Google שומרת לעצמה את הזכות לשנות את הממשק של dm-user
ב-Android.
snapuserd
רכיב snapuserd
בסביבת המשתמש של dm-user
מטמיע דחיסה של בדיקות A/B וירטואליות. Snapuserd הוא דמון במרחב המשתמש שאחראי על כתיבה וקריאה של מכשירי COW ב-Android. כל פעולות הקלט והפלט של התמונה צריכות לעבור דרך השירות הזה.
במהלך התקנת OTA, נתוני מערכת הפעלה חדשים נכתבים לתמונת המצב על ידי snapuserd (עם דחיסה). כאן מתבצע גם הניתוח של המטא-נתונים והפירוק של נתוני בלוק חדשים.
דחיסת XOR
במכשירים שמופעלת בהם מערכת Android מגרסה 13 ואילך, התכונה XOR compression מופעלת כברירת מחדל ומאפשרת ליצור תמונות מצב של מרחב המשתמש כדי לאחסן בייטים דחוסים של XOR בין בלוקים ישנים לבלוקים חדשים. כשמעדכנים בדיקת A/B וירטואלית ומשנים רק כמה בייטים בבלוק, תוכנית האחסון של דחיסת XOR משתמשת בפחות נפח אחסון מאשר תוכנית האחסון שמוגדרת כברירת מחדל, כי תמונות המצב לא מאחסנות 4K בייטים מלאים. הקטנת גודל תמונת המצב אפשרית כי נתוני ה-XOR מכילים הרבה אפסים וקל יותר לדחוס אותם מאשר נתוני בלוק גולמיים. במכשירי Pixel, דחיסת XOR מקטינה את גודל התמונה ב-25% עד 40%.
במכשירים שמשדרגים ל-Android מגרסה 13 ואילך, צריך להפעיל דחיסה מסוג XOR. פרטים נוספים מופיעים במאמר בנושא דחיסת XOR.
מיזוג תמונות מצב
במכשירים עם Android מגרסה 13 ומעלה, תהליכי תמונת המצב ומיזוג תמונת המצב בדחיסת Virtual A/B מתבצעים על ידי רכיב מרחב המשתמש snapuserd
. במכשירים שמשדרגים ל-Android מגרסה 13 ואילך, צריך להפעיל את התכונה הזו. לפרטים נוספים, אפשר לעיין במאמר בנושא מיזוג של מרחב משתמשים.
התהליך של דחיסת בדיקות A/B וירטואליות מתואר בהמשך:
- המסגרת מטמיעה את המחיצה
/system
במכשירdm-verity
, שנמצא מעל מכשירdm-user
. המשמעות היא שכל פעולת קלט/פלט (I/O) ממערכת הקבצים הבסיסית (root) מנותבת אלdm-user
. -
dm-user
מעביר את קלט/פלט אל דמוןsnapuserd
של מרחב המשתמש, שמטפל בבקשת קלט/פלט. - בסיום פעולת המיזוג, המסגרת מתכווצת
dm-verity
מעלdm-linear
(system_base
) ו-dm-user
מוסר.
איור 3. תהליך הדחיסה של בדיקת A/B וירטואלית
אפשר להפריע לתהליך המיזוג של התמונות. אם המכשיר מופעל מחדש במהלך תהליך המיזוג, תהליך המיזוג ימשיך אחרי ההפעלה מחדש.
העברות של נתוני אתחול
כשמבצעים אתחול עם תמונות מצב דחוסות, תהליך האתחול בשלב הראשון צריך להתחיל
snapuserd
כדי לטעון מחיצות. הבעיה היא: כש-sepolicy
נטען ונאכף, snapuserd
מוצב בהקשר שגוי, והבקשות שלו לקריאה נכשלות, עם דחיות של selinux.
כדי לפתור את הבעיה הזו, המעבר של snapuserd
מתבצע במקביל למעבר של init
, באופן הבא:
- בשלב הראשון,
init
מפעיל אתsnapuserd
מ-ramdisk ושומר בו מתאר קובץ פתוח במשתנה סביבה. - בשלב הראשון
init
מחליף את מערכת הקבצים הבסיסית למחיצת המערכת, ואז מפעיל את העותק של המערכת שלinit
. - עותק המערכת של
init
קורא את מדיניות האבטחה המשולבת כמחרוזת. -
Init
מפעיל אתmlock()
בכל הדפים שמגובים על ידי ext4. לאחר מכן, הוא משבית את כל הטבלאות של device-mapper במכשירים של תמונת מצב, ומפסיק אתsnapuserd
. אחרי זה אסור לקרוא ממחיצות, כי פעולה כזו גורמת לקיפאון. - שימוש בתיאור הפתוח כדי להעתיק את
snapuserd
ל-ramdisk, init
מפעיל מחדש את הדמון עם הקשר ה-selinux הנכון. טבלאות של מיפוי מכשירים למכשירים של תמונות מצב מופעלות מחדש. - הפונקציה Init מפעילה את
munlockall()
– אפשר לבצע שוב קלט/פלט.
שימוש במרחב
בטבלה הבאה מוצגת השוואה של השימוש במקום בזיכרון עבור מנגנוני OTA שונים, באמצעות גדלי מערכת ההפעלה ו-OTA של Pixel.
השפעה על הגודל | non-A/B | A/B | בדיקת A/B וירטואלית | בדיקת A/B וירטואלית (דחוסה) |
---|---|---|---|---|
Original Factory Image | 4.5GB סופר (תמונה של 3.8G + 700M שמורים)1 | 9GB סופר (3.8G + 700M שמורים, לשני חריצים) | 4.5GB סופר (תמונה בנפח 3.8GB + 700MB שמורים) | 4.5GB סופר (תמונה בנפח 3.8GB + 700MB שמורים) |
מחיצות סטטיות אחרות | /cache | ללא | ללא | ללא |
נפח אחסון נוסף במהלך OTA (הנפח יוחזר אחרי החלת ה-OTA) | 1.4GB ב- /data | 0 | 3.8GB2 ב- /data | 2.1GB2 ב- /data |
נפח האחסון הכולל שנדרש להחלת OTA | 5.9GB3 (סופר ונתונים) | 9GB (סופר) | 8.3GB3 (סופר ונתונים) | 6.6GB3 (סופר ונתונים) |
1 מציין פריסה משוערת שמבוססת על מיפוי Pixel.
2מניח שתמונת המערכת החדשה זהה בגודלה לתמונה המקורית.
3דרישת המקום היא זמנית עד להפעלה מחדש.
Android 11 Virtual A/B
Android 11 של Virtual A/B כתב למחיצה דינמית באמצעות פורמט Kernel COW. בסופו של דבר, הפורמט הזה הוצא משימוש כי הוא לא תומך בדחיסה.
Android 12 Virtual A/B
ב-Android 12, הדחיסה נתמכת בפורמט COW ספציפי ל-Android. בגרסה הזו של Virtual A/B נדרש תרגום של ה-COW הספציפי ל-Android לפורמט Kernel COW. בסופו של דבר, היא הוחלפה ב-Android 13, שבו הוסרה ההסתמכות על פורמט ה-COW של הליבה וגם על dm-snapshot
.
כדי להטמיע בדיקות A/B וירטואליות או להשתמש ביכולות של snapshot דחוס, אפשר לעיין במאמר בנושא הטמעה של בדיקות A/B וירטואליות.