Advanced AOSP Subsystems
3 min read

Adoptable Storage

Adoptable Storage Architecture

Adoptable Storage (introduced in Android 6.0 Marshmallow) allows a user to format a removable storage device (like a microSD card or a USB drive) to act like internal storage. Once "adopted," the device becomes an encrypted, private volume that the system uses to store apps, app data, and media seamlessly.

Adoptable SD Card: Encrypted as Internal Storage

When a drive is adopted, it ceases to be a traditional "Public Volume" (typically formatted as FAT32/exFAT). Instead, Android treats it as an extension of the /data partition.

Key characteristics of adopted storage:

  • Encryption: The disk is encrypted using a key randomly generated by Android. This key is stored on the device's internal memory. Consequently, the adopted SD card cannot be read if inserted into a PC or another Android phone.
  • Filesystem: The drive is formatted with a Linux file system, usually EXT4 or F2FS, to support POSIX permissions, symlinks, and extended attributes required by Android apps.

Partition and Format Flow

The process of adopting a storage device is orchestrated by StorageManagerService and executed by vold.

  1. Partitioning: The framework sends a partition() command to vold. vold uses tools like sgdisk to rewrite the partition table of the SD card. It typically creates an Android metadata partition and a primary data partition.
  2. Key Generation: A new encryption key is generated and stored in the internal /data/misc/vold directory.
  3. Formatting: vold formats the newly created partition with mkfs.ext4 or make_f2fs, applying the encryption parameters via fscrypt.
  4. Mounting: The volume is mounted. The framework maps it into the user's view, often shifting the primary shared storage (/sdcard) onto this new volume.

App and Data Migration

Once adopted, users can migrate their existing data to the new storage.

// Example: Requesting migration via StorageManager
StorageManager sm = context.getSystemService(StorageManager.class);
sm.setPrimaryStorageUuid(adoptedVolumeUuid, new IPackageMoveObserver.Stub() {
    @Override
    public void onCreated(int moveId, Bundle extras) {}
    @Override
    public void onStatusChanged(int moveId, int status, long estMillis) {
        // Handle progress updates
    }
});

When an app is installed, the PackageManagerService determines the best location for it based on the app's manifest flag android:installLocation. If an adopted volume is present and has space, the APK, optimized DEX, and app data directory (/data/user/0/com.example.app) can be physically placed on the SD card.

Practical Commands

You can simulate and manage adoptable storage using the sm (Storage Manager) command-line tool.

List available disks:

adb shell sm list-disks

Output example: disk:179,64

Force adoption of a disk: To format the entire disk as private/adoptable storage:

adb shell sm partition disk:179,64 private

Mixed partitioning: Format 50% as adoptable (private) and 50% as portable (public):

adb shell sm partition disk:179,64 mixed 50