# 介紹

截至本文編寫的時間(2023-03-06),在 Android 系統中應用程式對公共儲存空間的濫用仍然是一個沒有解決的問題。

儲存空間隔離致力於在儘可能小或不影響應用程式功能的前提下,解決這一問題。

要清楚地說明這個問題,我們不得不先引入一些技術性的概念。

# Android 系統對於儲存空間的設計

Android 系統為應用程式提供了兩大類共三處儲存其檔案的位置,它們分別為:

# data 區域

對應的資料夾:

  • /data/user/<user_id>/<package_name>
  • /storage/emulated/<user_id>/Android/data/<package_name>

<user_id> 為使用者 ID,涉及 Android 的多使用者/工作資料機制,與本文主題無關。

<package_name> 為應用程式的唯一 ID。

這兩個資料夾應該用於儲存應用程式自身的資料,具有如下特點:

  • 應用程式無需請求權限即可使用
  • 只有應用程式自身可以訪問
  • 在解除安裝應用程式或清除應用程式資料後會被刪除

/storage/emulated/<user_id>/Android/data/<package_name>/data/user/<user_id>/<package_name> 的用處相同。它的存在是因為一些歷史原因:在 Android 4.x 及更早的時代,裝置自帶的儲存空間通常非常小,外接 SD 卡會被用來擴充套件儲存空間,此處便也被用作儲存應用程式自身的資料。

# 內部儲存空間

對應的資料夾:

  • /storage/emulated/<user_id>

此處應存放對使用者有用的檔案,例如使用者在應用程式中儲存的圖片。Android 系統提供了 DCIMDownloadPictures 等公共資料夾用於分門別類地儲存照片、下載的檔案等。此處還可以被成為「共享儲存空間」、「公共儲存空間」等。

具有如下特點:

  • 需要儲存權限才可以讀取
  • 需要儲存權限才可以寫入〔1〕
  • 擁有儲存權限的應用程式可以讀取其中所有的檔案,包括由其他應用程式、使用者寫入的檔案
  • 在解除安裝應用程式或清除應用程式資料後,應用程式寫入的檔案不會被刪除

〔1〕 在 Android 11 後有變化,請參考下文

# 應用程式訪問檔案的方式

除了最基本的直接透過檔案路徑訪問以外,Android 系統還提供了其他幾種方式。

  • 媒體儲存

    媒體儲存是一個系統應用程式,其內部有一個包含內部儲存空間中所有檔案資訊的資料庫。最常見的用例是,從媒體儲存查詢所有的圖片檔案。讀取、寫入檔案也可以透過媒體儲存進行。

  • 儲存訪問框架(Storage Access Framework,簡稱 SAF)

    SAF 是一個 Android 4.4 起新增的功能。藉助 SAF,使用者可以從一個統一的由系統提供的 UI 進行開啟檔案、儲存檔案等操作。應用程式程式還可以自己成為一個提供程式,其他使用 SAF 的應用程式便可使用它。

    SAF 的好處是應用程式僅可使用由使用者選擇的檔案、統一的 UI、應用程式無需請求權限等等。

    但是,多數應用程式還是更傾向於請求儲存權限後自己實現需要的功能。

# 什麼是應用程式濫用儲存空間的問題

對儲存空間的濫用是對「內部儲存空間」的濫用。 一些應用程式或一些 SDK 會希望自己的資料檔案在解除安裝後不會被刪除,因此它們會選擇「內部儲存空間」寫入其資料檔案。

如果應用程式有「傳送圖片」、「儲存檔案」等功能,使用者很多時候就不得不授予應用程式儲存權限。它們就會藉此在「內部儲存空間」寫入一大堆奇奇怪怪的資料夾(見下圖)。久而久之使用者的儲存空間將變得混亂無比。

例子

許多濫用儲存空間的應用程式建立一堆奇奇怪怪的資料夾,甚至以「SystemConfig」命名來讓使用者誤以為是系統檔案。

例子

# Android 11 新增的 Scoped storage

許多人認為「Scoped storage」能夠解決這個問題,但是事實並非如此。

受「Scoped storage」限制的應用程式在使用公共儲存空間時的行為會發生如下的變化:

  • 僅可在公共資料夾中寫入對應型別的檔案(但是系統只會檢查檔名稱是否符合規則)
  • 不需要任何權限即可在公共資料夾中寫入檔案(這比以前更加寬鬆!)

顯然我們可以發現,仍然可以寫入任意檔案,唯一的區別僅僅是需要調整儲存檔案的位置到某個公共檔案中,調整檔名來欺騙系統。

此外,「Scoped storage」僅作用於以 Android 11 或以上版本為目標平臺的應用程式(即 Target API ≥ 31)。不在 Google Play 上架的應用程式或停止更新的老應用程式不會受到限制。

# 解決這個問題

為了解決上面這個問題,我們創造了這個應用程式——儲存空間隔離。

使用者可以為特定的應用程式啟用隔離。應用程式所使用的「內部儲存空間」實際將變為 /storage/emulated/<user_id>/Android/data/<package_name> 中的一個資料夾。因此,真正的「內部儲存空間」將不會被汙染,其建立的檔案也會在解除安裝後得以刪除。

我們提供了多種機制來保證被隔離的應用程式在需要使用「內部儲存空間」中的檔案時工作正常。請閱讀後續的文件。