ストレージ

Android の外部ストレージ HAL のアイコン

Android は、さまざまなストレージ デバイスの種類と機能に対応するため、時間とともに進化してきました。Android のすべてのバージョンで、ポータブル ストレージとエミュレートされたストレージを含む従来のストレージを備えたデバイスをサポートします。ポータブル ストレージは、SD カードや USB などの物理メディアによって提供され、一時的なデータ転送やファイル保存に使用されます。物理メディアは長時間デバイスに接続したままにすることもありますが、デバイスには結合されておらず、取り外しが可能です。SD カードは Android 1.0 以降でポータブル ストレージとして利用できます。USB のサポートは Android 6.0 で追加されました。エミュレートされたストレージは、内部ストレージの一部をエミュレーション レイヤを通じて公開することで提供され、Android 3.0 以降で利用できます。

Android 6.0 以降、Android では Adoptable Storage をサポートするようになりました。これは、SD カードや USB などの物理メディアによって提供され、暗号化とフォーマットを行ったうえで内部ストレージと同様に動作するストレージです。Adoptable Storage には、あらゆる種類のアプリデータを保存できます。

権限

外部ストレージへのアクセスは、さまざまな Android 権限によって保護されます。 Android 1.0 以降、書き込みアクセスは WRITE_EXTERNAL_STORAGE 権限で保護されています。また、Android 4.1 以降からは、読み取りアクセスが READ_EXTERNAL_STORAGE 権限で保護されています。

Android 4.4 以降、外部ストレージ デバイス上のファイルのオーナー、グループ、モードについては、ディレクトリ構造に基づいて統合されるようになりました。その結果、アプリで多様な WRITE_EXTERNAL_STORAGE 権限を保持しなくても、外部ストレージのパッケージ固有のディレクトリを管理できるようになりました。たとえば、パッケージ名が com.example.foo のアプリは、外部ストレージ デバイスの Android/data/com.example.foo/ に権限なしで自由にアクセスできます。このような統合された権限は、FUSE デーモン内の RAW ストレージ デバイスをラップすることで実現されます。

Android 10 以降、Android 9 以下をターゲットとするアプリは従来のストレージをデフォルトとして使用し、分離型ストレージをオプトインできます。Android 10 をターゲットとし、デフォルトで分離型ストレージを使用するアプリは、一時的なオプトアウトも可能です。デフォルトの状態を変更するには、ストレージ モデルを制御するマニフェスト属性 requestLegacyExternalStorage を使用します。

READ_EXTERNAL_STORAGE 権限と WRITE_EXTERNAL_STORAGE 権限はいずれもソフト制限されているため、インストール時にアプリを許可リストに登録しなかった場合、これらの権限には SD カードへのアクセス権が含まれず、聴覚および視覚コレクションへのアクセスのみを制御します。これは、アプリが従来のストレージをリクエストする場合も同様です。ハード制限とソフト制限の詳細については、Android 10 のハード制限とソフト制限をご覧ください。

インストール時に権限を許可リストに登録した場合、レガシーモードで実行されるアプリは未分割の権限に従って動作します。この権限により、SD カードへのアクセスと、聴覚および視覚コレクションの制御が行えます。これは、アプリが Android 9 以下をターゲットにしていて分離型ストレージをオプトインしていない場合、または Android 10 をターゲットにしていて分離型ストレージをオプトアウトしている場合に生じます。

許可リストの状態は、インストール時にのみ指定可能で、アプリのインストールが終了するまで変更できません。

READ_EXTERNAL_STORAGE 権限の設定については、PackageInstaller.SessionParams クラスの setWhitelistedRestrictedPermissions() をご覧ください。

実行時の権限

Android 6.0 では、新しいランタイム権限モデルが導入されました。これは、アプリが実行時に必要に応じて機能をリクエストするものです。新しいモデルには READ/WRITE_EXTERNAL_STORAGE 権限が含まれているため、プラットフォームでは、すでに実行中のアプリを強制終了または再起動することなく、ストレージ アクセスを動的に付与する必要があります。これは、マウントされたすべてのストレージ デバイスの 3 つの異なるビューを維持することで実現されます。

  • /mnt/runtime/default は、特別なストレージ権限を持たないアプリと、adbd および他のシステム コンポーネントが稼働しているルート名前空間に対して表示されます。
  • /mnt/runtime/read は、READ_EXTERNAL_STORAGE を持つアプリ(LEGACY_STORAGE を Android 10 用に設定)に対して表示されます。
  • /mnt/runtime/write は、WRITE_EXTERNAL_STORAGE を持つアプリに対して表示されます。

Zygote でのフォーク時には、実行中のアプリごとにマウント名前空間が作成され、適切な初期ビューが所定の場所にバインド マウントされます。その後、ランタイム権限が付与されると、vold はすでに実行中のアプリのマウント名前空間にジャンプし、アップグレードされたビューを所定の場所にバインド マウントします。権限のダウングレードは、常にアプリの強制終了を発生させることに注意してください。

この機能を実装するために使用される setns() 関数は Linux 3.8 以上を必要としますが、パッチは Linux 3.4 に問題なくバックポートされています。PermissionsHostTest CTS テストを使用すると、カーネル動作が正常かどうかを確認できます。