עדכוני A/B וירטואליים הם מנגנון העדכון העיקרי של Android. עדכוני A/B וירטואליים מבוססים על עדכוני A/B מדור קודם (ראו עדכוני מערכת A/B) ועל עדכונים שהם לא A/B, שהוצאו משימוש בגרסה 15 כדי לצמצם את התקורה של העדכונים.
למעשה, אין ב-Virtual A/B משבצת נוספת למחיצות דינמיות. מידע נוסף על מחיצות דינמיות במקום זאת, הדלתא נכתבת לתמונת מצב, ואז מתבצע מיזוג שלה עם מחיצת הבסיס אחרי אישור של הפעלה מוצלחת. בבדיקות A/B וירטואליות נעשה שימוש בפורמט ספציפי של תמונת מצב ל-Android. אפשר לעיין במאמר בנושא פורמט COW לדחיסת קובצי snapshot, שמאפשר לדחוס קובצי snapshot ולצמצם את השימוש במקום בדיסק. ב-OTA מלא, גודל התמונה מצטמצם בכ-45% באמצעות דחיסה, וב-OTA מצטבר, גודל התמונה מצטמצם בכ-55%.
Android 12 מציע את האפשרות של דחיסת Virtual A/B לדחיסת מחיצות של תמונות מצב. היתרונות של בדיקות A/B וירטואליות
- עדכוני A/B וירטואליים הם ללא הפרעה (העדכון מתבצע כולו ברקע בזמן שהמכשיר פועל). עדכוני A/B וירטואליים מצמצמים את הזמן שבו המכשיר במצב אופליין ולא ניתן לשימוש.
- אפשר לבטל עדכוני A/B וירטואליים. אם מערכת ההפעלה החדשה לא מצליחה לבצע אתחול, המכשירים חוזרים אוטומטית לגרסה הקודמת.
- עדכוני A/B וירטואליים משתמשים במינימום של נפח אחסון נוסף כי הם משכפלים רק את המחיצות שמשמשות את טוען האתחול. מחיצות אחרות שאפשר לעדכן מצולמות.
רקע וטרמינולוגיה
בקטע הזה מוגדרת הטרמינולוגיה ומתואר הטכנולוגיה שתומכת בבדיקות A/B וירטואליות. במהלך התקנת OTA, נתוני מערכת הפעלה חדשים נכתבים למקום החדש שלהם במחיצות הפיזיות, או למכשיר COW ספציפי ל-Android. אחרי שמפעילים מחדש את המכשיר, נתוני המחיצה הדינמית משולבים בחזרה במכשיר הבסיסי באמצעות השדים dm-user ו-snapuserd. התהליך הזה מתרחש כולו במרחב המשתמש.
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 מציג את המערך מתחת לנקודת הטעינה /system.
איור 1. הערימה מתחת לנקודת הטעינה /system
תמונות מצב דחוסות
ב-Android 12 ומעלה, דרישות המקום במחיצת /data יכולות להיות גבוהות. כדי לעמוד בדרישות המקום הגבוהות יותר במחיצת /data, אפשר להפעיל צילומי מצב דחוסים ב-build.
תמונות מצב דחוסות של 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 במכשיר הבסיס.
- Replace: התוכן של בלוק 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 מספק ממשק חדש שגלוי למשתמשים בליבה, שלא נכלל ב-code base של הליבה ב-kernel.org. עד אז, Google שומרת לעצמה את הזכות לשנות את הממשק של dm-user ב-Android.
snapuserd
רכיב snapuserd בסביבת המשתמש של dm-user מטמיע דחיסה וירטואלית של בדיקות A/B. Snapuserd הוא daemon של מרחב משתמש שאחראי על כתיבה וקריאה של מכשירי COW ב-Android. כל פעולות הקלט והפלט של התמונה צריכות לעבור דרך השירות הזה.
במהלך התקנת OTA, נתוני מערכת הפעלה חדשים נכתבים לתמונת המצב על ידי snapuserd (עם דחיסה). כאן מתבצע גם הניתוח של המטא-נתונים והפירוק של נתוני בלוק חדשים.
דחיסת XOR
במכשירים עם Android מגרסה 13 ומעלה, התכונה XOR compression (דחיסת XOR) מופעלת כברירת מחדל ומאפשרת ליצור תמונות מצב של מרחב המשתמש כדי לאחסן בייטים דחוסים של 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. המשמעות היא שכל פעולת קלט/פלט ממערכת הקבצים הבסיסית מנותבת אל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ה-daemon מופעל מחדש עם הקשר ה-selinux הנכון. טבלאות של מיפוי מכשירים למכשירים של תמונות מצב מופעלות מחדש. - הפונקציה Init מפעילה את
munlockall()– אפשר לבצע שוב קלט/פלט.
שימוש במרחב
בטבלה הבאה מוצגת השוואה של השימוש במקום בזיכרון עבור מנגנוני OTA שונים, באמצעות גדלי מערכת ההפעלה ו-OTA של Pixel.
| השפעה של גודל | non-A/B | A/B | בדיקת A/B וירטואלית | Virtual A/B (compressed) |
|---|---|---|---|---|
| תמונת המפעל המקורית | 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 (super and data) | 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, שבו הוסרה ההסתמכות על פורמט Kernel COW וגם על dm-snapshot.
כדי להטמיע בדיקות A/B וירטואליות או להשתמש ביכולות של snapshot דחוס, אפשר לעיין במאמר בנושא הטמעה של בדיקות A/B וירטואליות.