我们有一个Android应用程序,最近报告了许多ANR错误。这仅在Android 7.1和8.0上发生(例如不会在4.4、5.0或6.0上出现)。ANR是:
Broadcast of Intent { act=com.google.firebase.INSTANCE_ID_EVENT flg=0x14 cmp=com.our.package.name/com.google.firebase.iid.FirebaseInstanceIdInternalReceiver (has extras) }
问题是:为什么会出现这个ANR,我们该怎么做才能避免它?请注意,在早期的Android版本上,这个问题可以正常工作,这证明了我们没有犯造成ANR的新手错误。
我很难再现这个错误。由于只有在Android 7.1和8.0上出现,因此我认为可能与新的待机模式和节电功能有关,但即使在测试过程中使用adb shell dumpsys deviceidle force-idle
等也无法重现此问题,将SystemClock.sleep(20000);
放置在几个地方也不行。
我们的InstanceIdService
代码如下:
public class InstanceIdService extends FirebaseInstanceIdService {
private Analytics mAnalytics;
@Override
public void onCreate() {
super.onCreate();
mAnalytics = new AnalyticsImpl();
boolean isFullVersion = getApplicationContext().getPackageName().endsWith("full");
mAnalytics.init(getApplicationContext(), isFullVersion);
}
@Override
public void onTokenRefresh() {
boolean initialLoginSucceeded = OurAppNameApplication.getInstance().getSettings().getInitialLoginSucceeded();
mAnalytics.logEvent("FCM_Token_Refresh_Triggered", "initialLoginSucceeded", String.valueOf(initialLoginSucceeded));
if (initialLoginSucceeded) { // We only report the FCM token to our server if the user has logged in at least once
OurAppNameApplication.getInstance().getOurAppNameService().registerDeviceWithRetry();
}
}
}
我们使用Google Play服务和Firebase版本11.2.0。我们的targetSdkVersion为25。
PS:上面的代码mAnalytics.init(...)
给我们一个StrictMode警告,因为这个代码块初始化了Flurry。但这是磁盘访问,而不是网络流量。在这个位置放入SystemClock.sleep(20000);
不会触发任何ANR。
为什么会出现ANR,我们该怎么避免?
--
编辑:根据Bob Snyder的建议,在测试了adb shell cmd appops set com.our.package.name RUN_IN_BACKGROUND ignore
后。然而,这不会产生任何ANR,只会停止我们的广播接收器运行,如日志中所示:
09-21 10:39:25.314 943-6730/? W/ActivityManager: Background start not allowed: service Intent { act=com.google.firebase.INSTANCE_ID_EVENT pkg=com.our.package.name cmp=com.our.package.name/com.our.package.service.notifications.InstanceIdService (has extras) } to com.our.package.name/com.our.package.service.notifications.InstanceIdService from pid=4062 uid=10139 pkg=com.our.package.name
09-21 10:39:25.314 4062-4062/com.our.package.name E/FirebaseInstanceId: Error while delivering the message: ServiceIntent not found.
我的结论是这可能不是复现这个ANR错误的正确方式。
为了完整起见:测试时使用的所有ADB命令如下:
adb shell dumpsys deviceidle force-idle
adb shell dumpsys battery unplug
adb shell am set-inactive com.our.package.name true
adb install -r our-app.apk
adb shell cmd appops set com.our.package.name RUN_IN_BACKGROUND ignore
实际上 - 最后一行与adb install
同时运行多次,以确保在安装和还原(设置)完成之前它生效,并且Firebase注册令牌在安装后会自动刷新。
adb shell cmd appops set <package_name> RUN_IN_BACKGROUND ignore
。它可以模拟无法使用隐式广播和后台服务的情况。 - Bob Snyder