在 Android 系統中,每個應用程式都會需要儲存資料:
StorageManagerService 是 SystemServer 啟動的核心服務之一,位於 Android Framework 層,主要負責:
+-------------------------------------------------------------+
| Android Framework 層 |
|-------------------------------------------------------------|
| App Process | MediaProvider | SystemUI | Settings |
|-------------------------------------------------------------|
| StorageManagerService (SMS) |
| ↑ ↑ ↑ |
| │ │ │ |
| MountService StorageStats StorageVolume API |
+-------------------------------------------------------------+
| Native 層 (vold, sdcardd) |
| vold ↔ libstoragemanager ↔ kernel (ext4, f2fs, fuse) |
+-------------------------------------------------------------+
| Linux Kernel 層 (VFS) |
| /data, /sdcard, /mnt/runtime/default |
+-------------------------------------------------------------+
(1) 啟動時機
SystemServer.java 在開機階段會啟動 StorageManagerService:
traceBeginAndSlog("StartStorageManagerService");
mSystemServiceManager.startService(StorageManagerService.class);
traceEnd();
(2) 初始化階段
在 StorageManagerService.java 的 onStart() 方法中:
Android 採用「多層式儲存抽象架構」,可分為三大類:
| 類型 | 路徑範例 | 說明 |
|---|---|---|
| 內部儲存 (Internal Storage) | /data/data/<package> |
每個 App 獨立空間(沙箱) |
| 外部儲存 (External Storage) | /storage/emulated/0/ |
共用空間(照片、影片、下載) |
| 可移除儲存 (Removable Storage) | /storage/XXXX-XXXX |
SD 卡或 USB 裝置 |
Android 的 App 沙箱機制是基於 Linux User ID (UID) 的安全隔離模型:
+---------------------------------------------+
| App A (UID=10056) -> /data/data/com.appA/ |
| ├── shared_prefs/ |
| ├── cache/ |
| └── databases/ |
+---------------------------------------------+
| App B (UID=10057) -> /data/data/com.appB/ |
| ├── files/ |
| ├── cache/ |
| └── lib/ |
+---------------------------------------------+
↑ 無法直接跨訪問
系統層面透過 SELinux Policy 與 Mount Namespace 來防止跨應用存取。
StorageManagerService 與底層的 vold(Volume Daemon)協作,管理實際的磁碟掛載。
| Volume 類型 | 主要種類說明 |
|---|---|
| Public Volume | 可移除媒體,如 SD 卡、USB |
| Private Volume | App 專屬儲存空間,採加密方式存放 |
| Emulated Volume | 模擬外部儲存(常見於 /storage/emulated/0) |
掛載流程
[SD 卡插入]
↓
kernel uevent
↓
vold 接收事件並建立 Volume 物件
↓
StorageManagerService 通知系統 (mountVolume)
↓
BroadcastReceiver 廣播 ACTION_MEDIA_MOUNTED
↓
MediaProvider 重新掃描媒體檔案
自 Android 10 (API 29) 起,Google 引入 Scoped Storage,限制 App 對外部儲存的訪問範圍。
改變前後對比:
| 版本 | 存取模式 | 範圍 |
|---|---|---|
| Android 9 以前 | WRITE_EXTERNAL_STORAGE | 可自由讀寫 /sdcard/ |
| Android 10 以後 | Scoped Storage | 僅可訪問 App 專屬目錄或授權檔案 |
Scoped Storage 的導入讓 StorageManagerService 的職責更重,因為它需協調:
SAF 是 Android 為解決使用者檔案選取而設計的高階 API。
底層仍由 StorageManagerService 協助管理 URI 存取權限。
Ex.
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "image/*"
}
startActivityForResult(intent, PICK_IMAGE)
使用者選取檔案後,App 會得到一個 content:// URI,而非實際檔案路徑。
該 URI 背後由 DocumentsProvider 與 StorageManagerService 協調管理,確保安全。
Android 的檔案權限系統綜合了以下三層防護:
| 層級 | 技術 | 說明 |
|---|---|---|
| Kernel 層 | UID/GID 權限位元 | 以 Linux 檔案權限模式 (rwx) 控制存取 |
| Framework 層 | StorageManagerService + AppOps | 判斷呼叫者權限 |
| 應用層 | Scoped Storage、FileProvider | 控制授權的 URI |
此外,StorageManagerService 也負責:
| 資料類型 | 路徑 | 存取方式 |
|---|---|---|
| 內部私有資料 | /data/data// | 僅該 App 可用 |
| 外部私有資料 | /storage/emulated/0/Android/data// | 需權限 |
| 共用媒體資料 | /storage/emulated/0/DCIM、Pictures | 經由 MediaStore 存取 |
| 暫存檔案 | /cache/ | 系統可清除 |
| API | 功能 |
|---|---|
| getVolumes() | 取得所有儲存裝置資訊 |
| getUuidForPath() | 查詢 Volume UUID |
| getAllocatableBytes() | 取得可用空間 |
| mount() / unmount() | 掛載或卸載 Volume |
| registerListener() | 註冊磁碟事件監聽 |
| setPrimaryStorageUuid() | 指定主要儲存區 |
Ex.
val sm = context.getSystemService(StorageManager::class.java)
val volumes = sm.storageVolumes
volumes.forEach {
Log.d("Volume", "desc=${it.getDescription(context)} path=${it.directory}")
}
StorageManagerService 也負責統計各 App 的磁碟用量,供設定頁面「儲存空間」顯示。
Settings → Storage → App usage
實作上透過:
Android 會依據用量進行清理(如自動刪除 Cache),確保儲存空間健康。
+--------------------+ +------------------------+
| App (com.appA) | | App (com.appB) |
| UID=10055 | | UID=10056 |
| request file | | |
+---------+----------+ +-----------+------------+
| |
v v
[StorageManagerService] ←───→ [AppOpsManager]
│ │
v v
[vold / sdcardd] ←──→ [Kernel / SELinux]
│
v
/data, /mnt, /storage/emulated/0
Android 的儲存架構逐漸朝向:
| 關鍵點 | 說明 |
|---|---|
| 核心職責 | 管理儲存裝置、App 沙箱與存取權限 |
| 系統位置 | Framework 層的 System Service |
| 關聯元件 | vold、MediaProvider、AppOpsManager |
| 主要挑戰 | 平衡安全性、可用性與相容性 |
| 演進趨勢 | Scoped Storage、SAF、使用者授權化 |
+-------------------------------------------+
| App Layer |
| (File API, MediaStore, SAF) |
+--------------------▲----------------------+
│
+--------------------│----------------------+
| Framework Layer |
| StorageManagerService / AppOpsManager |
+--------------------▲----------------------+
│
+--------------------│----------------------+
| Native Layer (vold, libstoragemgr) |
+--------------------▲----------------------+
│
+--------------------│----------------------+
| Kernel Layer (VFS, ext4, FUSE, SELinux)|
+-------------------------------------------+