戌印-INUJIRUSHI- (Androidあれこれ)

Androidのプログラミングをメインにしてます。記事に貼られたソースコードはダブルクリックすることで行番号をはずしてコピーすることができます。

 
1
2
3
4
5
6
8
9
11
12
13
14
15
16
18
19
20
22
23
28
29
30
11

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

外部ストレージのパスを取得する(Android 2.2~?)

【関連記事】外部SDカードについてまとめるまえのメモ

Androidでは、ストレージ(SDカードなど)のパスを取得するために Environment.getExternalStorageDirectory() が用意されています。
しかし、ストレージが内部ストレージ(取外不可)と外部ストレージ(取外可能)に別れている場合、内部ストレージを取得します。

外部ストレージを取得する Android API は用意されていません。
そこで開発者は色々な方法を使って、外部ストレージのパスを取得しています。

で、私も色々と試しました。こんな感じに。

×環境変数に登録されているパスを取得する
 ⇒ 環境変数がバラバラ。そもそもHTC端末など、一部の端末は登録されていない。
×環境変数と、一部特殊なパスは直書きで対応する
 ⇒ 種類が多すぎて対応しきれない
×シンボリックリンク参照
 ⇒ 設定されていないデバイスがある(そもそもこんなのに期待しては駄目…)
△マウントポイントから取得する(/proc/mounts)
 ⇒ マウントされていないと表示されない
△システムの設定ファイルから取得する(/system/etc/vold/fstab)
 ⇒ Android2.2 (API 8 FROYO)以降からだが対応できそう(HTC J ISW13HT でのみ確認)
 ⇒ (2013/03/02) GalaxyNexus や一部のカスタムROMには存在しないため△にしました…

/system/etc/vold.fstab については、過去記事の『Android のファイルシステム設定ファイル(Android 2.2~?)』を見てください。

この /system/etc/vold.fstab を使ったファイルパスの取得方法は以下のとおり。
------------------------------------------------------------
2013/01/06 追記
Xperia VL SOL21 の場合、内部ストレージが fuse_mount に定義されているらしいので修正しました。
参考:hiroyuki_tの日記 - Androidで外部ストレージのパスを取得する方法
------------------------------------------------------------
/**
* ストレージのパスを取得する。
* ストレージがマウントされていなくてもパスを返します。
* ※ /system/etc/vold.fstab を参照しているため、Android 2.1 (API 7)以下の場合
* {@link java.io.FileNotFoundException} が発生する恐れがある。
*
* @return ストレージのパス一覧
*/
private List<String> getStoragePaths() {
List<String> mountList = new ArrayList<String>();

Scanner scanner = null;
try {
// マウント情報を取得する
scanner = new Scanner(new FileInputStream(new File(
"/system/etc/vold.fstab")));
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
if (line.startsWith("dev_mount") || line.startsWith("fuse_mount")) {
// dev_mount または fuse_mount のパスを登録する(同じパスは登録しない)
String path = line.replaceAll("\t", " ").split(" ")[2];
if (!mountList.contains(path))
mountList.add(path);
}
}
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} finally {
if (scanner != null) {
scanner.close();
}
}

return mountList;
}
Android 2.1 (API 7 ECLAIR_MR1) 以下のエミュレータではファイルが存在しなかったので @TargetApi(Build.VERSION_CODES.FROYO) つけようかと思いましたが辞めておきました。

/system/etc/vold.fstab には、ストレージのパスが全て設定されている(はず)ので、Environment.getExternalStorageDirectory()のパスも含まれています。
不要であれば各自で除外してください。

除外の仕方(例)
// ストレージのパス一覧を取得する
List<String> storageList = getStoragePaths();

// 内部ストレージを除外する
storageList.remove(Environment.getExternalStorageDirectory().getPath());

// Android2.3 (API 9) 以降であれば取りはずし可能かで判断できる
// if (!Environment.isExternalStorageRemovable()) {
// storageList.remove(Environment.getExternalStorageDirectory().getPath());
// }

マウントされているか確認する場合は『デバイスにSDカードがマウントされているかチェックする(2)』で書いたメソッドを使ってチェックしてください。
// ストレージのパス一覧を取得する
List<String> storageList = getStoragePaths();

// マウントされていないパスを除外する
for (int i = 0; i < storageList.size(); i++) {
if (!isMounted(storageList.get(i)))
storageList.remove(i--);
}


ほかに /system/etc/vold.fstab を参照している人はいないかと調べてみたところ
wagic というマルチプラットフォームのカードゲームエンジンでも使われていました!(ほぼ同じことしてます)

https://code.google.com/p/wagic/source/browse/trunk/projects/mtg/Android/src/net/wagic/utils/StorageOptions.java

ゲームエンジンで使われているので信頼性は高そう!(主観)

こちらではパスに対して String#replaceAll(":.*$", "") しています。
必要なデバイスがあるということでしょうか…
とりあえずは無しで置いておきます。
スポンサーサイト

Android のファイルシステム設定ファイル(Android 2.2~?)

SDカードのマウント先について色々調べたところ、/system/etc/vold.fstab に書かれていることがわかった。

fstab は、OS起動時にファイルシステムをマウントするなど、デバイスファイルとマウントポイントなどを設定します。
【参照】UNIX Life - fstabの設定 より

android の vold.fstab は形式も違うがやってることは同じ…はず…
vold.fstab の形式は以下のようになっています。
----------------------------------------------------------------------
※ GALAXY Tab 7.0 Plus SC-02D のコメントより抜粋
dev_mount [label] [root_mount_point] [part] [subsystem] [sysfs_path1...]

label:Label for the volume
root_mount_point:In case of 'tree' style mount, we have to point root mount point to generate 'tree' dynamicaly
mount_point:Where the volume will be mounted, full mount_point path is 'root_mount_point/label'
part:Partition # (1 based), or 'auto' for first usable partition.
subsystem:Hardware level. E.g. "sd"/"usb"...
sysfs_path:List of sysfs paths to source devices
----------------------------------------------------------------------

この /system/etc/vold.fstab はエミュレータ上で確認したところ Android2.2 (API 8) から導入されているようです。
Android2.1 (API 7) 以下は /system/etc/vold.conf で形式も違います。
(もうAndroid2.1以下は切り捨てていいですよね…)

HTC JISW13HT では以下のように設定されています。
isw13ht_vold_fstab.png
dev_mount sdcard /mnt/sdcard emmc /devices/platform/msm_sdcc.1/mmc_host
dev_mount sdcard2 /mnt/sdcard/ext_sd auto /devices/platform/msm_sdcc.3/mmc_host

半角スペース区切りで3番目に設定されているパスがマウント先になります。

ここで GALAXY Tab 7.0 Plus SC-02D を見てみると…
dev_mount SdCard /mnt/sdcard/extStorages /mnt/sdcard/extStorages/SdCard auto sd /devices/platform/s3c-sdhci.2/mmc_host/mmc1
dev_mount sda /mnt/sdcard/extStorages /mnt/sdcard/extStorages/UsbDriveA auto usb /devices/platform/s5p-ehci
dev_mount sdb /mnt/sdcard/extStorages /mnt/sdcard/extStorages/UsbDriveB auto usb /devices/platform/s5p-ehci
dev_mount sdc /mnt/sdcard/extStorages /mnt/sdcard/extStorages/UsbDriveC auto usb /devices/platform/s5p-ehci
dev_mount sdd /mnt/sdcard/extStorages /mnt/sdcard/extStorages/UsbDriveD auto usb /devices/platform/s5p-ehci
dev_mount sde /mnt/sdcard/extStorages /mnt/sdcard/extStorages/UsbDriveE auto usb /devices/platform/s5p-ehci
dev_mount sdf /mnt/sdcard/extStorages /mnt/sdcard/extStorages/UsbDriveF auto usb /devices/platform/s5p-ehci
dev_mount sdg /mnt/sdcard/extStorages /mnt/sdcard/extStorages/UsbDriveG auto usb /devices/platform/s5p-ehci
dev_mount sdh /mnt/sdcard/extStorages /mnt/sdcard/extStorages/UsbDriveH auto usb /devices/platform/s5p-ehci
dev_mount sdi /mnt/sdcard/extStorages /mnt/sdcard/extStorages/UsbDriveI auto usb /devices/platform/s5p-ehci
dev_mount sdj /mnt/sdcard/extStorages /mnt/sdcard/extStorages/UsbDriveJ auto usb /devices/platform/s5p-ehci
dev_mount sdk /mnt/sdcard/extStorages /mnt/sdcard/extStorages/UsbDriveK auto usb /devices/platform/s5p-ehci
dev_mount sdl /mnt/sdcard/extStorages /mnt/sdcard/extStorages/UsbDriveL auto usb /devices/platform/s5p-ehci
dev_mount sdm /mnt/sdcard/extStorages /mnt/sdcard/extStorages/UsbDriveM auto usb /devices/platform/s5p-ehci
dev_mount sdn /mnt/sdcard/extStorages /mnt/sdcard/extStorages/UsbDriveN auto usb /devices/platform/s5p-ehci
dev_mount sdo /mnt/sdcard/extStorages /mnt/sdcard/extStorages/UsbDriveO auto usb /devices/platform/s5p-ehci
dev_mount sdp /mnt/sdcard/extStorages /mnt/sdcard/extStorages/UsbDriveP auto usb /devices/platform/s5p-ehci
dev_mount sdq /mnt/sdcard/extStorages /mnt/sdcard/extStorages/UsbDriveQ auto usb /devices/platform/s5p-ehci
dev_mount sdr /mnt/sdcard/extStorages /mnt/sdcard/extStorages/UsbDriveR auto usb /devices/platform/s5p-ehci
dev_mount sds /mnt/sdcard/extStorages /mnt/sdcard/extStorages/UsbDriveS auto usb /devices/platform/s5p-ehci
dev_mount sdt /mnt/sdcard/extStorages /mnt/sdcard/extStorages/UsbDriveT auto usb /devices/platform/s5p-ehci
dev_mount sdu /mnt/sdcard/extStorages /mnt/sdcard/extStorages/UsbDriveU auto usb /devices/platform/s5p-ehci
dev_mount sdv /mnt/sdcard/extStorages /mnt/sdcard/extStorages/UsbDriveV auto usb /devices/platform/s5p-ehci
dev_mount sdw /mnt/sdcard/extStorages /mnt/sdcard/extStorages/UsbDriveW auto usb /devices/platform/s5p-ehci
dev_mount sdx /mnt/sdcard/extStorages /mnt/sdcard/extStorages/UsbDriveX auto usb /devices/platform/s5p-ehci
dev_mount sdy /mnt/sdcard/extStorages /mnt/sdcard/extStorages/UsbDriveY auto usb /devices/platform/s5p-ehci
dev_mount sdz /mnt/sdcard/extStorages /mnt/sdcard/extStorages/UsbDriveZ auto usb /devices/platform/s5p-ehci

USBストレージらしきモノが設定されているが、3番目のパスはすべて一緒。
う、うーん…?

デバイスにSDカードがマウントされているかチェックする(2)

以前書いた『デバイスにSDカードがマウントされているかチェックする』で
SDカードのマウント状態を確認にはLinuxのmountコマンドを使うと書きました。

Linuxのコマンドを直接使うのに抵抗があったので調べてみたところ /proc/mounts でシステムが使用中のマウント一覧が取得できるみたい。
※ 取得できる情報は Runtime.getRuntime().exec(String prog) で mount を実行したときと同じです

/proc/mounts については Red Hat Enterprise Linux 4: システム管理入門ガイド などを見てください。

で、せっかく調べたので /proc/mounts を使った場合のマウントチェックを作りました。
結果は変わりませんが、コードは若干短くなります。
/**
* 指定されたパスがマウントされているかチェックする。
* USB接続で外部ストレージモードにしている場合などにはマウント扱いされずに false を返します。
*
* @param path
* マウントされているかチェックするパス
* @return true:マウントされている、false:マウントされていない
*/
public static boolean isMounted(String path) {
boolean isMounted = false;

Scanner scanner = null;
try {
// マウントポイントを取得する
File file = new File("/proc/mounts");
scanner = new Scanner(new FileInputStream(file));

// マウントポイントに該当するパスがあるかチェックする
while (scanner.hasNextLine()) {
if (scanner.nextLine().contains(path)) {
// 該当するパスがあるのでマウントされている
isMounted = true;
break;
}
}
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} finally {
if (scanner != null) {
scanner.close();
}
}

// マウント状態を返します
return isMounted;
}

HTC J ISW13HTのSDカードへのシンボリックリンク

HTC J ISW13HT をPCに繋げてみたところDDMSパースペクティブにSDカードのシンボリックリンクが表示されていた。

isw13ht_DDMS_sdcard.png
内蔵ストレージ: /sdcard -> /mnt/sdcard
外部ストレージ: /sdcard2 -> /mnt/sdcard/ext_sd


このうち、sdcardはエミュレータにも表示されているので標準のシンボリックリンクだと思われる。

問題は sdcard2 の方。
内蔵ストレージと外部ストレージに分かれている場合、この名称でシンボリックリンクが貼られているのかどうか。
残念ながら手元には HTC J ISW13HT しかないため確認できません。
別名であれ、必ずストレージのシンボリックリンクが貼られているのであれば外部ストレージのパス問題も解決するのだが…。
(2012/11/26 追記)
GALAXY Tab 7.0 Plus SC-02D には設定されていませんでした。
うん、設定されてないのはあるって思ってた…


なお、シンボリックリンクからリンク先のパスを取得するには File#getCanonicalPath() を使うことで取得できる。
File sdcard2 = new File("/sdcard2");
if (sdcard2.exists()) {
// File#getPath() は指定されたパスを取得する → /sdcard2
Log.d("File#getPath()", sdcard2.getPath());
// File#getCanonicalPath() は正規パスを取得する → /mnt/sdcard/ext_sd
Log.d("File#getCanonicalPath()", sdcard2.getCanonicalPath());
}

JSSEC セキュアコーディングガイド

一般社団法人日本スマートフォンセキュリティ協会(JSSEC)主催の
スマートフォン セキュリティ シンポジウム2012
『みんなでスマホが安全に使える世界へ!』

へ行ってきました。
会員ではないので3,000円払っての一般参加です。

シンポジウムに参加したことで、協会の成果物である以下の冊子をいただきました。
・Android アプリのセキュア設計・セキュアコーディングガイド【2012年11月1日版】
・スマートフォン&タブレットの業務利用に関するセキュリティガイドライン【第一版(BYOD基礎資料追加版】


この冊子のPDFファイル、および、サンプルコードは
JSSECのホームページにある『活動内容 Activities』から無料でダウンロードできます

セキュアコーディングガイドには、アプリで忘れがちなセキュリティの設定などを、サンプルコードを交えて詳細に書かれています。
まだ読まれていない方は読むことをお勧めします!
307ページもあるので読み応えバッチリです!

と、シンポジウムに参加しました、と最初に報告しましたがタイトルにあるように今回の記事はセキュアコーディングガイドの紹介なのでシンポジウムの内容はなしです!

電子書籍が騒がれる昨今、1ページ、2ページの文章ならともかく、こういう分厚いのは紙媒体じゃないと読めない管理人でした(実は冊子が一番の目的で参加した)

一般社団法人日本スマートフォンセキュリティ協会(JSSEC)
http://www.jssec.org/
プロフィール

とむ・やむくん

Author:とむ・やむくん
管理人について

Windows 7 / 64bit
Eclipse 4.2 Juno (日本語パッチ済)

スポンサーサイト
最新トラックバック
検索フォーム
ブロとも申請フォーム
QRコード
QR
Twitter
2013/01/04 19:00 カウント開始

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。