読者です 読者をやめる 読者になる 読者になる

sandbox

Scala, Android, Architecture, Management, Service Design あたりを主戦場としております

Activity がシステムによって kill される状態をシミュレートする方法

Android で、メモリが逼迫した状況下特有の不具合に遭遇し、そのデバッグ方法が分からなかったので調べてみた。
まず、メモリが逼迫した状態でどの様な事が起こるかというと、公式のドキュメントに下記の様な記載がある。

if the system must recover memory in an emergency, then onStop() and onDestroy() might not be called. Therefore, you should use onPause() to write crucial persistent data (such as user edits) to storage.


つまり、システムがどうしてもメモリを必要とする時には、既にスタックに詰まれている Activity が onStop や onDestory の呼び出しなしにプロセスが kill される事がある。
この状況を端末操作によって再現しようと思うとかなり困難だが、adb を使えばごく簡単に再現できた。(というか良く考えれば真っ当な手順)

  1. 対象の Activity を起動する
  2. Home ボタンで Activity を pause 状態にする
  3. adb kill の実行、または DDMS で対象のプロセスを選択し、STOP アイコンをクリックする


上記により、Activity が onDestory *1呼び出しなしに kill され、次回は onCreate から起動する流れをシミュレートできる。
一連の流れを logcat で見てみるとこんな感じ。

// 初回の起動
11-15 13:26:48.066: I/ActivityManager(278): Starting activity: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=me.tlync/.SampleActivity bnds=[186,543][294,688] }
11-15 13:26:48.166: I/ActivityManager(278): Start proc me.tlync for activity me.tlync/.SampleActivity: pid=14981 uid=10085 gids={}
11-15 13:26:48.266: D/SampleActivity(14981): [ENTER] onCreate
11-15 13:26:48.266: D/SampleActivity(14981): [ENTER] onStart
11-15 13:26:48.266: D/SampleActivity(14981): [ENTER] onResume

// Home ボタンで pause
11-15 13:26:58.016: I/ActivityManager(278): Starting activity: Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10200000 cmp=com.android.launcher2/.Launcher }
11-15 13:26:58.136: D/SampleActivity(14981): [ENTER] onSaveInstanceState
11-15 13:26:58.136: D/SampleActivity(14981): [ENTER] onPause

// adb kill
11-15 13:27:03.556: I/WindowManager(278): WIN DEATH: Window{460a9978 me.tlync/me.tlync.SampleActivity paused=false}
11-15 13:27:03.556: I/ActivityManager(278): Process me.tlync (pid 14981) has died.
11-15 13:27:06.356: I/ActivityManager(278): Starting activity: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=me.tlync/.SampleActivity bnds=[186,543][294,688] }
11-15 13:27:06.416: I/ActivityManager(278): Start proc me.tlync for activity me.tlync/.SampleActivity: pid=15006 uid=10085 gids={}

// 再度の起動
11-15 13:27:06.516: D/SampleActivity(15006): [ENTER] onCreate
11-15 13:27:06.526: D/SampleActivity(15006): [ENTER] onStart
11-15 13:27:06.526: D/SampleActivity(15006): [ENTER] onRestoreInstanceState // 通常のライフサイクルでは呼ばれない onRestoreInsntanceState が呼ばれる
11-15 13:27:06.526: D/SampleActivity(15006): [ENTER] onResume


自身のケースでは単なる onCreate 時の不具合であったが、他にも何故かリリース後(他のアプリが頻繁に利用されメモリが逼迫されやすい状況)に Activity まわりで問題が発生するケースの再現や、普通に操作してもまず呼ぶ事ができない onRestoreInstanceState をテストしたい場合にも使える。

*1:"onStop() and onDestroy() might not be called" とあるが onStop は呼ばれた