ストレージの用途別記憶領域とボリューム

投稿日:  更新日:

ストレージはデータの用途別に記憶領域が分けられます。

保存先を守らないと、セキュリティリスクが発生したり、他のアプリと協調した動作が出来なくなったり、します。

ですので、適切な場所へデータを保存しましょう。

今回は「用途別記憶領域とボリューム」について、まとめます。

※環境:Android Studio Narwhal | 2025.1.1 Patch 1

スポンサーリンク

ストレージの用途別領域

Adoptable Storage(API≧23)が導入されて以降、ストレージの構成は3つになりました。

そして、ユーザにより自由に選ぶことができます。

ストレージの構成、3タイプ

また、ストレージは用途別に利用する領域が決まっています。この領域も3つあります。

  • ★内部ストレージ(Internal)
  •   ・アプリ固有のデータを保存
  • ★外部ストレジ_プライマリ(External-Primary)
  •   ・アプリ間で共有するデータを保存
  •   ・メディアデータ(画像・動画・音楽)を保存
  • ★外部ストレージ_セカンダリ(External-Secondary)
  •   ・アプリ間で共有するデータを保存
  •   ・その他のデータ(特に選ばない)を保存

内部ストレージ

「内部ストレージ」はアプリ固有のデータを保存する領域です。

アプリ間はパッケージ名(アプリ固有の文字列)のディレクトリで隔てられています。また、マルチユーザのユーザ毎に独立した領域になっています。
※マルチユーザー環境についていは「Android OSのマルチユーザー環境」を参照

内部ストレージのディレクトリ

# pwd
/data/user
# ls -ld 0/com.example.*/*                               ↓UserID
drwxrws--x 2 u0_a174 u0_a174_cache 4096 2025-04-19 02:42 0/com.example.myapp_a/cache
drwxrws--x 2 u0_a174 u0_a174_cache 4096 2025-04-19 02:42 0/com.example.myapp_a/code_cache
drwxrwx--x 2 u0_a174 u0_a174       4096 2025-04-19 02:42 0/com.example.myapp_a/files
drwxrws--x 2 u0_a175 u0_a175_cache 4096 2025-04-19 02:41 0/com.example.myapp_b/cache
drwxrws--x 2 u0_a175 u0_a175_cache 4096 2025-04-19 02:41 0/com.example.myapp_b/code_cache
drwxrwx--x 2 u0_a175 u0_a175       4096 2025-04-19 02:42 0/com.example.myapp_b/files
             ↑UID    ↑GID                                  ↑Package

※エミュレータ(API33)で確認

アプリ固有のデータはサンドボックス内にあるので、他のアプリからアクセスは出来ません。厳重に守られます。秘匿性の高いデータの保存に適します。

内部・外部ストレージのアクセス許可

外部ストレージ_プライマリ

「外部ストレージ_プライマリ」はアプリ間の共有データを保存する領域です。

主にメディアデータ(画像・動画・音楽)を保存します。これらのデータは、Content Providerがデータベースで効率よく管理しています。

アプリからはMedia Store APIを使って、Content Resolver経由でメディアデータへアクセスする方法が提供されています。
※Content Providerについては「App Component:Content Provider」を参照

外部ストレージのフォルダ

# pwd
/storage/emulated
# ls -ld 0/* 0/Android/data/com.example.myapp_a/*       ↓UserID
drwxrws--- 2 u0_a165  media_rw    4096 2025-07-09 00:47 0/Alarms
drwxrws--x 5 media_rw media_rw    4096 2025-07-09 00:46 0/Android
drwxrws--- 3 u0_a174  ext_data_rw 4096 2025-07-09 00:56 0/Android/data/com.example.myapp_a/files
drwxrws--- 2 u0_a165  media_rw    4096 2025-07-09 00:47 0/Audiobooks   ↑Package
drwxrws--- 2 u0_a165  media_rw    4096 2025-07-09 00:47 0/DCIM
drwxrws--- 2 u0_a165  media_rw    4096 2025-07-09 00:47 0/Documents
drwxrws--- 2 u0_a165  media_rw    4096 2025-07-09 00:47 0/Download
drwxrws--- 3 u0_a165  media_rw    4096 2025-07-09 00:47 0/Movies
drwxrws--- 3 u0_a165  media_rw    4096 2025-07-09 00:47 0/Music
drwxrws--- 2 u0_a165  media_rw    4096 2025-07-09 00:47 0/Notifications
drwxrws--- 3 u0_a165  media_rw    4096 2025-07-09 00:47 0/Pictures
drwxrws--- 2 u0_a165  media_rw    4096 2025-07-09 00:47 0/Podcasts
drwxrws--- 2 u0_a165  media_rw    4096 2025-07-09 00:47 0/Recordings
drwxrws--- 2 u0_a165  media_rw    4096 2025-07-09 00:47 0/Ringtones

※エミュレータ(API33)で確認

この領域にアクセスするためには、パーミッションの取得が必要になります。

データを「他のアプリと共有する」は「他のアプリに公開する」と同意です。悪意のあるアプリがインストールされた場合に、このアプリを経由してデータ(個人情報)が漏洩します。

ですので、秘匿性の高いデータの保存に適しません。

また、マルチユーザのユーザ毎に独立した領域になっています。
※マルチユーザー環境についていは「Android OSのマルチユーザー環境」を参照

外部ストレージ_セカンダリ

「外部ストレージ―セカンダリ」はデバイス(他の携帯端末、パソコンなど)間の共有データを保存する領域です。

主にドキュメント・他のファイルを保存します。「ドキュメント・他のファイル」とは、一般的な全てのデータであり、特に一つを選びません。

外部ストレージのフォルダ

# pwd
/storage/1EEF-081A
# ls -ld * Android/data/com.example.*/*
drwxrwx--- 2 root media_rw 2048 2025-07-09 00:47 Alarms
drwxrwx--- 3 root media_rw 2048 2025-07-09 00:47 Android
drwxrwx--- 3 root media_rw 2048 2025-07-09 00:56 Android/data/com.example.myapp_a/files
drwxrwx--- 2 root media_rw 2048 2025-07-09 00:47 Audiobooks   ↑Package
drwxrwx--- 2 root media_rw 2048 2025-07-09 00:47 DCIM
drwxrwx--- 2 root media_rw 2048 2025-07-09 00:47 Documents
drwxrwx--- 2 root media_rw 2048 2025-07-09 00:47 Download
drwxrwx--- 3 root media_rw 2048 2025-07-09 00:47 Movies
drwxrwx--- 3 root media_rw 2048 2025-07-09 00:47 Music
drwxrwx--- 2 root media_rw 2048 2025-07-09 00:47 Notifications
drwxrwx--- 3 root media_rw 2048 2025-07-09 00:47 Pictures
drwxrwx--- 2 root media_rw 2048 2025-07-09 00:47 Podcasts
drwxrwx--- 2 root media_rw 2048 2025-07-09 00:47 Recordings
drwxrwx--- 2 root media_rw 2048 2025-07-09 00:47 Ringtones

※エミュレータ(API33)で確認

他のデバイス(携帯端末やパソコンなど)とデータの交換を行いたい場合は、SDカードを差し替えて行えます。これは、データが端末から持ち出されることを意味します。

ですので、プライマリ以上に、秘匿性の高いデータの保存に適していません。

スポンサーリンク

ストレージのボリューム

ボリュームとは、「記憶装置(媒体)を管理する上での単位」を言います。

先に挙げた「外部ストレージ_プライマリ/セカンダリ」に対して、このボリュームが定義されています。

ボリュームの情報を参照

StorageManager経由でボリュームの情報を参照できます。

                                val _sm = this@Activity.getSystemService(STORAGE_SERVICE) as StorageManager
                                _sm.getStorageVolumes().forEach {
                                    it.dump(this@Activity)
                                }
fun StorageVolume.dump(context: Context) {
    Log.i(TAG, "SV description = ${getDescription(context)}")
    Log.i(TAG, "SV isEmulated = ${isEmulated}")
    Log.i(TAG, "SV isPrimary = ${isPrimary}")
    Log.i(TAG, "SV isRemovable = ${isRemovable}")
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)  // API≧30
        Log.i(TAG, "SV mediaStoreVolumeName = ${mediaStoreVolumeName}")
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)  // API≧33
        Log.i(TAG, "SV owner = ${owner}")
    Log.i(TAG, "SV state = ${state}")
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)  // API≧31
        Log.i(TAG, "SV storageUuid = ${storageUuid}")
    Log.i(TAG, "SV uuid = ${uuid}")
}
SV description = Internal shared storage
SV isEmulated = true
SV isPrimary = true
SV isRemovable = false
SV mediaStoreVolumeName = external_primary
SV owner = UserHandle{0}
SV state = mounted
SV storageUuid = 41217664-9172-527a-b3d5-edabb50a7d69
SV uuid = null

※「タイプ1」の場合

タイプ1/2/3のボリューム

表に、ストレージの構成のタイプ1/2/3におけるボリューム情報を示します。

「description」はAndroidを実装したメーカーが表示内容を決めるので、実機の表示がエミュレータと同じになるとは限りません。

また「strorageUuid」と「uuid(Universally Unique IDentifier)」は、生成に使用するパラメータが携帯端末や記憶媒体の固有値に依存するので、全ての端末で必ず同じ値になるとは限りません。

タイプ1タイプ2タイプ3
パラメータプライマリセカンダリ
descriptionInternal shared storage
isEmulatedtrue
isPrimarytrue
isRemovablefalse
mediaStoreVolumeNameexternal_primary
ownerUserHandle{0}
statemounted
storageUuid41217664-9172-527a-b3d5-edabb50a7d69
uuidnull
※エミュレータ(API33)で取得
パラメータプライマリセカンダリ
descriptionVirtual SD card
isEmulatedtrue
isPrimarytrue
isRemovabletrue
mediaStoreVolumeNameexternal_primary
ownerUserHandle{0}
statemounted
storageUuid77d84f34-8278-4c5f-a8ce-995f2424d0e8
uuid77d84f34-8278-4c5f-a8ce-995f2424d0e8
※エミュレータ(API33)で取得
パラメータプライマリセカンダリ
descriptionInternal shared storageSDCARD
isEmulatedtruefalse
isPrimarytruefalse
isRemovablefalsetrue
mediaStoreVolumeNameexternal_primary1eef-081a
ownerUserHandle{0}UserHandle{0}
statemountedmounted
storageUuid41217664-9172-527a-b3d5-edabb50a7d69null
uuidnull1EEF-081A
※エミュレータ(API33)で取得

ですので、プログラム中で何かの判断に使えそうなのは、「isEmulated、isPrimary、isRemovable、state」くらいです。

例えば、「isRemovable==true」のストレージは「state==”mounted”」を確認して、SDカードがマウントされている場合のみにアクセスします。

スポンサーリンク

Appendix:FileまたはUriのボリューム

ストレージ上のファイルを一意に指定する場合に、FileやUriクラスが使われます。

FileやUriからファイルが保存されているボリュームを調べることが可能です。

                                val _sm = this@MediaActivity.getSystemService(STORAGE_SERVICE) as StorageManager

                                val _uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1000000033)
                                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { API≧30
                                    val _sv = _sm.getStorageVolume(_uri)
                                    Log.i(TAG, "Volume = ${_sv}")
                                }
Volume = StorageVolume: Internal shared storage

※「タイプ3」の場合
※エミュレータ(API33)で確認
                                val _files: Array<File> = this@MediaActivity.getExternalFilesDirs(null)
                                _files.forEach {
                                    val _sv = _sm.getStorageVolume(it)
                                    Log.i(TAG, "Volume = ${_sv}")
                                }
Volume = StorageVolume: Internal shared storage
Volume = StorageVolume: SDCARD (1EEF-081A)

※「タイプ3」の場合
※エミュレータ(API33)で確認
スポンサーリンク

Appendix:「内部」と「外部」が示す意味

内部ストレージ、外部ストレージと表記した場合の「内部」と「外部」が示す意味は、文章の目線によって異なります。

このブログでは、次のように解釈しています。

目線内部ストレージ外部ストレージ
端末のユーザー端末に内臓されたストレージ
(内部メモリー上)
端末に外付けされたストレージ
(挿入されたSDカード上)
アプリプログラム
(Android API)
サンドボックス内の領域
(アプリ内)
サンドボックス外の領域
(アプリ外)
スポンサーリンク

関連記事:

ストレージのリソースは、内部メモリー、外部メモリー、クラウドの3つがあります。 外部メモリーは、主にSDカードです。 このSDカードはAndroid端末の世代が進むにつれて、扱いを変えてきました。 リソースとSDカードを主眼に置いたストレージの変遷について、まとめます。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
Adoptable Storage(API≧23、Android 6.0)が導入されて、SDカードの扱い方をユーザ側で指定できるようになりました。 「Adoptable Storage」について、まとめます。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
ストレージへアクセスする方法は、「扱うデータの種類」「アクセス先」「セキュリティの確保」などの要件により、最適なアクセス方法が存在するので、使い分けが必要です。 今回は「アクセスする方法」について、まとめます。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
スポンサーリンク