2013 年 11 月 8 日

アンドロイドのSDカードパスの取得方法

3074-logo

今回は、アンドロイドの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を調べてみてはいかがでしょうか。