做了个分析名字含义的小网站,希望各位给点建议 |
时间:3月9日晚8:00 | 地点:猫友会微信群
群策划:首先声明下猫友会的宗旨:改变武汉的互联网行业环境,需要每一个人出力,每个人做出一点点,它就会慢慢改变!
腾讯Bugly终端团队主要负责人,目前承担腾讯Bugly终端SDK的研发工作
主要涉及iOS/Android、Unity/Cocos等相关的工具研发。
4+年移动终端经验
一、崩溃监控分析的重要性
二、相关技术要点
三、第三方工具与服务的作用
四、一点经验总结
1.讲师分享 - 图文形式,大约45~60分钟
2.问题以及讨论环节
3.答谢环节
冯义力:大家好,非常高兴可以跟大家一起交流。
一:
今天主要给大家分享下App崩溃监控分析方面的内容,对于崩溃监控分析,想必很多开发的同学们对其也是十分熟悉,在此,我就简单的分享下个人关于这个话题的一些理解和看法,权当抛砖引玉。
MDCC 2015移动开发工具“元素周期表” 相信大家都很熟悉。这张图从一个很直观的角度,勾勒出移动开发工具与服务生态。作为一名移动应用开发者,你一定会跟其中的一些工具与服务产生过交集,尤其是统计分析、监控类的工具与服务。今天,重点分享的就是移动应用崩溃监控分析工具相关的内容。
根据我们对App Store和应用宝的排名靠前的App分析,基本上每一个App都有集成一套崩溃监控分析工具,不论是自己实现还是使用第三方的服务,而那些裸奔的应用,其用户量级也是比较小的。从这个方面,可以看出崩溃监控分析的重要性。在笔者看来,其重要性则是由下面几个因素决定:
1)崩溃监控是开发者追综应用线上版本Bug的快速有效的方式。因为脱离调试环境的线上版本,只有通过云端的监控才能及时感知App的质量问题。
2)崩溃统计分析是衡量应用质量的重要参考指标。因为从长远来看,App用户规模的增长跟其功能稳定性是有必然联系的。没有哪一个每天闪退频繁的App,其用户规模可以获得大规模的持续增长。
以上,是我对于崩溃监控对于应用的重要性的看法。
二:
接下来,咱们就简单的说一下如何快速的实现应用的崩溃监控功能。实际上,其涉及的要点主要有以下几点:
1.如何进行崩溃监听?
程序猿都知道,应用发生崩溃,一部分是由于代码逻辑出现异常,但开发者并没有主动处理(try-catch),系统抛出(throw)未处理异常(UncaughtException)后,关闭应用进程。对于这个场景的崩溃,系统有提供API方法让开发者可以统一处理UncaughtException,因此,通过系统API方法可以快速实现未处理异常的崩溃的监听,即:
- Thread.setDefaultUncaughtExceptionHandler() - 监听Java未处理异常
- NSSetUncaughtExceptionHandler() - 监听Objective-C未处理异常
所以,开发者可以快速的通过这个接口方式快速实现监听:
注册监听Java未处理异常,同样地,注册监听Objective-C未处理异常的方式如下:
在这几段示例代码中,有一点需要跟大家强调一下,因为这个问题我们经常遇到开发者的咨询。那就是,系统的API注册监听函数是覆盖式的,后注册的函数生效。而这个就是为什么多个崩溃监控组件一起集成后,有的没有捕获到崩溃的原因。所以,我们一般建议在处理时都按示例代码中方式进行注册监听,即在注册监听之前,先获取默认设置的监听函数,在处理完成后,传递给默认的监听函数。
如果每一个实现崩溃监控的组件都是按照这个规则处理,彼此就不会影响,否则就会导致抢注册问题,影响到部分组件的崩溃监控。一般地,实现未处理异常的监听,就可以捕获到应用大部分的崩溃问题。但对于iOS应用或者有开发Native库的Android应用来说,这样的监听机制还不够全面。因为应用发生崩溃,还有一部分是因为指针问题而引发,所以,开发者需要针对Objective-C或Android Native库(c/c++开发)进行此类崩溃问题的监听。而这个场景的崩溃,则可以依赖Linux/Unix信号处理机制实现监听,即:
- signal(int signo, void * handler) - 注册错误信号监听,handler仅传递signo
- sigaction(int signo, void * handler, void* pre_handler) - 注册错误信号监听,handler传递signo、siginfo_t、user_context
两个方法,使用其中一种注册监听即可。一般地,建议使用sigaction进行注册监听,因为它获得的崩溃现场信息相比signal函数会更多一些。sigaction的实现相比signal要复杂一些,这里,我也不展开阐述。稍后可以专门梳理相关文章跟大家分享。
2.如何进行崩溃现场信息采集
对于Java的未处理异常,可以直接从监听函数的行参获取当前线程,异常堆栈信息。示例:
捕获的信息如下:
在获取现场信息时,也有一些注意事项:
部分未处理的异常,因为线程嵌套问题而被二次封装为一个RuntimeException,其真正的错误原因是回调函数的Throwable对象的Cause对象中,所以,有必要对Cause的对象进行遍历获取。
获取的线程堆栈中,部分应用堆栈行是混淆后的类和方法,所以,需要后续进一步反混淆处理才能定位分析具体的位置
而对于Objective-C未处理异常,同样也可以从监听函数的行参获取当前异常堆栈信息:
捕获的堆栈信息如下:
同样地,也有几个注意事项:
- 监听函数仅传递异常堆栈信息,线程状态等需通过其他方法获取
- 直接上报堆栈符号是不靠谱的做法
- 堆栈行中的系统堆栈行可以进一步解析出具体的函数符号
- 除了堆栈信息以外,还必须上报BinaryImage信息,包含堆栈行所有模块的地址分配等信息,是地址解析出符号的依赖条件
以上就是崩溃现场信息捕获方面的内容。
从截图中可以看到,无论Java堆栈还是OC的堆栈,都是无法直接分析定位问题的。因为线上版本的Android App其代码是经过混淆处理,而iOS App则是因为其调试符号信息文件已经被剥离。所以,对于Android的崩溃堆栈,需要进行反混淆的处理,而这个反混淆的过程,是可以通过Proguard工具进行处理。
Proguard是Java代码混淆的工具,在Android SDK中,有提供配套的混淆和反混淆的工具,开发者只需把捕获的堆栈,跟代码混淆产生的映射文件mapping结合,就可以得到正常的堆栈。对于iOS的崩溃堆栈,则需要进行堆栈地址的符号化处理,这个处理过程使用系统的atos工具,借助iOS应用的符号调试信息文件dSYM 就可以完成。
以上内容,就是关于崩溃监控分析方面的一些要点。 或许,从其基本实现原理来看,比较简单。 但实际处理过程却并非想象中的那么容易。
三:
今天,跟大家分享的是开发工具,必然是有一些好用的轮子,避免大家重复制造。
首先,开发者可以借助开源框架,快速的为App添加崩溃监控功能,目前比较成熟的框架有:
- Android: Breakpad(Google提供的跨平台崩溃监控框架,也支持iOS)
- iOS: PLCrashReporter,KSCrash等
并且,不乏一些第三方崩溃监控工具是对开源框架的二次封装。
当然,开源框架可以快速解决崩溃问题采集上报的需求。 但不可避免的,开发者仍需要自己负责对上报的数据进行解析归类处理。而这个分析统计,正是崩溃监控分析服务中重中之重的一个环节。所以,如果开发者信赖第三方的服务,可以在App中集成第三方崩溃监控分析服务,借助服务平台的能力对App的崩溃问题进行监控分析。
目前,国内外有好些个第三方的崩溃监控分析的服务,包括一些专用的服务或辅助性的:
首先,不得不提的就是 Fabric/Crashlytics。Crashlytics是国外知名的崩溃监控分析服务,被Twitter收购后并入Fabric服务,目前Fabric提供Answers(统计分析)、Beta(内测发布)、Crashlytics(崩溃监控)服务。它的堆栈分析是做的比较赞的。
还有Hockey SDK,国外崩溃监控分析服务,基于KSCrash框架开发,被微软收购后并入Application Insights服务。
Bugsnag,国外轻量级崩溃监控分析服务,支持平台,类别较多,支持WebHook种类非常多。
而国内的开发工具有提供崩溃统计分析的也有不少:
Umeng,移动统计分析服务平台,提供统计分析、更新,分享,推送等服务,其中,错误分析也是在统计分析的基础上添加。
还有Testin,云测平台,服务升级改版后,推出云测,APM,分发三部分的服务,其中,崩溃分析在APM服务中包括。
其他的还有OneAPM-APM服务平台,BugHD-分发服务平台FIR推出的崩溃监控服务等。
鹅厂有 MTA-移动统计分析平台,核心功能跟Umeng相似,同样提供崩溃监控分析。腾讯Bugly则是2014年面向外部开发者推出的崩溃监控分析服务, 而且除了崩溃,还提供ANR(Android)/卡顿(iOS)问题,脚本错误脚本等监控分析。
说了这么多 第三方工具,大家不禁要问,崩溃捕获哪家强,是吧?
整体来说,各个服务平台崩溃监控采集上报能力基本相当,前面也提到,不乏部分第三方服务基于开源框架开发而来。但崩溃监控分析服务,除了需要关注监控崩溃问题的场景数据以外,还需考量额外辅助信息的全面性,场景覆盖,实时性和分析统计的能力。至于详细的情况,笔者也就不褒不贬,感兴趣的开发者可以自己试用体会下。
四:
说到这里,再跟大家简单的介绍下Bugly的崩溃监控分析服务。
Bugly的崩溃监控分析服务起初是服务于鹅厂内部的终端App,从部门级逐渐到公司级全量App的覆盖。所以,完成公司终端App的服务提供后,我们开始考虑把服务对外,给其他的开发者也提供专业的服务。而Bugly的崩溃监控分析,除了关注崩溃捕获以外,还提供 自动化堆栈解析,动态归类,实时统计,监控告警等功能,特有的ANR/卡顿监控分析,专属的游戏脚本错误监控分析和用户留存分析等功能。后续,也会逐渐开放更多研发流程中的开发工具给大家使用,诸如CI、应用分发(已上线)等,欢迎感兴趣的伙伴试用。
具体的Bugly的使用这里不详细介绍,感兴趣的同学可以极客学院搜索Bugly的接入视频了解。
我要分享的内容就到这里啦,感谢大家!
Q&A
Q1:比如我服务器端性能不好,或者老是异常,有工具可以分析吗?
A1:你说的是APM方面的内容,APM主要关注服务接口性能或成功率方面的监控,而对于服务端的异常监控,也有成熟的JS异常捕获服务提供。Bugly也正在尝试是否提供这样的一套服务。
Q2:部分未处理的异常,因为线程嵌套问题而被二次封装为一个RuntimeException,其真正的错误原因是回调函数的Throwable对象的Cause对象中,所以,有必要对Cause的对象进行遍历获取。这里不是很懂,即使线程嵌套的话,只要关注最终失败的线程异常堆栈就可以了。
A2:这个问题是这样的,一个Throwable对象中可能会出现嵌套许多层CauseBy的情况,如果直接获取StackTrace,那么顶层的异常信息不一定是问题所在,所以需要遍历深层的CauseBy信息,得到具体的出错信息。这样上报的崩溃问题归类才会比较准确。
Q3:处理异常 其实是运行在另外一个线程吗?还是只能在当前线程做简单的事 因为你稍后就把把线程kill掉了?
A3: 处理异常时是在当前线程执行的,但部分任务有放到其他子线程去做,此时会阻塞当前线程,设定超时,到达时间阀值后,就Kill进程。
Q4: 堆栈怎么定位到具体问题的,那块怎么实现的,没太懂?
A4:堆栈是崩溃时刻,相关方法的调用链,一般顶层的堆栈行就是发生崩溃问题的函数或方法。如果有进行解析的话,还可以得到具体的行号信息,而文件行号即指向发生崩溃问题的代码行。其实现基本原理 就是从系统的监听函数中获取当前的发生崩溃的异常信息,这个堆栈就在异常信息中。
Q5:内存消耗过大导致的闪退怎么监测?
A5:内存消耗过大问题,目前没有第三方的监控服务可以监测并上报,包括系统记录的日志文件,也只是罗列了内存占用最大的进程信息。目前,Bugly已经推出监测FOOMs的场景的事件上报,方便开发者明确此类问题的概率,后续,会结合内存监控模块,提供附属信息,方便定位发生的具体时刻。
Q6: 不同的异常捕获服务,在抓取异常这块有什么差异点吗? 我们之前用友盟,感觉它在捕获Android native c++ crash上就不如crashlytics。
A6:不同异常捕获服务,在Java/OC的异常捕获处理基本无差异。但Native方面的实现却各不相同。友盟的Native捕获比crashlytics的要晚一些,基本原理也是注册新号监听。但监听后,线程堆栈回溯的过程相对比较繁琐,没有踩坑的经历,其准确性好不到哪儿去。
过早客微信公众号:guozaoke • 过早客新浪微博:@过早客 • 广告投放合作微信:fullygroup50 鄂ICP备2021016276号-2 • 鄂公网安备42018502001446号