העברת FUSE

ב-Android 12 יש תמיכה ב-FUSE passthrough, שמצמצם את התקורה של FUSE כדי להשיג ביצועים דומים לאלה של גישה ישירה למערכת הקבצים ברמה הנמוכה יותר. התכונה FUSE passthrough נתמכת בליבות android12-5.4,‏ android12-5.10 ו-android-mainline (בדיקה בלבד). כלומר, התמיכה בתכונה הזו תלויה בליבה שבה המכשיר משתמש ובגרסת Android שפועלת במכשיר:

  • מכשירים שעוברים שדרוג מ-Android 11 ל-Android 12 לא יכולים לתמוך ב-FUSE passthrough כי הליבות של המכשירים האלה קפואות, והן לא יכולות לעבור לליבה ששודרגה באופן רשמי עם השינויים של FUSE passthrough.

  • במכשירים שיושקו עם Android 12 תהיה תמיכה ב-FUSE passthrough כשמשתמשים בליבה רשמית. במכשירים כאלה, קוד המסגרת של Android שמטמיע העברה ישירה (passthrough) של FUSE מוטמע במודול הראשי MediaProvider, שמשודרג באופן אוטומטי. גם במכשירים שלא מטמיעים את MediaProvider כמודול ראשי (למשל, מכשירי Android Go), יש גישה לשינויים ב-MediaProvider כי הם משותפים באופן ציבורי.

FUSE לעומת SDCardFS

מערכת קבצים במרחב המשתמש (FUSE) היא מנגנון שמאפשר לליבה (בקר FUSE) להעביר למיקור חוץ פעולות שמבוצעות במערכת קבצים של FUSE, לתוכנית במרחב המשתמש (דימון FUSE) שמטמיעה את הפעולות. ב-Android 11 הוצאנו משימוש את SDCardFS והפכנו את FUSE לפתרון ברירת המחדל להדמיית אחסון. במסגרת השינוי הזה, הטמענו ב-Android דימון FUSE משלו כדי ליירט גישה לקבצים, לאכוף תכונות אבטחה ופרטיות נוספות ולבצע פעולות על קבצים בזמן הריצה.

ב-FUSE הביצועים טובים כשמדובר במידע שאפשר לשמור במטמון, כמו דפים או מאפיינים, אבל הוא גורם לנסיגה בביצועים כשנכנסים לאחסון חיצוני, במיוחד במכשירים ברמה בינונית ובמכשירים ברמה נמוכה. הנסיגות האלה נגרמות על ידי שרשרת של רכיבים שמשתפים פעולה בהטמעה של מערכת הקבצים FUSE, וגם על ידי מספר מעברים ממרחב הליבה למרחב המשתמש בתקשורת בין מנהל ה-FUSE לבין הדימון של FUSE (בהשוואה לגישה ישירה למערכת הקבצים התחתונה, שהיא יעילה יותר ומוטמעת באופן מלא בליבה).

כדי לצמצם את הנסיגות האלה, אפליקציות יכולות להשתמש בהצמדה כדי לצמצם את העתקת הנתונים, ולהשתמש ב-ContentProvider API כדי לקבל גישה ישירה לקבצים ברמה נמוכה יותר של מערכת הקבצים. גם עם השיפורים האלה ושיפורים אחרים, יכול להיות שרוחב הפס של פעולות קריאה וכתיבה יהיה קטן יותר כשמשתמשים ב-FUSE בהשוואה לגישה ישירה למערכת הקבצים ברמה הנמוכה יותר  – במיוחד בפעולות קריאה אקראיות, שבהן לא ניתן להיעזר במטמון או בקריאה מראש. בנוסף, אפליקציות שמקבלות גישה ישירה לאחסון דרך הנתיב הקודם /sdcard/ ממשיכות להראות ירידה משמעותית בביצועים, במיוחד כשהן מבצעות פעולות עם עומס גבוה על קלט/פלט.

בקשות של מרחב המשתמש ב-SDcardFS

השימוש ב-SDcardFS יכול להאיץ את הדמיית האחסון ובדיקות ההרשאות של FUSE על ידי הסרת הקריאה של מרחב המשתמש מהליבה. בקשות במרחב המשתמש עוברות את הנתיב: מרחב המשתמש → VFS‏ → sdcardfs‏ → VFS‏ → ext4‏ → מטמון דפים/אחסון.

FUSE Passthrough SDcardFS

איור 1. בקשות של מרחב המשתמש ב-SDcardFS

בקשות של מרחב המשתמש של FUSE

בהתחלה, FUSE שימש להפעלת אמולציית אחסון ולאפשרות לאפליקציות להשתמש באופן שקוף באחסון הפנימי או בכרטיס SD חיצוני. השימוש ב-FUSE גורם לקצת זמן אחזור מיותר, כי כל בקשה במרחב המשתמש עוברת את הנתיב: מרחב המשתמש → VFS‏ → מנהל ההתקן של FUSE‏ → דימון FUSE‏ → VFS‏ → ext4‏ → מטמון דפים/אחסון.

FUSE Passthrough FUSE

איור 2. בקשות של מרחב המשתמש של FUSE

בקשות העברה של FUSE

רוב הרשאות הגישה לקובץ נבדקות בזמן פתיחת הקובץ, ובדיקות נוספות של ההרשאות מתבצעות בזמן קריאה מהקובץ ובזמן כתיבת הקובץ. במקרים מסוימים, אפשר לדעת בזמן פתיחת הקובץ שלאפליקציה המבקשת יש גישה מלאה לקובץ המבוקש, כך שהמערכת לא צריכה להמשיך להעביר את הבקשות לקריאה ולכתיבה מהדריבר של FUSE לדימון של FUSE (כי הפעולה הזו רק מעבירה נתונים ממקום אחד למקום אחר).

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

בהמשך מוצגת השוואה בין בקשות FUSE לבין בקשות העברה של FUSE.

השוואה בין FUSE Passthrough

איור 3. בקשת FUSE לעומת בקשת העברה של FUSE

כשאפליקציה מבצעת גישה למערכת קבצים של FUSE, מתבצעות הפעולות הבאות:

  1. מנהל ההתקן של FUSE מטפל בבקשה ומוסיף אותה לתור, ואז מעביר אותה לדימון FUSE שמטפל במערכת הקבצים של FUSE דרך מופע חיבור ספציפי בקובץ /dev/fuse, שקריאה שלו חסומה לדימון FUSE.

  2. כשהדימון של FUSE מקבל בקשה לפתוח קובץ, הוא מחליט אם תהיה זמינה העברה ישירה (passthrough) של FUSE עבור הקובץ הספציפי הזה. אם הוא זמין, הדימון:

    1. שליחת הודעה לנהג FUSE על הבקשה הזו.

    2. הפעלת העברה של FUSE לקובץ באמצעות FUSE_DEV_IOC_PASSTHROUGH_OPEN ioctl, שצריך לבצע על מתאר הקובץ של /dev/fuse שנפתח.

  3. הפונקציה ioctl מקבלת (כפרמטר) מבנה נתונים שמכיל את הנתונים הבאים:

    • מתאר הקובץ של קובץ מערכת הקבצים ברמה הנמוכה יותר, שהוא היעד של תכונת העברה.

    • המזהה הייחודי של בקשת ה-FUSE שמטופלת כרגע (חייבת להיות פתוחה או שנוצרה ונפתחה).

    • שדות נוספים שאפשר להשאיר ריקים, והם מיועדים להטמעות עתידיות.

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

    • אם יש קובץ עזר, מנהל ההתקן יוצר בקשה חדשה למערכת קבצים וירטואלית (VFS) עם אותם פרמטרים שמטרגטים את הקובץ של מערכת הקבצים הנמוכה יותר.

    • אם אין הפניה זמינה, הנהג מעביר את הבקשה לדימון (daemon) של FUSE.

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

הטמעת העברה דרך FUSE

כדי להפעיל העברה (passthrough) של FUSE במכשירים עם Android 12, מוסיפים את השורות הבאות לקובץ $ANDROID_BUILD_TOP/device/…/device.mk של מכשיר היעד.

# Use FUSE passthrough
PRODUCT_PRODUCT_PROPERTIES += \
    persist.sys.fuse.passthrough.enable=true

כדי להשבית את העברת הנתונים של FUSE, משמיטים את שינוי התצורה שלמעלה או מגדירים את persist.sys.fuse.passthrough.enable ל-false. אם הפעלתם בעבר את תכונת העברת הנתונים של FUSE, השבתה שלה תמנע מהמכשיר להשתמש בה, אבל המכשיר ימשיך לפעול.

כדי להפעיל או להשבית את העברת הנתונים של FUSE בלי להפעיל את המכשיר, משנים את מאפיין המערכת באמצעות פקודות ADB. דוגמה מופיעה בהמשך.

adb root
adb shell setprop persist.sys.fuse.passthrough.enable {true,false}
adb reboot

לקבלת עזרה נוספת, אפשר לעיין בהטמעת העזרה.

אימות העברה דרך FUSE

כדי לוודא ש-MediaProvider משתמש ב-FUSE passthrough, בודקים את logcat כדי לראות אם יש הודעות ניפוי באגים. לדוגמה:

adb logcat FuseDaemon:V \*:S
--------- beginning of main
03-02 12:09:57.833  3499  3773 I FuseDaemon: Using FUSE passthrough
03-02 12:09:57.833  3499  3773 I FuseDaemon: Starting fuse...

הרשומה FuseDaemon: Using FUSE passthrough ביומן מוודאת שנעשה שימוש ב-FUSE passthrough.

בדיקת ה-CTS של Android 12 כוללת את CtsStorageTest, שכולל בדיקות שמפעילות העברה ישירה (passthrough) של FUSE. כדי להריץ את הבדיקה באופן ידני, משתמשים ב-atest כפי שמתואר בהמשך:

atest CtsStorageTest