Android Bug收集解决方案
一.概述
本文主要介绍Android平台下bug类型和产生原因、崩溃捕获和收集解决方案、以及bugly的使用方法。Android平台下bug类型主要有Crash、ANR、卡顿、服务器异常等。要实现Android Bug捕获和收集的困难主要有这么几个:
1、如何捕获崩溃;
2、如何获取堆栈信息;
3、将错误日志上传到指定服务器。
采用腾讯bugly的错误日志功能能捕获应用Java Crash、C/C++ Native Crash 、 ANR和卡顿,能够满足日常需求,且不需要额外准备接收服务器。使用bugly可以收集到已发布应用的异常,以便测试和开发人员发现和修改bug,对于提高软件质量有着极大的帮助。
二.Android 平台bug类型及产生原因分析
Android系统架构图.png 为了更好的理解后面的内容,首先让我们来了解一下Android的系统架构,从上图我们可以看到,Android分为四个层,从高层到低层分别是应用程序层、应用程序框架层、系统运行库层和linux核心层。
简单来说Android系统本质上通过底层精简的Linux系统来启动Android的Dalvik虚拟机,然后在这个虚拟机上跑Java应用,同时它封装了大量java和c++的API供外部调用。
Android 平台bug类型主要有:Crash、ANR、卡顿、服务器异常等。
1,常见的Android Crash有两类:一类是Java Exception异常,一类是Native Signal异常。java代码导致jvm退出,弹出“程序已经崩溃”的对话框,最终用户点击关闭后进程退出。通过NDK,使用C/C++开发,导致进程收到错误信号,发生Crash,Android 5.0之前进程直接退出(闪退) , Android 5.0之后会弹“程序已崩溃”的对话框。
2,ANR全称是Application Not Responding,是指应用程序未响应。
Android系统对于一些事件需要在一定的时间内完成,如果超过预定时间未响应或者响应时间过长,会造成ANR。一般这时系统会弹出一个ANR对话框,用户可自行选择继续等待或者停止当前程序运行。
那么哪些场景会造成ANR呢?
- 1)、Service Timeout:比如前台服务在20秒内未执行完成;
- 2)、BroadcastQueue Timeout:比如前台广播在在10秒内未执行完成;
- 3)、ContentProvider Timeout:内容提供者,在punlish过超时10秒;
- 4)、InputDispatching Timeout:输入事件分发超时5秒,如按键或者触摸事件;
3,卡顿:16ms原则。Android系统每隔16ms会发出VSYNC信号重绘界面(Activity)。
为什么是16ms,因为Android设定的刷新频率是60FPS(Frame Per Second),也就是每秒60帧的刷新率,约合16ms刷新一次。
这就意味着,我们需要在16ms内完成下一次刷新的界面相关运算,以便界面更新。
哪些情况会导致卡顿?
- 1)、过于复杂的布局(使用Hierarchy Viewer工具分析,Hierarchy Viewer 不仅可以以图形化树状结构的形式展示出UI层级,还对每个节点给出三个小圆点,以指示该元素Measure,Layout,Draw的耗时及性能);
- 2)、过度绘制(OverDraw),理想情况下,每屏每帧上,每个像素点应该只被绘制一次,如果有多次绘制,就是OverDraw,过度绘制了。
4,服务器异常:使用Fiddler抓包工具。
Fiddler是位于客户端和服务端的HTTP代理。它能够记录客户端的服务器之间的所有HTTP请求,可以针对特定的HTTP请求,分析请求数据、设置断点、调试web应用、修改请求的参数,甚至可以修改服务器返回的数据,功能非常强大。
引申——Android适配问题引起的bug
- 1),屏幕适配:分辨率、尺寸等。
- 2),机型适配:2015年统计1294家厂商生产出682000款Android手机。
- 3),Android版本适配:比如说,Android6.0加入运行时权限,7.0加入虚拟文件对相机拍照和选择图片有影响。
三.崩溃捕获原理
系统的默认处理
很抱歉,”营销管家”已停止运行。
-
1),Java崩溃捕获方式
java的Thread中有一个UncaughtExceptionHandler接口,该接口的作用主要是为了 当 Thread 因未捕获的异常而突然终止时,调用处理程序。
线程一旦崩溃,异常处理器的Thread.UncaughtExceptionHandler.uncaughtException(Thread t,Throwable e)方法被调用(该方法主要作用为设置当线程由于未捕获到异常而突然终止,并且没有为该线程定义其他处理程序时所调用的默认处理程序)。最后在uncaughtException方法中实现Java异常的捕获及上报。 -
2),Native崩溃捕获方式
通过上图我们可以看到,当我们new Thread 然后start线程启动,这时候线程的状态是已经准备就绪但是并没有执行的状态。这时首先会在liunx C层面通过Pthread_Create()这个API创建一个线程,创建这个线程以后执行一遍interpThreadStart()方法,然后继续执行到dvmcallMethod()方法,这个方法里面通过JNI调用我们new出来的Thread里面的run方法。可以看到这整个过程都是在一个Pthread线程里面,整个线程栈被划分为两个部分,一个是c层的native栈,一个是java层的java栈。假设这个时候执行的java线程突然崩溃了,它会一层一层的往上抛异常,直到整个java栈一层一层退出,java栈退出之后会生成一个Pending Exception这样一个数据结构。接下来它就回到了dvmcallMethod里面,就结束了。结束之后理论上它就要把这个线程跟虚拟机解开来,解开以后这个线程就要退出了。当它解开的时候发现有一个Pending Exception存在,即有一个未捕获的异常存在,那么这个线程退出之前会调用uncaughtExceptionHandler方法,所有我们可以在这个回调方法里处理未捕获的异常情况。
四.移动端常用的bug收集方案
- 友盟
优点:Android和iOS可用,统计功能突出,能捕获应用层Crash;
缺点:bug收集不及时。
- 友盟
- Bugly
优点:Android和iOS可用,bug收集及时,能捕获应用Java Crash、C/C++ Native Crash和ANR并提供相应的bug修复建议,对bug进行了合并统计,目前是免费的;
缺点:bugly收集的信息较多。
- Bugly
- Bugtags
优点:一套完善的bug管理系统,Android和iOS可用。
缺点:免费版功能有限。
- Bugtags
- DIY(自己搭建bug收集平台)
优点:可以根据自己的业务需求实现,不依赖第三方平台;
缺点:需要编写错误收集代码,需要搭建错误日志收集服务器。
- DIY(自己搭建bug收集平台)
五.使用Bugly
看懂问题ISSUE.png- 1),看懂bugly 的java 栈
- 2),看懂Bugly的Native栈
六.Bugly存在误报和漏报吗?
- 1)不存在误报。
因为异常与否是由系统API直接回调,不存在Bugly误判的空间。 - 2)存在漏报。
没来的及处理,比如说虚拟机崩溃,直接dump了,虚拟机直接sigabrt ,此时调用任何jni ,程序直接退出了。
上报是在java层,第二次启动时上报上去,有可能用户卸载了,或者不再打开等。 - 3)对于try...catch住的异常,可使用高级功能中的CrashReport.postCatchedException(thr)主动上报开发者Catch的异常 。
参见:https://bugly.qq.com/docs/user-guide/advance-features-android/?v=20170912151050
七.关于移动应用Crash统计数据
整体崩溃率.png 崩溃机型.png Top崩溃.png八.Android常见bug及解决方案总结
参考:Android常见bug及解决方案总结.doc
九.服务器异常获取
参考:Fiddler手机抓包工具使用详解.doc
十.DIY Android和iOS平台的崩溃捕获和收集器
参考:经典好文:android和iOS平台的崩溃捕获和收集 - wx0123 - 博客园.htm