治理Crash的相关开源框架介绍

治理Crash的相关开源框架介绍

4.1、xCrash(应用崩溃捕获工具)

4.2、KOOM(快手自研OOM解决方案)

4.3、Matrix(腾讯APM框架Matrix)

4.4、Cockroach

4.5、Recovery(奔溃恢复框架)

4.1、xCrash

简述:在移动端 APP 的各种质量问题中,最严重的可能就是 APP 崩溃闪退了。

从安卓 APP 开发的角度,Java 崩溃捕获相对比较容易,JVM 给 Java 字节码提供了一个受控的运行环境,同时也提供了完善的 Java 崩溃捕获机制。Native 崩溃的捕获和处理相对比较困难,安卓系统的debuggerd 守护进程会为 native 崩溃自动生成详细的崩溃描述文件(tombstone)。

在开发调试阶段,可以通过系统提供的 bugreport 工具获取 tombstone 文件(或者将设备 root 后也可以拿到)。但是对于发布到线上的安卓 APP,如何获取 tombstone 文件,安卓操作系统本身并没有提供这样的功能。这个问题一直是安卓 native 崩溃分析和移动端 APM 系统的痛点之一。

2019 年,爱奇艺在 GitHub 上开源了 xCrash。这是一个比较完整的安卓 APP 崩溃捕获 SDK,它能在 App 进程崩溃时,在你指定的目录中生成 tombstone 文件(格式与系统的 tombstone 文件类似)。它支持捕获 native 崩溃和 Java 崩溃;支持安卓 4.0 - 9.0;支持 armeabi,armeabi-v7a,arm64-v8a,x86 和 x86_64。

4.2、KOOM(目前仅支持AndroidX)

简述:OOM是当前Android开发中的常见疑难问题,尤其是线上发生的OOM问题极难定位。业界当前最知名的方案LeakCanary,通过监控Activity/Fragment泄漏优化Java OOM问题,多年来一直为广大app保驾护航,解决了OOM治理从0到1的问题。但面对行业不断复杂的业务环境和庞大用户流量,LeakCanary仍有优化空间:受限于性能,无法在线上大规模部署,仅支持线下使用;只能定位Activity&Fragment泄漏,无法定位大对象、频繁分配等问题;需要人工一一分析,无法对问题聚类量化……为了彻底解决OOM问题,行业尝试了多种解决方案,通常是基于LeakCanary做优化,但至今没有能完全解决监控过程中的性能问题,普遍解决方法是通过采样的办法牺牲一小部分用户的体验来定位问题。

快手OOM Killer沿用行业的研究思路,针对LeakCanary无法解决的难题进行自研改造,充分发挥LeakCanary原有优势的同时补足短板,打造了一套可以线上部署、兼顾线下、配置灵活、适用范围广泛、高度自动化,埋点、监控、解析、上报、分发、跟进、报警一站式服务的闭环监控系统,将绝大多数OOM问题拦截在灰度阶段,彻底解决了OOM问题。

项目地址:https://github.com/KwaiAppTeam/KOOM

4.3、Matrix

简述:

Matrix 是一款微信研发并日常使用的应用性能接入框架,支持iOS, macOS和Android。 Matrix 通过接入各种性能监控方案,对性能监控项的异常数据进行采集和分析,输出相应的问题分析、定位与优化建议,从而帮助开发者开发出更高质量的应用。

Matrix for Android:

一:Matrix-android 当前监控范围包括:应用安装包大小,帧率变化,启动耗时,卡顿,慢方法,SQLite 操作优化,文件读写,内存泄漏等等。

二:APK Checker: 针对 APK 安装包的分析检测工具,根据一系列设定好的规则,检测 APK 是否存在特定的问题,并输出较为详细的检测结果报告,用于分析排查问题以及版本追踪。

三:Resource Canary: 基于 WeakReference 的特性和 Square Haha 库开发的 Activity 泄漏和 Bitmap 重复创建检测工具。

四:Trace Canary: 监控界面流畅性、启动耗时、页面切换耗时、慢函数及卡顿等问题。

五:SQLite Lint: 按官方最佳实践自动化检测 SQLite 语句的使用质量。

六:IO Canary: 检测文件 IO 问题,包括:文件 IO 监控和 Closeable Leak 监控。

项目地址:https://github.com/Tencent/matrix

4.4、Cockroach

简述:很多时候由于一些微不足道的bug导致app崩溃很可惜,android默认的异常杀进程机制简单粗暴,但很多时候让app崩溃其实也并不能解决问题。

有些bug可能是系统bug,对于这些难以预料的系统bug我们不好绕过,还有一些bug是我们自己编码造成的,对于有些bug来说直接忽略掉的话可能只是导致部分不重要的功能没法使用而已,又或者对用户来说完全没有影响,这种情况总比每次都崩溃要好很多。

Cockroach可以避免应用因为一些小bug导致app崩溃,例如:某次热修复发布,增加埋点日志,出现空指针问题,大量不影响用户操作的异常如果没有进行捕获,可能会导致严重故障。

下面介绍几个真实案例来说明这个库的优势:

1、有一款特殊的手机,每次开启某个Activity时都报错,提示没有在清单中声明,但其他几百万机型都没问题,这种情况很可能就是系统bug了,由于是在onclick回调里直接使用startActivity来开启Activity,onclick里没有其他逻辑,对于这种情况的话直接忽略掉是最好的选择,因为onclick回调是在一个单独的message中的,执行完了该message就接着执行下一个message,该message执行不完也不会影响下一个message的执行,调用startactivity后会同步等待ams返回的错误码,结果这款特殊的机型返回了没有声明这个Activity,所以对于这种情况可以直接忽略掉,唯一的影响就是这个Activity不会显示,就跟没有调用onClick一样。

2、我们在app中集成了个三方的数据统计库,这个库是在Application的onCreate的最后初始化的,但上线后执行初始化时却崩溃了,对于这种情况直接忽略掉也是最好的选择。根据app的启动流程来分析,Application的创建以及onCreate方法的调用都是在同一个message中执行的,该message执行的最后调用了Application的onCreate方法,又由于这个数据统计库是在onCreate的最后才初始化的,所以直接忽略的话也没有影响,就跟没有初始化过一样。

3、我们做了个检查app是否需要升级的功能,若需要升级,则使用context开启一个dialog风格的Activity提示是否需要升级,测试阶段没有任何问题,但一上线就崩溃了,提示没有设置FLAG_ACTIVITY_NEW_TASK,由于启动Activity的context是Application,但在高版本android中,可以使用Application启动Activity并且不设置这个FLAG,但在低版本中必须要设置这个FLAG,对于这种问题也可以直接忽略。

项目地址:https://github.com/android-notes/Cockroach

4.5、Recovery

简述:一般的Android应用只是对Crash进行捕捉。Recovery框架能做到对Crash进行捕捉并自动恢复,大大地提高APP的用户体验。

ActivityStack的恢复:对于恢复界面,默认是恢复整个Activity的堆栈,以便保护用户之前的数据。

当应用在前台时崩溃无非就三种:

1、界面一创建就崩溃,可能在onCreate等方法中读取数据造成的Crash

2、界面创建且绘制完成正常显示,在用户执行某个操作,如点击按钮执行某个操作等造成的Crash

3、其它异步线程、服务等在后台执行任务时导致的Crash

上面的情况都应恢复绘制完成后的界面,也就是栈顶Activity是在Crash之前用户所看到的界面,而之前创建且未销毁的Activity也应该进行恢复。

当应用在后台时:

1、进程未挂,无非就是异步线程、server等后台任务发生异常时导致的Crash

2、进程已挂,进程被360等工具杀死了,常见的是push过来了然后唤起App进程,在解析push信息时候导致Crash

上面的情况App在后台时导致的Crash,Recovery提供了一个参数(recoverInBackgroud),用来设置是否在后台Crash时进行恢复。

ActivityStack恢复的操作,都是先恢复栈中的Activity,无Activity时则重启应用。

项目地址:https://github.com/Sunzxyong/Recovery

五、疑难杂症的分析与解决实战

案例一:只发生在vivo V3Max的Crash

我们发现原生系统上对应系统版本的AbsListView里并没有UpdateBottomFlagTask类,因此可以断定是vivo该版本定制的ROM修改了系统的实现。我们在定位这个Crash的可疑点无果后决定通过Hook的方式解决,通过源码发现AsyncTask$SerialExecutor是静态变量,是一个很好的Hook的点,通过反射添加try-catch解决。因为修改的是final对象所以需要先反射修改accessFlags,需要注意ART和Dalvik下对应的Class不同,代码如下:

美团外卖App用上述方法解决了对应的Crash:

案例二:DialogFragment出现IllegalStateException: Can not perform this action after * onSaveInstanceState异常。

解析:在dialog中执行show函数时,概率性出现上面错误信息,查看源码看此异常的出现逻辑。

重写show()函数:

@Override

public void show(FragmentManager manager, String tag) {

if (manager.isStateSaved()) {

Logger.d(TAG, "show: isStateSaved = true");

return;

}

try {

super.show();

} catch (Exception e) {

Logger.w(TAG, "show error"+e);

}

}

案例三:IllegalArgumentException: Service not registered 服务未注册异常

错误信息:

W System.err: java.lang.IllegalArgumentException: Service not registered:com.programandroid.Exception.ExceptionActivity$1@5f3161e

W System.err: at android.app.LoadedApk.forgetServiceDispatcher(LoadedApk.java:1363)

W System.err: at android.app.ContextImpl.unbindService(ContextImpl.java:1499)

W System.err: at android.content.ContextWrapper.unbindService(ContextWrapper.java:648)

W System.err: at com.programandroid.Exception.ExceptionActivity.ServiceNotRegisteredCrash(ExceptionActivity.java:276)

W System.err: at java.lang.reflect.Method.invoke(Native Method)

W System.err: at android.view.View$DeclaredOnClickListener.onClick(View.java:4744)

W System.err: at android.view.View.performClick(View.java:5675)

log分析:

此异常经常发生在错误的解除绑定服务造成的,解决方法:

1.解除绑定服务之前,先判断是否绑定过,只有绑定过后才可以解绑。

2.使用try-catch 抓取住异常。

代码实现:

案例四:BadTokenException异常处理

错误log信息:

FATAL EXCEPTION: main

Process: com.android.fmradio, PID: 5564

java.lang.RuntimeException: Error receiving broadcast Intent { act=android.intent.action.HEADSET_PLUG flg=0x40000010 (has extras) } in com.android.fmradio.FmService$FmServiceBroadcastReceiver@b3d2a03

at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0(LoadedApk.java:1401)

at android.app.-$$Lambda$LoadedApk$ReceiverDispatcher$Args$_BumDX2UKsnxLVrE6UJsJZkotuA.run(Unknown Source:2)

at android.os.Handler.handleCallback(Handler.java:873)

at android.os.Handler.dispatchMessage(Handler.java:99)

at android.os.Looper.loop(Looper.java:193)

at android.app.ActivityThread.main(ActivityThread.java:6702)

at java.lang.reflect.Method.invoke(Native Method)

at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)

at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:911)

Caused by: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@f652dba -- permission denied for window type 2003

at android.view.ViewRootImpl.setView(ViewRootImpl.java:851)

at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:356)

at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)

at android.app.Dialog.show(Dialog.java:329)

at com.android.fmradio.FmService$FmServiceBroadcastReceiver.onReceive(FmService.java:322)

at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0(LoadedApk.java:1391)

... 8 more

解决方案:

系统弹窗,请用TYPE_APPLICATION_OVERLAY 替换之前的Windows Type。

Dialog mFMDialog = new AlertDialog.Builder(context)

.setTitle(R.string.airplane_title).setMessage(R.string.airplane_message)

.setPositiveButton(R.string.close_FM,

new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

}

}

).setCancelable(false).create();

// Android 8.0 之后弹出系统弹窗,需要使用 TYPE_APPLICATION_OVERLAY

// <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

// 一下两个 之前常用的系统的Dialog 会报

// BadTokenException: Unable to add window android.view.ViewRootImpl$W@f652dba -- permission denied for window type 2003

//mFMDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);

//mFMDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

mFMDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);

mFMDialog.show();

六、扩展阅读:

1、https://tech.meituan.com/2018/06/14/waimai-android-crash.html(美团外卖Android Crash治理之路)

2、Android 微信APM工具 Matrix使用 - 简书(Android 微信APM工具 Matrix使用)

3、Android开发之打造永不崩溃的APP——Crash防护 - 简书(Android开发之打造永不崩溃的APP——Crash防护)

4、https://blog.csdn.net/leeo1010/article/details/50522892(Android平台的崩溃捕获机制及实现)

5、https://my.oschina.net/bugly/blog/1354954(Android 平台 Native 代码的崩溃捕获机制及实现)

6、Android Crash 案例分析 - 简书(Android Crash 解决方案)

7、http://blog.itpub.net/69945252/viewspace-2674668/(安卓APP崩溃捕获方案——xCrash)

8、https://developer.51cto.com/art/202008/623474.htm(快手自研OOM解决方案KOOM今日宣布开源)

9、Android OOM 解决方案 - 简书(Android OOM 解决方案)

10、你知道Android为什么会Crash吗 - 简书(你知道Android为什么会Crash吗)

11、https://blog.csdn.net/csdn_aiyang/article/details/105054241(Crash治理之路——AndroidCrashX开源库)

12、https://www.jianshu.com/p/fc0f6e38e2f3(Android应用崩溃(Crash)日志报告)

13、https://kymjs.com/code/2018/08/22/01/(Android Native Crash 收集)

14、https://blog.csdn.net/u010144805/article/details/80763956(使用objdump进行Android crash 日志 分析)

15、https://blog.csdn.net/hfut_why/article/details/85221069(Crash信息本地存储)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值