StorageManager Overview
The StorageManager is the public API provided by the Android framework for apps to interact with the device's storage systems. It acts as the client-facing proxy for the StorageManagerService, which orchestrates the complex logic of storage volume lifecycles and communicates natively with vold.
StorageManager API
Apps use the StorageManager to query available storage, request allocation space, and obtain UUIDs for storage volumes.
StorageManager storageManager = context.getSystemService(StorageManager.class);
// Get a list of all storage volumes available to the user
List<StorageVolume> volumes = storageManager.getStorageVolumes();
for (StorageVolume volume : volumes) {
boolean isRemovable = volume.isRemovable();
String uuid = volume.getUuid();
// Check state (e.g., mounted, unmounted, bad_removal)
String state = volume.getState();
}
StorageVolume Types: Public vs. Private
Android categorizes storage volumes into two primary types:
- Private Volumes: These are encrypted using keys specific to the device. They are formatted with a Linux file system (EXT4 or F2FS) and support standard POSIX permissions. The internal
/datapartition is a private volume. Adoptable storage drives also become private volumes. - Public Volumes: These are visible to other devices (e.g., when plugged into a PC) and are not encrypted by the Android OS. They are typically formatted with FAT32 or exFAT to ensure broad compatibility. Portable SD cards and USB OTG drives are public volumes.
Scoped Storage (Android 10+)
Introduced in Android 10 and enforced in Android 11, Scoped Storage drastically changed how apps access external storage. Previously, the READ_EXTERNAL_STORAGE permission granted an app access to the entire external storage partition.
Scoped Storage restricts this:
- App-Specific Directories: Apps have unrestricted access to their own external app-specific directories (
Context.getExternalFilesDir()) without any permissions. - Shared Media: To access shared media (photos, videos, audio), apps must use the
MediaStoreAPI. - Downloads and Documents: Accessing non-media files created by other apps requires the user to pick the file explicitly using the Storage Access Framework (SAF) via
ACTION_OPEN_DOCUMENT.
Behind the scenes, Android implements Scoped Storage using a FUSE (Filesystem in Userspace) daemon or sdcardfs alongside mount namespaces, ensuring that standard file path access (/sdcard/DCIM/...) is intercepted and permission-checked by the framework.
MediaStore API
The MediaStore provides an optimized, indexed database of all media files on the device. It abstracts the underlying file system, allowing apps to query media by metadata rather than traversing directories.
// Querying for all images using MediaStore
String[] projection = { MediaStore.Images.Media._ID, MediaStore.Images.Media.DISPLAY_NAME };
Uri collection = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
try (Cursor cursor = context.getContentResolver().query(
collection, projection, null, null, null)) {
while (cursor.moveToNext()) {
long id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID));
String name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME));
Uri contentUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id);
// Use contentUri to load the image
}
}
Debugging StorageManager
You can view the internal state of the StorageManagerService using dumpsys.
adb shell dumpsys mount
This command outputs detailed information about all mounted volumes, disks, user states, and connected FUSE daemons.