Android ANR (Application Not Responding) を検出するシンプルなウォッチドッグ。
現時点では、Android アプリケーションが ANR エラーをキャッチして報告する方法はありません。
アプリケーションが Play ストアにない場合 (開発中であるか、別の方法で配布しているため)、ANR を調査する唯一の方法は、ファイル /data/anr/traces.txt をプルすることです。
さらに、Play ストアの使用は、独自のバグ追跡サービスを選択できるほど効果的ではないことがわかりました。
Android のバグ トラッカーに、この欠落を説明する問題エントリがあります。自由にスターを付けてください ;)
UI スレッドが応答を停止したときを検出する「ウォッチドッグ」タイマーを設定します。実行すると、すべてのスレッドのスタック トレース (メインが最初) でエラーが発生します。
はい!ご質問いただいてうれしいです。それがそもそも開発された理由です。
これによりエラーがスローされると、クラッシュ ハンドラーがそれをインターセプトし、必要な方法で処理できます。
既知の機能するクラッシュ レポーターには次のものがあります。
setReportMainThreadOnly()
を使用した場合のみ)また、これが[お気に入りのクラッシュ レポート システムをここに挿入]で動作しない理由はありません。
ウォッチドッグは、ループ内で次の処理を実行する単純なスレッドです。
app/build.gradle
ファイルに以下を追加します。
implementation 'com.github.anrwatchdog:anrwatchdog:1.4.0'
アプリケーション クラスのonCreate
に次を追加します。
new ANRWatchDog (). start ();
最新のjarをダウンロードする
jar をプロジェクトのlibs/
ディレクトリに置きます
ANRError
スタック トレースは少し特殊で、アプリケーション内で実行されているすべてのスレッドのスタック トレースが含まれます。したがって、レポートでは、セクションcaused by
、先行する例外の原因ではなく、別のスレッドのスタック トレースです。
デッドロックの例を次に示します。
FATAL EXCEPTION: |ANR-WatchDog|
Process: anrwatchdog.github.com.testapp, PID: 26737
com.github.anrwatchdog.ANRError: Application Not Responding
Caused by: com.github.anrwatchdog.ANRError$_$_Thread: main (state = WAITING)
at testapp.MainActivity$1.run(MainActivity.java:46)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
Caused by: com.github.anrwatchdog.ANRError$_$_Thread: APP: Locker (state = TIMED_WAITING)
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:1031)
at java.lang.Thread.sleep(Thread.java:985)
at testapp.MainActivity.SleepAMinute(MainActivity.java:18)
at testapp.MainActivity.access$100(MainActivity.java:12)
at testapp.MainActivity$LockerThread.run(MainActivity.java:36)
このレポートから、2 つのスレッドのスタック トレースが確認できます。最初のスレッド (「メイン」スレッド) はMainActivity.java:46
でスタックし、2 番目のスレッド (「App: Locker」という名前) はMainActivity.java:18
でスリープ状態にロックされます。
そこから、この 2 行を見れば、デッドロックの原因がきっとわかるはずです。
一部のクラッシュ レポート ライブラリ (Crashlytics など) は、キャッチされなかった例外の時点ですべてのスレッド スタック トレースをレポートすることに注意してください。その場合、すべてのスレッドを同じ例外に含めるのは面倒になる可能性があります。そのような場合は、単にsetReportMainThreadOnly()
使用してください。
別のタイムアウトを設定するには (デフォルトは 5000 ミリ):
if ( BuildConfig . DEBUG == false ) {
new ANRWatchDog ( 10000 /*timeout*/ ). start ();
}
デフォルトでは、デバッガーがアタッチされている場合、またはアプリがデバッガーのアタッチを待機している場合、ウォッチドッグは ANR を無視します。これは、実行の一時停止とブレークポイントを ANR として検出するためです。これを無効にして、デバッガーが接続されている場合でもANRError
をスローするには、 setIgnoreDebugger(true)
を追加します。
new ANRWatchDog (). setIgnoreDebugger ( true ). start ();
ANR が検出されたときにアプリケーションをクラッシュさせたくない場合は、代わりにコールバックを有効にすることができます。
new ANRWatchDog (). setANRListener ( new ANRWatchDog . ANRListener () {
@ Override
public void onAppNotResponding ( ANRError error ) {
// Handle the error. For example, log it to HockeyApp:
ExceptionHandler . saveException ( error , new CrashManager ());
}
}). start ();
これは、実稼働環境でアプリを配信する場合に非常に重要です。最終ユーザーの手に渡った場合は、5 秒後にクラッシュせず、使用しているレポート システムに ANR を報告する方がよいでしょう。おそらく、さらに数秒後にアプリが「フリーズ解除」されるでしょう。
すべてのスレッド ( FinalizerDaemon
スレッドなどのシステム スレッドを含む) ではなく、独自のスレッドのみを ANRError で報告したい場合は、プレフィックスを設定できます。名前がこのプレフィックスで始まるスレッドのみが報告されます。 。
new ANRWatchDog (). setReportThreadNamePrefix ( "APP:" ). start ();
次に、スレッドを開始するときに、その名前をこのプレフィックスで始まる名前に設定することを忘れないでください (スレッドを報告したい場合)。
public class MyAmazingThread extends Thread {
@ Override
public void run () {
setName ( "APP: Amazing!" );
/* ... do amazing things ... */
}
}
他のすべてのスレッドではなく、メイン スレッドのスタック トレースのみを取得したい場合は、次のようにすることができます。
new ANRWatchDog (). setReportMainThreadOnly (). start ();
場合によっては、アプリケーションが一定期間フリーズしたことを知りたいが、まだ ANR エラーを報告したくない場合があります。エラーを報告する前に呼び出されるインターセプターを定義できます。インターセプターの役割は、指定されたフリーズ期間を考慮して、ANR エラーを発生させるか延期するかを定義することです。
new ANRWatchDog ( 2000 ). setANRInterceptor ( new ANRWatchDog . ANRInterceptor () {
@ Override
public long intercept ( long duration ) {
long ret = 5000 - duration ;
if ( ret > 0 ) {
Log . w ( TAG , "Intercepted ANR that is too short (" + duration + " ms), postponing for " + ret + " ms." );
}
return ret ;
}
})
この例では、ANRWatchDog は 2000 ミリ秒のタイムアウトで開始されますが、インターセプターは少なくとも 5000 ミリ秒のフリーズに達するまでエラーを延期します。
ANRWatchDog はスレッドなので、いつでも中断できます。
Android のマルチプロセス機能 (新しいプロセスでアクティビティを開始するなど) を使用してプログラミングしている場合は、プロセスごとに ANRWatchDog スレッドが必要になることに注意してください。
ANR-Watchdog は、非営利目的でも商用目的でも無料で使用でき、今後も無料で使用できます。
私の仕事に何らかの支援や感謝を示したい場合は、自由に寄付してください。
これは (もちろん) 非常にありがたいことですが、ヘルプやサポートを受ける必要はまったくありません。喜んで無料で提供させていただきます :)