範圍存儲限制應用程序對外部存儲的訪問。在 Android 11 或更高版本中,面向 API 30 或更高版本的應用必須使用範圍存儲。在之前的 Android 10 中,應用可以選擇退出範圍存儲。
應用訪問限制
範圍存儲的目標是保護應用程序和用戶數據的隱私。這包括保護用戶信息(例如照片元數據),防止應用在未經明確許可的情況下修改或刪除用戶文件,以及保護下載到下載或其他文件夾的敏感用戶文檔。
使用範圍存儲的應用程序可以具有以下訪問級別(實際訪問權限是特定於實現的)。
- 在沒有權限的情況下對自己的文件進行讀寫訪問
- 具有READ_EXTERNAL_STORAGE權限的其他應用程序媒體文件的
READ_EXTERNAL_STORAGE
權限 - 只有在用戶直接同意的情況下才允許對其他應用程序的媒體文件進行寫入訪問(授予系統庫和有資格獲得所有文件訪問權限的應用程序除外)
- 沒有對其他應用程序的外部應用程序數據目錄的讀取或寫入權限
將範圍存儲與 FUSE 結合使用
Android 11 或更高版本支持用戶空間中的文件系統 (FUSE),這使 MediaProvider 模塊能夠檢查用戶空間中的文件操作,並根據允許、拒絕或編輯訪問的策略來控制對文件的訪問。範圍存儲中使用 FUSE 的應用程序獲得範圍存儲的隱私功能以及使用直接文件路徑訪問文件的能力(保持文件 API 在應用程序中工作)。
由於攔截內核調用需要付出努力,Android 10 對 MediaProvider 的文件訪問強制實施了範圍存儲規則,但不適用於直接文件路徑訪問(例如,使用 File API 和 NDK API)。因此,範圍存儲中的應用程序無法使用直接文件路徑訪問文件。此限制影響了應用程序開發人員的適應能力,因為它需要大量代碼更改來重寫 File API 對 MediaProvider API 的訪問。
FUSE 和 SDCardFS
Android 11 對 FUSE 的支持與SDCardFS 的棄用無關,但確實為以前使用 SDCardFS 的設備提供了媒體存儲的替代方案。設備:
- 使用內核 5.4 或更高版本啟動 Android 11 或更高版本無法使用 SDCardFS。
- 升級到 Android 11 或更高版本可以在 SDCardFS 之上託管 FUSE 以攔截文件操作並滿足隱私目標。
FUSE 性能調優
Android 之前在 Android 7 或更低版本中支持 FUSE,其中外部存儲被掛載為 FUSE。由於該 FUSE 實現的性能和死鎖問題,Android 8 引入了 SDCardFS。 Android 11 使用改進的、經過更好測試的libfuse
實現重新引入了對 FUSE 的支持,可以對其進行調整以解決 Android 7 或更低版本中的性能問題。
FUSE 調整包括以下調整:
- 繞過
Android/data
和Android/obb
目錄的 FUSE,以提高依賴這些目錄的遊戲應用程序的性能。 - 優化(例如調整 FUSE 文件系統的預讀和臟比)以保持讀取性能和媒體播放流暢。
- 使用 FUSE 回寫緩存。
- 緩存權限以減少對系統服務器的 IPC。
- 對具有所有文件訪問權限的應用程序進行了優化,以加快批量操作。
上述調整可以在 FUSE 和非 FUSE 設備之間產生相當的性能。例如,測試使用 FUSE 的 Pixel 2 和使用 Media Store 的 Pixel 2 發現文件路徑訪問和 Media Store 之間的順序讀取性能(例如,視頻播放)相當。但是,使用 FUSE 的順序寫入稍微差一些,隨機讀取和寫入的速度可能會慢兩倍。
性能測量可以在不同設備之間以及在特定用例之間發生變化。因為 MediaProvider API 提供最一致的性能,所以關心性能的應用程序開發人員應該在他們的應用程序中使用 MediaProvider API。
減輕 FUSE 性能影響
FUSE 性能影響僅限於存儲在外部共享存儲上的文件的重度用戶。外部私有存儲(包括android/data
和android/obb
目錄)被 FUSE 繞過,而內部存儲(例如/data/data
,許多應用程序存儲數據以保持其加密和安全)沒有安裝 FUSE。
共享外部存儲的輕量級用戶應用程序通常與一組有限的文件(通常少於 100 個文件)進行交互。這些應用受益於對常見讀寫操作的現有優化,並且在 Android 11 中不會看到任何與 FUSE 相關的性能影響。
大量使用共享外部存儲的應用程序通常會執行批量文件操作,例如列出或刪除包含 1000 個文件的目錄,或者在文件系統上創建或刪除包含一百萬個文件的目錄。批量文件操作可能會受到 Android 11 上 FUSE 的影響,但如果此類應用符合
MANAGE_EXTERNAL_STORAGE
權限的條件,它們將受益於 2020 年 10 月更新中包含的性能優化。
為了避免 FUSE 性能開銷,應用程序可以將數據存儲在外部私有存儲中或使用ContentProvider
類中的批量 API 繞過 FUSE 並獲得性能優化的路徑。此外,2020 年 10 月對 MediaProvider 系統組件的更新包括對擁有MANAGE_EXTERNAL_STORAGE
權限的文件管理器和類似應用程序(例如備份/恢復、防病毒)的性能優化。
隱私高於性能
在針對 FUSE 進行了調整的設備上,大多數關鍵用戶旅程在 Android 10 和 Android 11 之間的性能相同。但是,在針對一組文件操作測試基準時,Android 11 的性能可能比 Android 10 差。對於執行的文件訪問模式在 Android 11 中更糟糕的是(例如,隨機讀取或寫入),我們建議使用 MediaProvider API 為應用程序提供非 FUSE 訪問模式,這是最佳且始終如一的性能選項。
MediaProvider 和 FUSE 更新
MediaProvider系統組件的行為因 Android 版本而異。
在 Android 10 及更低版本中,SDCardFS 是文件系統,MediaProvider 為文件集合(例如,圖像、視頻、音樂文件等)提供了一個接口。當應用程序使用 File API 創建文件時,它可以要求 MediaProvider 掃描文件並將其記錄在數據庫中。
在 Android 11 或更高版本中, SDCardFS已被棄用,MediaProvider 成為外部存儲的文件系統處理程序(用於 FUSE),使外部存儲上的文件系統和 MediaProvider 數據庫保持一致。作為 FUSE 文件系統的用戶空間處理程序,MediaProvider 可以攔截內核調用並確保文件操作是隱私安全的。
在 Android 11 及更高版本中,MediaProvider 也是一個模塊化系統組件(一個 Mainline 模塊),可以在 Android 版本之外進行更新。這意味著在 MediaProvider 中發現的性能、隱私或安全問題可以通過 Google Play 商店或其他合作夥伴提供的機制進行修復和傳輸。 FUSE 處理程序預期範圍內的任何內容也是可更新的,支持更新以修復 FUSE 性能回歸和錯誤。