今回は、アンドロイドのSDカードパスの取得方法をご紹介します。一般的には、Environment.getExternalStorageDirectory()を利用すれば取得できるだろうと考えがちですが、実はSDカードのパスとは限りません。Externalという言葉が外部とかSDカードを連想しがちですが、どちらかというと拡張と考えると理解しやすいです。
KitKatの詳細が公開されましたが、SDカードに関する扱いはまた異なってくるかもしれません。KitKatが早急に広まることで、Gingerbread対応(2.3)をしなくてよくなれば、本当に助かるのですが、各ベンダーごとの実装が存在するので、そう簡単にはいかないでしょう。
通常、SDカードのマウントパスを取得するには、Environment.getExternalStorageDirectory()を使うことになっています。sdcardという文字列をハードコーディングすれば、Eclipseもこんなことを言ってきます(笑)。
Do not hardcode "/sdcard/"; use Environment.getExternalStorageDirectory().getPath()
しかし、このメソッドで取得できるのは、SDカードのパスとは限らず、機種により(通常のパーティションとは異なるところにマウントされた)内部ストレージのパスを返すものもあります。
ですから、私はgetExternalStorageDirectoryのExternalを外部と訳さず、拡張と訳すことにしています。(内部の)拡張ストレージとSDカードを持ついくつかの機種で確認したところ、これが返すパス名にsdcardというような文字列を含むので混乱します。
本当のSDカードパスを取得するには、どうすればよいのでしょうか?実は今のところ、そのようなAPIは存在しません。
では、SDカードを扱う多くのアンドロイドアプリはどうしているのかというと、恐らくLinuxのシステムファイルを参照しているのだろうと考えられます。
/system/etc/vold.fstabをスキャン
Linuxでは、マウント可能な外部ストレージは、/system/etc/vold.fstabに記述されています。以下はEM01F(Arrows OS4.1)の例です(sdcardの行のみ)。
$ adb shell cat /system/etc/vold.fstab dev_mount sdcard /storage/sdcard0/external_sd auto /devices/platform/msm_sdcc.3/mmc_host
EM01Fの場合は、getExternalStorageDirectoryは/storage/sdcard0になっています。vold.fstabのパスとは少し異なります。
SDカードパスの取得方法においては、環境変数から取得すればよいという情報もあります。確かにEXTERNAL_SD_STORAGEにはSDカードのマウントパスらしきものが設定されていて、合致します。しかし、環境変数名は機種毎に異なると予想されるため、当てにはならないです。
$ adb shell printenv EXTERNAL_SD_STORAGE=/storage/sdcard0/external_sd
やはり、vold.fstabをスキャンするのが確実です。しかし、これではまだ不完全です。パスがわかっても、実際マウントされているかどうかがわかりません。
/proc/mountsをスキャン
上記の方法で得たSDカードがマウントされているかどうかは、/proc/mountsをスキャンすることでわかります(またはmountコマンドの出力でも可)。SDカードを挿入した状態で/proc/mountsをスキャンすると、確かにマウントされています。
$ adb shell cat /proc/mounts tmpfs /storage/sdcard0/external_sd/.android_secure tmpfs ro,relatime,size=0k,mode=000 0 0
SDカードを外して、/proc/mountsをスキャンすると、この行は表示されませんので、これでSDカードパスとマウントの確認が可能となりました。
まだ落とし穴がある
しかし、機種によってはvold.fstabに以下のように設定されているものありました。これでは、どちらが本当のsdcardのパスなのか判断できません(プログラムで判断できるかどうかという意味)。正解はexternal_sdが付いている方なのですが、他の機種でもそうなのか不明です。
dev_mount sdcard /storage/sdcard0 on off 0602 off 32 /devices/platform/msm_sdcc.1/mmc_host nonremovable,encryptable dev_mount ext_sdcard /storage/sdcard0/external_sd off on 0602 off auto /devices/platform/msm_sdcc.3/mmc_host
結論
アンドロイドのSDカードパスとマウントの有無は、/system/etc/vold.fstabと/proc/mountsをスキャンするのがベストだが、上記の問題があるので、/proc/mountsのみに着目し、.android_secureをパスの含むパスをSDカードパスとし、この行があれば、マウントされていると判断するというのが、実践的な解決方法ではないかと考えています。
今のところ、私が調べた機種ではこの方法で問題なさそうですが、全ての機種を調べたわけではないので、例外があるのかもしれません。皆さんも手持ちのアンドロイドの/system/etc/vold.fstabと/proc/mountsを調べてみてはいかがでしょうか。