非root端末でパケットキャプチャが可能な tPacketCapture/tPacketCapture Pro がAndroid4.4(KitKat)に対応しました(アプリver. 1.6)。
今回はAndroid4.4に対応する上で、修正の必要があったメディアスキャンの方法などについてまとめてみます。

packetcapture_icon.png

その前に、そもそもtPacketCaptureって??

tPacketCaptureとはAndroid OS 4.0(Ice Cream Sandwich)から提供されているVpnServiceを利用して端末の通信内容をキャプチャするアプリです。既存のパケットキャプチャアプリでは必須とされていたroot権限を取得していない端末であっても通信データをキャプチャすることが可能です。
キャプチャデータ(pcapファイル)はSDカードまたは同等の外部記憶装置に保存されます。

対応前の問題点

今回の対応を行う前は、キャプチャ終了時にアプリケーションがクラッシュしてしまう問題がありました(´・ω・`)
これは、キャプチャ終了時に外部記憶装置のメディアスキャンを行なっており、そのメディアスキャンの方法がAndroid 4.4から使用できなくなったことが原因でした。

以下に、なぜメディアスキャンが必要なのか、Android端末をPCに繋いだ際の外部記憶装置の表示のされ方、どのように修正したのかを順に説明します。少し説明が長くなるので、最終的な修正方法だけ知りたい場合は途中を読み飛ばして最後の「正しいメディアスキャン方法」をご確認くださいΣ(゚Д゚)!!

なぜメディアスキャンが必要なのか

tPacketCaptureはキャプチャデータ(pcapファイル)を以下のディレクトリ内に保存します。
保存したファイルは端末とPCをUSBケーブルで接続し、PCにコピーして利用することを想定しています。(その他、ファイルをDropBoxやGmailに共有することも可能です)

[外部記憶装置のルート]/Android/data/jp.co.taosoftware.android.packetcapture/files

本来、上記ディレクトリにアプリからファイルを保存したうえで、端末とPCをUSBケーブルで接続すればエクスプローラなどでファイルを表示することができるはずです。しかしながら、特定の状況ではファイルが正しく表示されない場合があります。それは、外部記憶装置がSDカードではなく、端末内蔵ストレージを外部記憶装置としている場合です。(端末内なのに、外部ってわかりづらい。。汗)特に最近のAndroid端末ではSDカードを使用せずに、端末内蔵ストレージを外部記憶装置としている端末が多くなっています。

では、なぜ正しくファイルが表示されなくなるのでしょうか?
それは、SDカードを使用する端末とそうでない端末でPCに接続した際に、ファイルシステムの管理方法が異なることが原因です。

SDカードの場合、端末をPCと接続するとSDカードの内容はPC側で管理されます。
一方、端末内部ストレージを外部記憶装置とする場合は端末側で表示内容を管理します。その際、MTP(Media Transfer Protocol)という仕組みを利用します。

MTPを利用する場合、エクスプローラから見えるファイルの有無は、そのファイルがコンテントプロバイダに登録されているかどうかによって判断されます。このコンテントプロバイダはAndroidシステムによって管理されています。

メディアスキャン

Androidでは端末再起動時や、外部記憶装置がマウントされた時などにシステムが自動的に外部記憶装置をスキャンして結果をコンテントプロバイダに登録します。任意のタイミングで登録するには、アプリ自身でコンテントプロバイダに登録する操作が必要です。

誤ったメディアスキャン方法

Android4.4以前では、アプリからIntent.ACTION_MEDIA_MOUNTEDというアクションをブロードキャストすることで、擬似的に「外部記憶装置がマウントされた」ことを再現して、システムが自動的にメディアスキャンを走らせるように仕向けることができました。tPacketCaptureでもこの仕組を利用してメディアスキャンを行なっていました。

sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory()));

Android 4.4では Intent.ACTION_MEDIA_MOUNTED がprotected-broadcastに変更され、Intent.ACTION_MEDIA_MOUNTED をブロードキャストできるのはシステムアプリのみになりました。この変更はframeworks/base/core/res/AndroidManifest.xmlで確認することが出来ます。
Android 4.4以降の端末で一般アプリから上記インテントをブロードキャストするとSecurityExceptionが発生しアプリがクラッシュします。まぁ本来アプリから発行すべきでないインテントなのでAndroid4.4での修正は正しいものであり、上記方法を利用しているアプリは修正が必要です。

正しいメディアスキャン方法

スキャン方法というよりは、メディアの登録方法という形になりますが、コンテントプロバイダにファイルを登録するには以下の方法を使用します(APIレベル8以降)。この方法ではMediaScannerConnection#scanFile()メソッドを利用してコンテントプロバイダにファイルを登録します。詳しい説明などは既にTechBoosterの記事で紹介されているのでそちらを参照してもらうのが良いと思います。

String[] filePath = new String{"外部記憶装置/Android/data/jp.co.taosoftware.android.packetcapture/files/xxx.pcap"};
String[] mimeType = new String{"*/*"};
MediaScannerConnection.scanFile(getActivity(),
filePath,
mimeType,
null);

まとめ

今回tPacketCaptureのAndroid4.4(KitKat)対応を通して、MTP経由で正しくコンテンツを表示する方法や、使用できなくなったメディアスキャンの方法、及び正しい登録方法などをまとめました。
特に、Intent.ACTION_MEDIA_MOUNTED を使用する方法は検索結果でよく出てくるので注意してください。

アプリダウンロード

今回の記事を書くきっかけとなった、tPacketCaptureとtPacketCapture Proは以下からダンロード可能です。是非ご利用ください(゚∀゚)!!

tPacketCapture(無料)

Android app on Google Play

packetcapture_qr_code

tPacketCapture Pro(有料)

Android app on Google Play

packetcapture_pro_qr_code

ブログ内の関連する記事