ストレージはデータの用途別に記憶領域が分けられます。
保存先を守らないと、セキュリティリスクが発生したり、他のアプリと協調した動作が出来なくなったり、します。
ですので、適切な場所へデータを保存しましょう。
今回は「用途別記憶領域とボリューム」について、まとめます。
※環境:Android Studio Narwhal | 2025.1.1 Patch 1
目次
ストレージの用途別領域
Adoptable Storage(API≧23)が導入されて以降、ストレージの構成は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)」は、生成に使用するパラメータが携帯端末や記憶媒体の固有値に依存するので、全ての端末で必ず同じ値になるとは限りません。
パラメータ | プライマリ | セカンダリ |
---|---|---|
description | Internal shared storage | |
isEmulated | true | |
isPrimary | true | |
isRemovable | false | |
mediaStoreVolumeName | external_primary | |
owner | UserHandle{0} | |
state | mounted | |
storageUuid | 41217664-9172-527a-b3d5-edabb50a7d69 | |
uuid | null | |
※エミュレータ(API33)で取得 |
パラメータ | プライマリ | セカンダリ |
---|---|---|
description | Virtual SD card | |
isEmulated | true | |
isPrimary | true | |
isRemovable | true | |
mediaStoreVolumeName | external_primary | |
owner | UserHandle{0} | |
state | mounted | |
storageUuid | 77d84f34-8278-4c5f-a8ce-995f2424d0e8 | |
uuid | 77d84f34-8278-4c5f-a8ce-995f2424d0e8 | |
※エミュレータ(API33)で取得 |
パラメータ | プライマリ | セカンダリ |
---|---|---|
description | Internal shared storage | SDCARD |
isEmulated | true | false |
isPrimary | true | false |
isRemovable | false | true |
mediaStoreVolumeName | external_primary | 1eef-081a |
owner | UserHandle{0} | UserHandle{0} |
state | mounted | mounted |
storageUuid | 41217664-9172-527a-b3d5-edabb50a7d69 | null |
uuid | null | 1EEF-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) | サンドボックス内の領域 (アプリ内) | サンドボックス外の領域 (アプリ外) |
関連記事: