Superdry Memorandom :-p

旧「superdry memorandum :-D」です

StrictModeについて

StrictModeについてandroid developer blogにあがってたので適当に訳してみたよ。


使うのは、以下の処理の場合。

  • 通信やディスク読み書きを行うThread処理
  • データ読み書きを行うSQLite処理

これら処理に時間がかかってANSsが発生するようなバグを検知して、ログにはいたりダイアログ出したりなどデバッグしやすくするモードのようです。現在SQLiteの場合はclose処理によっておこるリークのみ検知でまだ実装が十分でないです(将来拡張予定)。

ANRs*1が出たときのバグ調査って退屈だしめんどいよね。特にメソッドが複数絡んでるときとか(BinderとかContentResolverとかがServicesとかContentProviderを操作してるときなど)原因超特定しずらい。そこでStrictModeをつくったよ!

GingerBreadからはStrictModeAPIをつかえるよ。これはスレッドで実行できない処理やポリシーに違反したときの挙動を明示的にスレッドに指定できるよ。このポリシーは単純にスレッド固有の整数のビットマスクなんですよう。デフォルトではすべてが許可状態なので、明示的に指定しない限りデフォルトでは影響はないよ。

スレッドのポリシーなどで有効にできるフラグは以下の通り。

  • ディスク書き込みの検出:detectDiskWrites()
  • 読み込みディスクの検出:detectDiskReads()
  • ネットワークの使用状況の検出:detectNetwork()
  • すべて検出:detectAll()
  • ポリシー違反のときログ出力:penaltyLog()
  • ポリシー違反のときクラッシュ:penaltyDeath()
  • ポリシー違反のときDropBoxへ出力:penaltyDropbox()
  • ポリシー違反のときダイアログ表示:penaltyDialog()

StrictModeの有効にする方法はonCreate()に

public void onCreate() {
     if (DEVELOPER_MODE) {
         StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                 .detectDiskReads()
                 .detectDiskWrites()
                 .detectNetwork()
                 .penaltyLog()
                 .build());
     }
     super.onCreate();
 }

の様に実装するか、単純に以下のようにする。

public void onCreate() {
     if (DEVELOPER_MODE) {
         StrictMode.enableDefaults();
     }
     super.onCreate();
 }

Gingerbread以前(2.3以前)を対象とするなら、後者の構文で、リフレクションとかその他の方法を使う方法がまだ簡単かも。StrictMode.enableDefaults()をリフレクション使ってコールし、Gingerbread搭載の端末やエミュレータ環境で動かすとか。

penaltyLog()をつかうとadb logcatでターミナルに表示されるよ。penaltyDropbox()をつかうと以下のコマンドでdropBoxManagerへ書きだせる。

adb shell dumpsys dropbox data_app_strictmode --print

スレッドやjava.util.concurrent.*に追加してHandler, AsyncTask, AsyncQueryHandler, IntentServiceなどのようなAndroid API をチェックできるよ。

StrictModeはどんどん実装拡大中だよ!ハニカムにもいっぱいいいのを用意したいので、何かあったらStackOverFlowにStrictModeタグつけていろいろ寄せてね!まってるよう!

VMについてもスレッドと同じ感じでフックできる。

StrictMode.VmPolicy policy = new StrictMode.VmPolicy.Builder()
     .detectAll()
     .penaltyLog()
     .build();
 StrictMode.setVmPolicy(policy);

使えるメソッドは

  • SQLiteCursorとかSQLiteオブジェクトをちゃんと閉じずに終了したタイミングで検出:detectLeakedSqlLiteObjects()
  • 全て検出*2:detectAll()
  • 違反を検出したときクラッシュする:penaltyDeath()
  • 違反を検出したときDropBoxへ出力:penaltyDropBox()
  • 違反を検出したときLogへ出力:penaltyLog()

*1:Application Not Responding。アプリが応答しませんダイアログが出る。

*2:GingerBreadではSQLリーク検出だけ。将来の拡張性のために用意