序文
ANR は Application No Response の略で、プログラムは応答しません。Android システムは ANR メカニズムを使用して設計されており、その目的は、対話するコンポーネント (アクティビティなど) とユーザー対話 (InputEvent) のタイムアウトを監視することです。これにより、アプリケーション プロセス (メイン スレッド) がスタックしているか、または応答が遅すぎるかどうかを判断できます。
ANR の問題は、クラッシュに比べて原因が複雑で特定が困難です。この記事には主に次の内容が含まれています
- ANR ワークフロー
- ANRを監視するにはどうすればよいですか?
- ANR の原因を特定するにはどうすればよいですか?
ANR ワークフロー
ANR がトリガーされる場合は数多くありますが、通常は次の側面に分類できます。
基本原理は実際には WatchDog の考え方で、送信されたイベントが一定期間内に消費されない場合、ANR がトリガーされます。
以下の図に示すように、ここでは全体的なプロセスについて説明します。
- ANR が発生すると、システムは大量のプロセス データを収集し、スタック ダンプを実行して ANR トレース ファイルを生成します。このうち、最初に収集するプロセスは、ANR が発生したプロセスである必要があります。
- システムはこれらのアプリケーション プロセスに SIGQUIT シグナルを送信し、これらのアプリケーション プロセスはシグナルの受信後にスタック ダンプの実行を開始します。
- アプリケーション プロセスのダンプ スタックが成功すると、ソケットを通じてシステム プロセスと通信し、トレース ファイルを書き込みます。
- トレース ファイルが書き込まれた後、ANR が発生したプロセスがフォアグラウンド プロセスの場合はダイアログがポップアップ表示され、そうでない場合はプロセスが直接強制終了されます。
ANRを監視するにはどうすればよいですか?
ANR のワークフローを理解した後、ANR の発生をどのように監視できるでしょうか?
ANR WatchDog 検出のアイデア
ANRの原因は入力が一定時間応答しないことなので、当然メインスレッドにタスクを送信することを考えますが、一定時間内に実行されなければANRが発生していると考えられます。 。
このアイデアには主に次の問題があります。
- 不正確なタイムアウト条件は、必ずしも ANR を引き起こすとは限りません。たとえば、5 秒のタイムアウトは、TouchEvent が消費されない場合に ANR が発生する条件の 1 つにすぎず、他の条件は必ずしも 5 秒であるとは限りません。
- 検出漏れ:タイムアウトを5秒に設定した場合、TouchEventのANR検出時に一定の確率で検出漏れ(周期が同期していない)が発生します。
ANR信号モニタリングのアイデア
上記の全体的な ANR プロセスを紹介したときに、ANR が発生すると SIGQUIT 信号が送信されることに気づきましたが、この信号をリッスンすることで ANR モニタリングを実装できないでしょうか? 実際、XCrash と Matrix はどちらもこの方法で ANR モニタリングを実装しています。
SignalCatcher
ここで、デフォルトでは、プロセスはSIGQUIT
シグナルをリッスンすることによってスタック ダンプを実行し、ANR トレース ファイルを生成することに注意してください。したがって、SIGQUIT
信号を監視した後、再度SignalCatcher
送信する必要があります。SIGQUIT
SIGQUIT シグナルを SignalCatcher に再送信する手順がない場合、Android システム管理サービス (AMS) は、ANR プロセスがスタック情報を書き込むまで待機します。20 秒のタイムアウト期間を超えるまで、AMS は強制的に中断され、後続のプロセスを続行します。これにより、ANR ポップアップ ウィンドウの表示が非常に遅くなり (タイムアウトが 20 秒であるため)、完全な ANR トレース ファイルを /data/anr ディレクトリに生成できなくなります。
誤検知の処理
SIGQUIT 信号を監視している場合、ANR が発生するとは限りません。
Matrix のドキュメントでは、誤検知の 2 つのケースについて言及しています。
- たとえば、別のプロセスに ANR があり、ANR が発生したプロセスがスタック ダンプを必要とする唯一のプロセスではない可能性があります。システムは他の多くのプロセスのスタック ダンプを収集し、それらを使用して ANR トレース ファイルを生成します。
- シグナルはメーカーまたは開発者自身によって送信されますが
SIGQUIT
、SIGQUIT シグナルの送信は実際には非常に簡単です。
したがって、シグナルをリッスンするときに別のチェックを実行する必要があります。ANR ポップアップ ウィンドウの前に、ANR が発生したプロセスには NOT_RESPONDING フラグが付けられます。このフラグは、ActivityManager を通じて取得できます。
private static boolean checkErrorState() {
try {
Application application = sApplication == null ? Matrix.with().getApplication() : sApplication;
ActivityManager am = (ActivityManager) application.getSystemService(Context.ACTIVITY_SERVICE);