保險絲直通

Android 12 支援 FUSE 直通,可最大限度地減少 FUSE 開銷,以實現與直接存取較低檔案系統相當的效能。 android12-5.4android12-5.10android-mainline (僅測試)內核支援 FUSE 直通,這意味著對此功能的支援取決於裝置使用的核心以及裝置運行的 Android 版本:

  • 從 Android 11 升級到 Android 12 的裝置無法支援 FUSE 直通,因為這些裝置的核心已凍結,並且無法移動到已透過 FUSE 直通更改正式升級的核心。

  • 使用 Android 12 啟動的裝置在使用官方核心時可以支援 FUSE 直通。對於此類設備,實作FUSE透傳的Android框架程式碼嵌入在MediaProvider主線模組中,該模組會自動升級。未將 MediaProvider 實現為主線模組的裝置(例如 Android Go 裝置)也可以存取公開共享的 MediaProvider 變更。

FUSE 與 SDCardFS

使用者空間檔案系統 (FUSE)是一種機制,允許核心(FUSE 驅動程式)將FUSE 檔案系統上執行的操作外包給使用者空間程式(FUSE 守護程式),並由使用者空間程式(FUSE 守護程式)實現這些操作。 Android 11棄用了 SDCardFS ,並使 FUSE 成為儲存模擬的預設解決方案。作為此更改的一部分,Android 實作了自己的 FUSE 守護程序來攔截檔案存取、實施額外的安全性和隱私功能以及在執行時間操作檔案。

雖然 FUSE 在處理可快取資訊(例如頁面或屬性)時表現良好,但在存取外部儲存時會出現效能下降,這一點在中低階裝置中尤其明顯。這些迴歸是由在FUSE 檔案系統實作中協作的一系列元件以及FUSE 驅動程式和FUSE 守護程式之間的通訊中從核心空間到使用者空間的多次切換所引起的(與直接存取較低層檔案相比)更精簡且完全在核心中實現的系統)。

為了減輕這些回歸,應用程式可以使用拼接來減少資料複製,並使用ContentProvider API來直接存取較低的檔案系統檔案。即使進行了這些和其他優化,與直接存取較低層檔案系統相比,使用FUSE 時讀取和寫入操作可能會看到頻寬減少,特別是對於隨機讀取操作,沒有快取或預讀可以提供幫助。透過舊版/sdcard/路徑直接存取儲存的應用程式繼續經歷明顯的效能下降,特別是在執行 IO 密集型操作時。

SDcardFS 使用者空間請求

使用SDcardFS可以透過從核心中刪除用戶空間呼叫來加速FUSE的儲存模擬和權限檢查。使用者空間請求遵循以下路徑:使用者空間→VFS→sdcardfs→VFS→ext4→頁面快取/儲存。

FUSE直通SDcardFS

圖 1. SDcardFS 使用者空間請求

FUSE 使用者空間請求

FUSE 最初用於啟用儲存模擬並允許應用程式透明地使用內部儲存或外部 SD 卡。使用 FUSE 會帶來一些開銷,因為每個使用者空間請求都遵循以下路徑:使用者空間 → VFS → FUSE 驅動程式 → FUSE 守護程式 → VFS → ext4 → 頁面快取/儲存。

保險絲 直通保險絲

圖 2. FUSE 使用者空間請求

FUSE 直通請求

大多數檔案存取權限在檔案開啟時進行檢查,並在讀取和寫入該檔案時進行額外的權限檢查。在某些情況下,可以在檔案開啟時知道請求應用程式具有對所請求檔案的完全存取權限,因此系統不需要繼續將讀寫請求從 FUSE 驅動程式轉送到 FUSE 守護程式(因為只會將資料從一個地方移動到另一個地方)。

透過FUSE passthrough,處理開啟請求的FUSE守護程序可以通知FUSE驅動程式允許該操作,並且所有後續的讀寫請求都可以直接轉送到下層檔案系統。這避免了等待使用者空間 FUSE 守護程式回覆 FUSE 驅動程式請求的額外開銷。

FUSE 和 FUSE 直通請求的比較如下所示。

FUSE直通比較

圖 3. FUSE 請求與 FUSE 直通請求

當應用程式執行FUSE檔案系統存取時,會發生以下操作:

  1. FUSE 驅動程式處理請求並將其排入佇列,然後呈現給 FUSE 守護程序,該程式透過/dev/fuse檔案上的特定連線實例來處理FUSE 檔案系統,FUSE 守護程序將被阻止讀取該文件。

  2. 當 FUSE 守護程式收到開啟檔案的請求時,它會決定 FUSE 直通是否可用於該特定檔案。如果可用,守護程式:

    1. 通知 FUSE 驅動程式有關此請求。

    2. 使用FUSE_DEV_IOC_PASSTHROUGH_OPEN ioctl 為檔案啟用 FUSE 直通,該操作必須在開啟的/dev/fuse的檔案描述符上執行。

  3. ioctl 接收(作為參數)包含以下內容的資料結構:

    • 作為直通功能目標的較低檔案系統檔案的檔案描述符。

    • 目前正在處理的 FUSE 請求的唯一識別碼(必須開啟或建立並開啟)。

    • 可以留空並供將來實現的額外欄位。

  4. 如果 ioctl 成功,FUSE 守護程序完成開啟請求,FUSE 驅動程式處理 FUSE 守護程式回复,並且對下層檔案系統檔案的參考將會新增至核心內的 FUSE 檔案。當應用程式要求對 FUSE 檔案進行讀取/寫入操作時,FUSE 驅動程式會檢查較低檔案系統檔案的參考是否可用。

    • 如果引用可用,驅動程式將建立一個新的虛擬檔案系統 (VFS) 請求,其具有針對較低檔案系統檔案的相同參數。

    • 如果引用不可用,驅動程式會將請求轉送至 FUSE 守護程式。

上述操作發生在通用文件上的讀/寫和讀迭代器/寫迭代器以及記憶體映射檔案上的讀/寫操作。給定檔案的 FUSE 直通一直存在,直到該檔案關閉為止。

實施 FUSE 直通

若要在執行 Android 12 的裝置上啟用 FUSE 直通,請將下列行新增至目標裝置的$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 直通,但裝置仍保持功能。

若要啟用/停用 FUSE 直通而不刷新設備,請使用 ADB 指令變更系統屬性。一個例子如下所示。

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

如需其他協助,請參閱參考實作

驗證 FUSE 直通

若要驗證 MediaProvider 是否正在使用 FUSE 直通,請檢查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 直通正在使用中。

Android 12 CTS 包含CtsStorageTest ,其中包含觸發 FUSE 直通的測試。若要手動執行測試,請使用 atest,如下所示:

atest CtsStorageTest