Android 使用自定义UncaughtExceptionHandler处理Firebase崩溃报告和自定义应用程序类
我的Android应用程序目前使用一个自定义的Android 使用自定义UncaughtExceptionHandler处理Firebase崩溃报告和自定义应用程序类,android,firebase,firebase-crash-reporting,Android,Firebase,Firebase Crash Reporting,我的Android应用程序目前使用一个自定义的UncaughtExceptionHandler,旨在捕获任何崩溃,并在手动调用Process.killProcess(Process.myPid())之前,使用AlarmManager计划未来几秒钟的应用程序重启,以避免Android在我的应用程序用例中出现强制关闭弹出窗口,用户将无法与设备交互以点击FC对话框上的“确定”并重新启动应用程序 现在,我想与Firebase崩溃报告集成,但我担心错误行为,所以我的问题如下: 我应该如何生成代码,以便我的
UncaughtExceptionHandler
,旨在捕获任何崩溃,并在手动调用Process.killProcess(Process.myPid())
之前,使用AlarmManager
计划未来几秒钟的应用程序重启,以避免Android在我的应用程序用例中出现强制关闭弹出窗口,用户将无法与设备交互以点击FC对话框上的“确定”并重新启动应用程序
现在,我想与Firebase崩溃报告集成,但我担心错误行为,所以我的问题如下:
UncaughtExceptionHandler
在终止其进程之前将异常传递给Firebase崩溃报告?调用Thread.getDefaultUncaughtExceptionHandler()
会给我Firebase崩溃报告UncaughtExceptionHandler
,这样我就可以调用uncaughtException(…)
Process.killProcess(Process.myPid())
防止Firebase崩溃报告库执行报告工作吗?Firebase在返回uncaughtException(…)
之前是否会在一个单独的过程中启动崩溃报告?Firebase是否拥有UncaughtExceptionHandler
调用Android默认的UncaughtExceptionHandler
,显示FC对话框Process.killProcess(Process.myPid())
kill Firebase崩溃报告进程应用程序类如何检测它是否在Firebase崩溃报告过程中实例化?以同样的方式处理这两个过程可能会导致状态不一致
感谢所有试图帮助我的人 如果在异常处理程序中终止进程,将无法接收崩溃。它将干扰为即时或延迟传输持续碰撞的能力。它可能会干扰任何已注册行为良好的未捕获异常处理程序的库 事实上,Process.killProcess(Process.myPid())在很大程度上是Android开发的一个工具。Android应用程序不应该关心整个生命周期,如果托管该应用程序的进程失败的话。安卓系统为您管理流程的事实是为用户的利益而设计的优化 我强烈建议,对于应用程序中未捕获的异常,只需让应用程序像往常一样死掉。掩盖碰撞的适当效果就像在地毯下清扫灰尘一样。您可能正在解决一个短期问题,但真正需要做的是对错误进行正常的日志记录和处理,以便您能够修复它 不要依赖Firebase崩溃报告在另一个进程中传输异常这一事实。其他进程将在完整的非测试版中删除
应用程序子类的最佳情况是完全不依赖于它运行的进程。事实上,谷歌的Android团队根本不建议使用应用程序子类,因为它只会给多进程应用程序带来麻烦。如果您必须使用应用程序子类,它应该在多个进程中运行。经过一些测试,我终于找到了一种方法来确保我的应用程序在发生
未捕获异常后正确重新启动。
我尝试了三种不同的方法,但只有第一种,这是我的原始代码,只需稍加调整即可将未捕获的Throwable
传递到`firebasecash',并确保它被视为致命错误
有效的代码:
final UncaughtExceptionHandler crashShield = new UncaughtExceptionHandler() {
private static final int RESTART_APP_REQUEST = 2;
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (BuildConfig.DEBUG) ex.printStackTrace();
reportFatalCrash(ex);
restartApp(MyApp.this, 5000L);
}
private void reportFatalCrash(Throwable exception) {
FirebaseApp firebaseApp = FirebaseApp.getInstance();
if (firebaseApp != null) {
try {
FirebaseCrash.getInstance(firebaseApp)
.zzg(exception); // Reports the exception as fatal.
} catch (com.google.firebase.crash.internal.zzb zzb) {
Timber.wtf(zzb, "Internal firebase crash reporting error");
} catch (Throwable t) {
Timber.wtf(t, "Unknown error during firebase crash reporting");
}
} else Timber.wtf("no FirebaseApp!!");
}
/**
* Schedules an app restart with {@link AlarmManager} and exit the process.
* @param restartDelay in milliseconds. Min 3s to let the user got in settings force
* close the app manually if needed.
*/
private void restartApp(Context context, @IntRange(from = 3000) long restartDelay) {
Intent restartReceiver = new Intent(context, StartReceiver_.class)
.setAction(StartReceiver.ACTION_RESTART_AFTER_CRASH);
PendingIntent restartApp = PendingIntent.getBroadcast(
context,
RESTART_APP_REQUEST,
restartReceiver,
PendingIntent.FLAG_ONE_SHOT
);
final long now = SystemClock.elapsedRealtime();
// Line below schedules an app restart 5s from now.
mAlarmManager.set(ELAPSED_REALTIME_WAKEUP, now + restartDelay, restartApp);
Timber.i("just requested app restart, killing process");
System.exit(2);
}
};
Thread.setDefaultUncaughtExceptionHandler(crashShield);
解释原因和失败尝试
奇怪的是,来自firebasecash
类的假设名为reportFatal(Throwable ex)
的方法在静止状态下(谢天谢地)public
,给了它以下签名:zzg(Throwable ex)
这个方法应该是公开的,但不能被混淆
为了确保我的应用程序能够与Firebase崩溃报告库引入的多进程正常工作,我必须按照Doug Stevenson的建议,将代码从应用程序类中移出(这是一件好事),并将其放在延迟加载的单进程中,现在它已经准备好了多进程
您可以看到,在我的代码中没有任何地方,我调用/委托了默认的UncaughtExceptionHandler
,这将是Firebase崩溃报告。我没有这样做,因为它总是调用默认的一个,这是Android的一个,它有以下问题:
在我将异常传递给Android默认的UncaughtExceptionHandler
的那一行之后编写的所有代码将永远不会执行,因为调用正在阻塞,进程终止是之后唯一可能发生的事情,除了已经运行的线程
让应用程序死掉并重新启动的唯一方法是在计划在不久的将来使用AlarmManager
重新启动后,使用System.exit(int which)
或process.kill(process.myPid())
以编程方式终止进程
有鉴于此,我在调用默认的UncaughtExceptionHandler
之前启动了一个新的线程
,该线程将在Firebase崩溃报告库获得异常后但在计划的重新启动触发(需要幻数)之前终止正在运行的进程。它第一次起作用,在后台线程终止进程时删除了强制关闭对话框,然后,AlarmManager
唤醒了我的应用程序,让它知道它崩溃了,有机会重新启动
问题是,第二次不起作用是因为一些模糊和完全没有记录的原因。即使计划重新启动的代码调用AlarmManager