Android和Ios的crash reporter(崩溃报告采集与上传)

Crash Report,这在大型软件开发领域是很常见的功能,就是能够当程序崩溃退出后,能够将崩溃时的信息,最好是携带dmp文件发送给服务器,这样开发人员既可以获得分发出去的客户端的崩溃率统计,也可以针对出现的错误进行及时的纠正,之前在PC的端游时代,这是很常见的做法,最近进行了在手游上的关于crash report的相关研究,并且为项目编写了一个相对完善的CrashReport模块。

       这个模块的来源于手游项目正式上线,但是很多玩家反馈闪退,但是我们只能听到反馈闪退,却不能找到原因,只能凭脑袋去猜,是不是内存不够,机器配置太差,然后去尽可能优化性能,于是老大开始喊我们需要一个Crash Report, 于是就花2个星期完善了一个可以正式使用的Crash Repoter,项目基于Unity3D,在Android和Ios上做crash report 对我还是第一次,所以还是抱有了极大的兴趣。

1 Android 平台。

其实CrashReport也不应该是只有Crash了才Report,各种错误和潜在会导致Crash的问题也应该report上去。对于基于Unity3D的Android应用来说,自底到上可以分为三层:C++,Java和C#。 android是基于linux的系统,最底下的各种so a库就是C++的部分,android系统本身的相关逻辑则是java,U3D则使用了C#开发逻辑,所以我们采集问题也要从这三块分别着手。

C#

c#的错误很好处理,这层U3D完全封装好了,C#层会出现warning error和exception,在android下这几种情况都不会导致crash,都会被UNITY3d接住,但是我们需要知道并报告给服务器,U3D有接口Application.RegisterLogCallback(),可以让C#层发生上面的问题时被我知道,我们只要写这个callback,然后在里面给服务器就行了。

Java

java层的错误就是各种java exception,对于java,如果对于我们catch了的exception,不会导致crash,会按照我们的catch行为执行,对于那些我们没有catch的exception,是会crash的,还会在adblog上打印出来,我们需要获知这些exception,我们可以采用java中的接口Thread.setDefaultUncaughtExceptionHandler来重新设置这个对未catch的exeption的处理,在我们自己的handler中基本做的事情就是首先把这个exceptio报告给服务器,然后并不让程序退出,让程序尽可能活下去。

C++

C++中出现的问题通常就是很严重的了,这里也分两种,一种是普通的一些异常,这取决于你是否catch了,如果没有catch,默认就是abort的,也就是crash了,还有一些比如对内存的非法访问,就直接在linux中产生了一个结束信号,把进程结束了,也是crash。对于C++我们先后尝试了两种方案,第一种就是采用捕获linux的信号量,程序异常退出总是有信号的,可以使用linux 下的sigaction来设置对这些信号的捕获处理,比如我们捕获了SIGILL SIGABRT SIGFPE SIGSEGV SIGPIPE SIGBUS SIGSTKFLT,这样对于异常的程序退出我们是知道的,可以在下次进入游戏时告知服务器,但是这样做有一个明显的问题就是我们只是知道程序crash了,但是没有trace
back,不知道在哪挂了,我们想要dump文件。于是后来采取的方法就是使用了google的breakpad框架,关于google breakpad,这是它的主页,https://chromium.googlesource.com/breakpad/breakpad/,关于他的基本原理,大家可以去看他的wiki和文档,很长,基本来说它是一个平台无关的C++的crash reporter,可以在crash后,生成dmp文件,然后利用它的一些工具获取堆栈的符号信息。

google breakpad在android的简单集成方法如下:

1.从http://google-breakpad.googlecode.com/svn/trunk拿到源码

2.建立你自己的jni工程

3.将google breakpad的android 和src两个文件夹放到你的工程里

4.配置你的Application.mk,里面要加入

APP_STL := stlport_static
APP_CPPFLAGS := -std=gnu++11 -D__STDC_LIMIT_MACROS 

5.配置你的Android.mk,里面要加入以下的src文件

    google_breakpad/src/client/linux/crash_generation/crash_generation_client.cc \
    google_breakpad/src/client/linux/handler/exception_handler.cc \
    google_breakpad/src/client/linux/handler/minidump_descriptor.cc \
    google_breakpad/src/client/linux/log/log.cc \
    google_breakpad/src/client/linux/dump_writer_common/thread_info.cc \
 google_breakpad/src/client/linux/dump_writer_common/ucontext_reader.cc \
google_breakpad/src/client/linux/microdump_writer/microdump_writer.cc \
    google_breakpad/src/client/linux/minidump_writer/linux_dumper.cc \
    google_breakpad/src/client/linux/minidump_writer/linux_ptrace_dumper.cc \
    google_breakpad/src/client/linux/minidump_writer/minidump_writer.cc \
    google_breakpad/src/client/minidump_file_writer.cc \
    google_breakpad/src/common/android/breakpad_getcontext.S \
    google_breakpad/src/common/convert_UTF.c \
    google_breakpad/src/common/md5.cc \
    google_breakpad/src/common/string_conversion.cc \
    google_breakpad/src/common/linux/elfutils.cc \
    google_breakpad/src/common/linux/file_id.cc \
    google_breakpad/src/common/linux/guid_creator.cc \
    google_breakpad/src/common/linux/linux_libc_support.cc \
    google_breakpad/src/common/linux/memory_mapped_file.cc \
   google_breakpad/src/common/linux/safe_readlink.cc \

还要加入LOCAL_STATIC_LIBRARIES += breakpad_client

以及include google_breakpad/android/google_breakpad/Android.mk

6.在你的crashreport模块初始化中(当然通常也可以在JNI_OnLoad中)初始化google breakpad,

 google_breakpad::MinidumpDescriptor descriptor(path);  
   handler = new google_breakpad::ExceptionHandler(descriptor,  NULL,   NULL,    NULL,   true,    -1);  

这里的path是你手机上存放dmp文件的文件夹,crash发生后,它会在这个文件夹内生成以UUID命名的dmp文件,当然前提你要保证这个文件夹真实存在。

7.最后编出你的so库,给程序使用。

这样我们就通过google breakpad实现了C++层的dump文件生成,当发生后,我们把dump文件传给服务器就行了。

最后关于这个dmp文件的解读,这里大家可以参考这份文档:https://www.chromium.org/developers/decoding-crash-dumps。这个解析要在linux环境下做,没有win的工具,基本就是两步骤,第一步是用工具将dmp的二进制文件转成可以看懂的文本格式,可以看到出错的地址,但是如果要想详细知道这些地址所代表的符号,还需要用里面的一个工具以及带有符号版本的so库才能知道,unity自己的库应该没有这种so库,但是也能大致看出问题处在哪了。

其他

似乎到这里我们能够堵到android上所有可能崩溃的地方,然而并不是。至少有两种情况是还不行的,一是watch dog超时,二是内存资源不足。

watch dog超时:当你的主线程超过一段时间没有相应,android系统会将你的程序退出,内存资源不足:当android系统认为这个程序使用的内存过高时,会选择将这个退出,以释放内存。

这两种情况都是android系统的管理器按照一定的策略调度的,虽然玩家看到闪退了,但是这两种情况逻辑上都不属于异常退出,和你自己退出android进程是一样的,只不过是系统帮你退出了,所以用google breakpad或者信号都不能知道,因为这其实是正常退出,但是对于我们程序设计来说,这是异常。所以从捕获异常退出来说没有办法(当然也许真的有,我不知道,那欢迎大家批评指正),所以对这两种情况我们退而求其次使用当感知到有潜在的退出危险时报告给服务器警告的策略。

对于watch dog 超时,我们在java层开一个新的线程,不断的去探测主线程,当较长时间发现主线程没回应,我们给一个警告给服务器,并带上现在的内存情况,告知服务器这台机器主线程卡住很久了,很可能一会就被系统退出了,但是也可能运气好一会又好了。这种探测的方法我们可以正好用unity的在native层的UnitySendMessage机制,因为这个就是异步的,我们用另一个线程不断的给主线程的Unity用这个发送心跳包,unity收到后回复,很久没回复就是主线程卡住了(原因多了,比如某个逻辑特别特别耗时。。。)

对于内存太高,我们会在程序里定期检测一下内存,当发现使用的内存明显高过我们的设计时发给服务器,比如说我们认为PSS内存超过600M,当然如果有机器每到这个就崩了,那也不是我们的目标机型。在android系统下动态得到系统的总内和当前可用内存可以用activityManager.getMemoryInfo(),获取当前的进程的使用内存的接口可以用activityManager.getProcessMemoryInfo(new int[]{Process.myPid()})

通过这两种策略我们可以预防式的得到这两种情况的一个crash统计。

IOS

    IOS只有C++和C#两层,对于C#来说,和Android是一模一样的,不用多说。

    对于C++这层,我们当然还是可以继续使用google breakpad,因为它是跨平台的,但是其实Unity(至少从4.6开始)为ios已经提供了一个crash report模块,他需要我们将工程生成好后,将Crashreport.h里面的ENABLE_CUSTOM_CRASH_REPORTER设置为1,或者你可以直接在unity安装路径下找到这个文件直接改。这样在c++
crash后,unity会为我们生存crash文件,等下次启动后,可以通过crashreport这个模块访问这些dmp文件,这些dmp文件都是ios上的标准dmp文件,可以使用ios的开发工具symbolicatecrash来查看。unity内置的crash report其实也是采用了第三方的库plcrashreport来实现的,这个库在ios上的应用很多。

  另外对于ios,其实也提供了一个函数NSSetUncaughtExceptionHandler
,用来当那些未捕捉的异常发生时,进入这个处理,可以拦截一些东西,但是一些比如内存访问错误直接就退出了,不会进到这里,另外进到这里之后程序还是会退出,只是让我们可以记录一下,不过有了unity自带的crashreport 这个也就没啥用了。

  还有在unity对ios的c#运行中,在player
setting里面有个对代码的运行优化,选择slow but safe 还是fast but no exception,如果选择前者,所有c#的执行错误都会像脚本一样被catch住,会报c#的exception,如果后者就不会,就直接不catch了,会造成程序退出,但是运行效率是高的,我们通常选择slow but safe。这是mono架构的特性。


通过对ios 和android的崩溃的采集和报告,有助于了解我们程序在用户手中的稳定性和及时改进。

				
时间: 2024-09-12 10:57:32

Android和Ios的crash reporter(崩溃报告采集与上传)的相关文章

ios socket 断点上传-iOS怎么用socket实现大文件断点上传功能,类似于优酷中视频上传?

问题描述 iOS怎么用socket实现大文件断点上传功能,类似于优酷中视频上传? iOS怎么用socket实现大文件断点上传功能,类似于优酷中视频上传?哪位大神给点思路或者相关demo,跪求!!! 解决方案 Android中Socket大文件断点上传Android中Socket大文件断点上传Android中Socket大文件断点上传---------------------- 解决方案二: 一遍这种都是,两边定义好命令, 文件拆分成一块一块的,每一块有一个序号,断点续传就是没上传那块接着传就行了

Android应用开发之使用Socket进行大文件断点上传续传

在Android中上传文件可以采用HTTP方式,也可以采用Socket方式,但是HTTP方式不能上传大文件,这里介绍一种通过Socket方式来进行断点续传的方式,服务端会记录下文件的上传进度,当某一次上传过程意外终止后,下一次可以继续上传,这里用到的其实还是J2SE里的知识. 这个上传程序的原理是:客户端第一次上传时向服务端发送"Content-Length=35;filename=WinRAR_3.90_SC.exe;sourceid="这种格式的字符串,服务端收到后会查找该文件是否

使用Android的OkHttp包实现基于HTTP协议的文件上传下载_Android

OkHttp的HTTP连接基础虽然在使用 OkHttp 发送 HTTP 请求时只需要提供 URL 即可,OkHttp 在实现中需要综合考虑 3 种不同的要素来确定与 HTTP 服务器之间实际建立的 HTTP 连接.这样做的目的是为了达到最佳的性能. 首先第一个考虑的要素是 URL 本身.URL 给出了要访问的资源的路径.比如 URL http://www.baidu.com 所对应的是百度首页的 HTTP 文档.在 URL 中比较重要的部分是访问时使用的模式,即 HTTP 还是 HTTPS.这会

Android仿微信发表说说实现拍照、多图上传功能_Android

本文实例为大家分享了Android仿微信发表说说.心情功能,供大家参考,具体内容如下 既能实现拍照,选图库,多图案上传的案例,目前好多App都有类似微信朋友圈的功能,能过发表说说等附带图片上传.下面的就是实现该功能的过程:大家还没有看过Android Retrofit 2.0框架上传图片解决方案这篇文章,在看今天的就很容易,接在本项目中用到了一个library:photopicker,封装了图片的选择功能,是否选相机,还有选中图片后可以查看图片的功能.   一. 首先:将photopicker到

Android仿微信发表说说实现拍照、多图上传功能

本文实例为大家分享了Android仿微信发表说说.心情功能,供大家参考,具体内容如下 既能实现拍照,选图库,多图案上传的案例,目前好多App都有类似微信朋友圈的功能,能过发表说说等附带图片上传.下面的就是实现该功能的过程:大家还没有看过Android Retrofit 2.0框架上传图片解决方案这篇文章,在看今天的就很容易,接在本项目中用到了一个library:photopicker,封装了图片的选择功能,是否选相机,还有选中图片后可以查看图片的功能. 一. 首先:将photopicker到工程

使用Android的OkHttp包实现基于HTTP协议的文件上传下载

OkHttp的HTTP连接基础 虽然在使用 OkHttp 发送 HTTP 请求时只需要提供 URL 即可,OkHttp 在实现中需要综合考虑 3 种不同的要素来确定与 HTTP 服务器之间实际建立的 HTTP 连接.这样做的目的是为了达到最佳的性能. 首先第一个考虑的要素是 URL 本身.URL 给出了要访问的资源的路径.比如 URL http://www.baidu.com 所对应的是百度首页的 HTTP 文档.在 URL 中比较重要的部分是访问时使用的模式,即 HTTP 还是 HTTPS.这

iOS《人人》更新 一次可上传多张照片

<人人>是一款实名制的校友录,在微博.微信没有兴起之时一直是在校学生的最爱.4月7日<人人>再一次修复了软件中客户端音乐停止播放等bug,并对产品进行了进一步更新.<人人>批量上传照片<人人>之前上传照片一直是单张上传模式,此次对于照片的上传进行了更新,一次最多可上传9张照片,点击选中.再次点击就是取消.选择上传相册的地方实在 照片编辑页面,系统默认为手机相册.<人人>特别关注好友动态在人人网中早就特意单设了特别关注好友的新鲜事提醒,此次更新中,

在 Android 上通过模拟 HTTP multipart/form-data 请求协议信息实现图片上传

通过构造基于 HTTP 协议的传输内容实现图片自动上传到服务器功能 .如果自己编码构造 HTTP 协议,那么编写的代码质量肯定不高,建议模仿 HttpClient .zip examples\mime\ClientMultipartFormPost.java 来实现,并通过源码来进一步理解如何优雅高效地构造 HTTP 协议传输内容.   自己构造 HTTP 协议传输内容的想法,从何而来呢?灵感启迪于这篇博文"Android下的应用编程--用HTTP协议实现文件上传功能 ",以前从未想过

符号化你的iOS崩溃报告

前言 本文翻译自Symbolicating Your iOS Crash Reports.这是一篇对于iOS崩溃报告符号化的比较全面的文章.我对Symbolicatecrash工具做了比较完善的封装,一句话就可以符号化你的崩溃报告,还集成了检查UUID匹配的功能. sh symbolicate.sh Crasher.crash Example/Crasher.app > Crasher_Symbolicated.crash 或者 sh symbolicate.sh Crasher.crash E