问题很简单,在我的应用程序的系统日志中,我得到了receiver
的背景
ANR,并且线程ID不是UI。想了解ANR的背景以及可能发生的方式。
我在官方手册中没有找到关于“bg anr”的详细解释,但是在android框架的源码中还是有一些线索的:
final void appNotResponding(...) {
...
synchronized (mService) {
isSilentANR = !showBackground && !isInterestingForBackgroundTraces(app);
...
}
...
File tracesFile = ActivityManagerService.dumpStackTraces(
true, firstPids,
(isSilentANR) ? null : processCpuTracker,
(isSilentANR) ? null : lastPids,
nativePids);
synchronized (mService) {
if (isSilentANR) {
app.kill("bg anr", true);
return;
}
...
//Show anr dialog
Message msg = Message.obtain();
msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG;
msg.obj = new AppNotRespondingDialog.Data(app, activity, aboveSystem);
mService.mUiHandler.sendMessage(msg);
}
}
上面代码中的silentANR表示满足以下两个条件:
而silentANR不会显示ANR对话框,而是直接杀死App进程
所以函数
isInterestingForBackgroundTraces(app)
判断是fg anr还是bg anr,参考https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r4/services/core/java /com/android/server/am/AppErrors.java#756
static boolean isInterestingForBackgroundTraces(ProcessRecord app) {
// The system_server is always considered interesting.
if (app.pid == MY_PID) {
return true;
}
// A package is considered interesting if any of the following is true :
//
// - It's displaying an activity.
// - It's the SystemUI.
// - It has an overlay or a top UI visible.
//
// NOTE: The check whether a given ProcessRecord belongs to the systemui
// process is a bit of a kludge, but the same pattern seems repeated at
// several places in the system server.
return app.isInterestingToUserLocked() ||
(app.info != null && "com.android.systemui".equals(app.info.packageName)) ||
(app.hasTopUi || app.hasOverlayUi);
}
总结一下,判断是fg还是bg anr取决于anr发生时App是否能够被用户感知。例如,具有当前在前台可见的活动的进程,或者具有带前台通知的 fg-service 的进程。这些都是anr发生时用户能够感知到的情况。对用户体验影响很大,所以需要弹出对话框让用户决定是退出还是等待。如果直接杀掉这类fg App,会导致用户莫名其妙的崩溃。
与 fg anr 相比,bg anr 将在后台直接被杀死,无需向用户对话,除非在设备的开发者选项中启用了显示所有 ANR。默认情况下它是禁用的。
还有一些测试结果可以证明这一点:
首先,我在
onReceive()
方法中定义了一个仅休眠 100 秒的广播接收器。
然后用
sendOrderedBroadcast()
和 sendBroadcast()
进行测试:
| | sendOrderedBroadcast(意图,空)|发送广播(意图)|
| -------- | -------------- |-------------- |
| - 显示活动的应用程序顺便说一句,是否是
FLAG_RECEIVER_FOREGROUND
与是fg anr还是bg anr无关。但它决定了时间,这是测试结果:
| intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
sendOrderedBroadcast(intent, null);
|// no flag
sendOrderedBroadcast(intent, null);
|
| -------- | -------------- |
|阻塞10s后出现anr |阻塞60s后出现anr |
感谢Gityuan: