1、状況の出現ANR
満たすシステムがポップANRを促すメッセージが表示されます以下の場合
入力イベント(キーとタッチイベント)5S内で処理されていません。
BroadcastReceiverイベント(onRecieve()メソッド)(60代のための10秒のためのフォアグラウンド放送、楽屋放送)を処理していない指定された時間内に、
サービスがブートを完了していない20代背景200Sをフォアグラウンド;
公開のContentProviderは()10秒以内に完了することはありません。
メインスレッドがブロックされて生じた通常の状況下で。
2. ANRの原則
(9.0コードに基づく)の例示的なプロセスの入力に応答いいえ:
AMS同じディレクトリ()メソッドのANR最終ポップアップダイアログボックスの位置とhandleShowAnrUiクラスAppErrors。このクラスは、プログラムで発生したエラーのさまざまなを処理するために使用されるだけでなく、ANRは、このクラスはまた、クラッシュプロセスを余儀なくされました。
// base/core/java/com/android/server/am/AppErrors.java
void handleShowAnrUi(Message msg) {
Dialog dialogToShow = null;
synchronized (mService) {
AppNotRespondingDialog.Data data = (AppNotRespondingDialog.Data) msg.obj;
// ...
Intent intent = new Intent("android.intent.action.ANR");
if (!mService.mProcessesReady) {
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND);
}
mService.broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
null, false, false, MY_PID, Process.SYSTEM_UID, 0 /* TODO: Verify */);
boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
if (mService.canShowErrorDialogs() || showBackground) {
dialogToShow = new AppNotRespondingDialog(mService, mContext, data);
proc.anrDialog = dialogToShow;
} else {
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR,
AppNotRespondingDialog.CANT_SHOW);
// Just kill the app if there is no dialog to be shown.
mService.killAppAtUsersRequest(proc, null);
}
}
// If we've created a crash dialog, show it without the lock held
if (dialogToShow != null) {
dialogToShow.show();
}
}
しかし、ここでANRの発生場所からの呼び出しは、クラスやメソッドの多くを通過します。ANRは、最初にInputDispatcher.cppにスローされます。私たちは、最初のトリガー場所を見つけるために、定数を定義することができます。
// native/services/inputflinger/InputDispatcher.cpp
constexpr nsecs_t DEFAULT_INPUT_DISPATCHING_TIMEOUT = 5000 * 1000000LL; // 5 sec
このクラスの位置からのアクセスの層を通過したトリガされますInputManagerService
// base/services/core/java/com/android/server/input/InputManagerService.java
private long notifyANR(InputApplicationHandle inputApplicationHandle,
InputWindowHandle inputWindowHandle, String reason) {
return mWindowManagerCallbacks.notifyANR(
inputApplicationHandle, inputWindowHandle, reason);
}
ここmWindowManagerCallbacksはInputMonitorです。
// base/services/core/java/com/android/server/wm/InputMonitor.java
public long notifyANR(InputApplicationHandle inputApplicationHandle,
InputWindowHandle inputWindowHandle, String reason) {
// ... 略
if (appWindowToken != null && appWindowToken.appToken != null) {
final AppWindowContainerController controller = appWindowToken.getController();
final boolean abort = controller != null
&& controller.keyDispatchingTimedOut(reason,
(windowState != null) ? windowState.mSession.mPid : -1);
if (!abort) {
return appWindowToken.mInputDispatchingTimeoutNanos;
}
} else if (windowState != null) {
try {
// 使用 AMS 的方法
long timeout = ActivityManager.getService().inputDispatchingTimedOut(
windowState.mSession.mPid, aboveSystem, reason);
if (timeout >= 0) {
return timeout * 1000000L; // nanoseconds
}
} catch (RemoteException ex) {
}
}
return 0; // abort dispatching
}
上記の方法で呼び出され、その後バックにAMS inputDispatchingTimedOut()メソッドは、処理を継続し、最終的にinputDispatchingTimedOut()メソッドは、イベントAppErrorsに渡されるされます
// base/services/core/java/com/android/server/am/ActivityManagerService.java
public boolean inputDispatchingTimedOut(final ProcessRecord proc,
final ActivityRecord activity, final ActivityRecord parent,
final boolean aboveSystem, String reason) {
// ...
if (proc != null) {
synchronized (this) {
if (proc.debugging) {
return false;
}
if (proc.instr != null) {
Bundle info = new Bundle();
info.putString("shortMsg", "keyDispatchingTimedOut");
info.putString("longMsg", annotation);
finishInstrumentationLocked(proc, Activity.RESULT_CANCELED, info);
return true;
}
}
mHandler.post(new Runnable() {
@Override
public void run() {
// 使用 AppErrors 继续处理
mAppErrors.appNotResponding(proc, activity, parent, aboveSystem, annotation);
}
});
}
return true;
}
イベントはAppErrorsに渡されたとき、それはハンドラは、メッセージが元のメソッドとポップアップダイアログボックスを呼び出して処理するのに役立ちます。
3、ANRソリューション
上記のANRの原因と原則の分析は、のANRを解決する方法で分析してみましょう。
1. ADB輸出ANRログと分析
ANRシステムは、に格納された情報記録ANR /data/anr/traces.txtファイル(システム内の比較的新しいが、両方の/データ/ ANR / anr_ *ファイルに格納されている)ときに発生します。私たちは、分析のために生成された理由ANRするために、お使いのコンピュータにエクスポートするには、次の方法を使用することができます。
adb root
adb shell ls /data/anr
adb pull /data/anr/<filename>
I ANR分析輸出ログへのコマンドANRトライを使用して浮上している場合は許可が拒否されました。この時間の後、あなたはルートの後に電話をエクスポートする、またはファイルを読み書きする権限を変更しようとする、またはSDカードからの現像モードでSDカードにログをエクスポートするように選択し、表示するためのコンピュータ端末にログを送信することができます
2.使用traceview DDMS分析
DDMSはASで開き、以下SDKのインストールディレクトリのmonitor.batオープンDDMSツールのディレクトリを使用します。
:使用TraceViewツールは、記事を参照することができ、「使用のAndroidのパフォーマンスTraceView分析(印加時間のかかる分析)」
この位置決めANRの考え方は次のとおりです。時間のかかる操作と呼ばれるTraceView時間のかかる方法を見つけるために位置情報を使用しています。
インフォメーション:
3.オープンソースプロジェクトANR-ウォッチドッグ検出ANR
プロジェクトアドレスは Githubの-ANR-ウォッチドッグ
プロジェクトの原理は:タスクを投稿するUIスレッドに進み、検出スレッドを作成し、その後、生成タスクが実行されていないと仮定し、そのような以前のようにして、再度ポストを実行するか否かを検出するタスクまでスレッドの後、一定の時間を寝ANRErrorは、処理を終了します。
4.一般的なANRシーン
I / Oブロックする
ネットワークの輻輳を
デッドロックをマルチスレッド
死ぬことによる反応性プログラミングサイクルにおけるメソッドの結果に
ビジネスロジックの実行時間のためには、長すぎます
5. ANRを回避する方法
UIスレッドのみ可能な限りUIに関連付けられた作業、
時間がかかり、(例えば、データベース操作、I / O、ネットワーク・オペレーション、等)の作業を別のワーカースレッド処理を使用して、
ハンドラとインタラクティブUIスレッドとワーカースレッドを処理するために、
使用RxJavaおよびその他の非同期メッセージを処理します。
要するに、原則は次のとおりです。ない時間のかかる操作を行うには、メインスレッドで。