Google Breakpad 之四,客户端设计

E文好的直接移步--》http://code.google.com/p/google-breakpad/wiki/ClientDesign

部分按照自己的理解来说,一部分来自翻译软件,一些和模块相关术语还是用英文比如handler和sender。

Breakpad 客户端库

目标

说白了,就是handler负责产生dump,sender负责上传。因为程序crash时,自己的堆栈被破坏,本身是不安全的,不适合再做其他事情。

打个比方:进程1是crash进程,使用handler,进程2是监控进程,进程1crash时,handler会产生一个minidump,通过管道发送给进程2,进程2此时使用sender发送到服务器。

背景

理解 dump files 有助于理解handler。

概述

Breakpad 提供库包括这些平台 Windows on x86 and Mac OS X on both x86 and PowerPC.  Linux 版的实现正在审查。其实还有android,我发现了代码现在没有深入研究。是不是支持64位程序待研究。

不同操作系统差异较大所以handler的实现也存在差异,多核操作系统会把每个核的信息产生,在不同平台的handler的使用类似。

说在载入某个库的最前面使用handler。

crash或者程序要求时,都能产生dump,后者利于调试断言或查看运行状态。产生dump时会调用设好的回调函数 ,它可以收集程序的信息,退出时调用crash 报告,或执行其它任务。可以灵活运用。

不同平台网络接口不同,所以sender实现不同,dump和程序信息组成的文件通过http发送, 敏感数据可以用HTTPS发送.

在main最前面设好handler和callback,在callback里调用另一进程来上报dump,使用本进程来做是不安全的。

详细设计

异常handler设置

不同平台是不同的实现。Windows平台是注册 top-level exception filter回调函数,类Unix系统如Linux,通过信号来告知异常,所以异常表现为信号handler。Mac OS X需要大量代码设置Mach port,标示异常端口,通过线程来监听此端口。异常handler不同,实现也不同。类Unix系统,异常线程会调用handler,Mac OS X, 线程监听异常端口,不同的异常handler执行的任务是类似的,接口是类似的。

Breakpad handler是一个ExceptionHandler,是 C++写的,ExceptionHandler可以像变量一样,被构造销毁使用和返回,因此开发者可以利用它来监视程序的一部分的crash。 (就像变量一样有作用域,退出本作用域会被销毁)

异常基础

遭遇异常的程序是不确定和危险的。因此,需格外小心,因为此时执行其他操作可能失败,挂起或导致额外的异常。Breakpad尽量详细即便经验少的开发者也可获得一些有用的信息。 通过以下异常安全的指导,可以在异常重现时,确保hander所有的代码得到执行:

  • 禁止使用程序的堆,堆已经被破坏,不可用,allocators堆分配器可能不起作用。
  • 严格禁止资源的分配。handler可能创建了个文件来获取dump,可能执行个过程来处理此文件。
  • 明令禁止执行crash的线程。这个线程只能执行此类代码:必要的来过渡处理一个专用的预先分配handler线程,异常handler返回的代码。
  • Handler们自己不能尝试walk stacks来处理crash,因为stacks可能已经和以前不一致。操作系统的内存管理器和代码模块管理器来产生Dump.
  • 避免包括运行时库在内的库的代码,除非证明符合以上指南。比如:STL的string可能不能用了,因为它是需要在堆上allocate内存的。意味着许多C的库不能用了,尤其是在Windows上,因为可能在操作堆。

异常重现时,handler尽可能让该线程在生成dump期间保持原状态,在转储生成,它很困难甚至不可能对一个线程来准确地捕捉自己的状态。执行另一个独立线程处理异常也是危险的,因为堆栈越界异常可能存在。处理异常时,堆栈溢出是相当危险的。因为可能否决申请资源的请求,Breakpad handler库当他设置handler时会创建自己的线程。Mac OS X,这个处理程序线程被创建在正常设置的异常处理程序,handler线程将标示在一个异常事件上。在Windows和Linux,handler线程发出少量的代码执行异常的线程。因为执行的代码在异常线程在本例中是小和安全,这并不构成问题。甚至当一个异常是由于超过栈大小限制,这段代码非常紧凑的执行完全在堆栈的保护页面没有引发一个异常。

在一个感兴趣的点上,可直接产生dump来分析。 

回调过滤器

当处理程序线程开始处理一个异常,它调用一个可选的用户定义的过滤器回调函数,它负责判断是否应该继续Breakpad的处理程序处理异常。这种机制提供了插件代码的开发人员方便,可能对使用自己模块外的模块crash不感兴趣。如果筛选器回调表明它是不感兴趣的异常,Breakpad处理程序安排送至任何之前安装的handler。
Dump的产生

假设过滤器回调赞同(或不存在),在处理程序被安装时,handler写一个转储在应用程序开发人员指定的目录中,使用以前生成的唯一标识符,以避免名称冲突。不同平台转储生成的机制也不同,但一般来说,这个过程包括列举每个线程的异常,并捕获它的状态,包括处理器上下文和活跃的部分地区的堆栈。转储还包括一个加载到应用程序的代码模块列表,和一个哪个线程生成的异常或请求转储的指示器。转储是写在磁盘上的位置为了避免在这一过程中分配内存。

Dump上传行为

在完成写转储时,第二回调函数被调用。这个回调可能被用于发射一个单独的崩溃报告程序或收集额外的数据从应用程序。这个回调也可以用来影响Breakpad是否会把异常处理过或未处理过。即使在一个转储是成功地生成,Breakpad能表现出好像它实际上并没有处理异常。这个函数可以用于开发人员想要测试他们的应用程序启用Breakpad但仍然保持能够使用传统的调试技术。它还允许应用程序共存Breakpad-enabled与平台的本机崩溃报告系统,如Mac OS X’CrashReporter 和Windows Error Reporting错误报告。
通常,当Breakpad处理异常完全没有调试器参与,崩溃的进程将终止。
在一个Breakpad执行处理程序时两个回调函数都警告说,他们的代码将运行在异常时,因此,他们应该遵守相同Breakpad handler本身坚持的编程审查。值得注意的是,如果一个回调是被用来收集额外的数据从一个应用程序,它应该小心只读“安全的”数据。这可能包括只能访问静态内存位置,定期更新的过程中正常的程序执行。

Sender 库

Breakpad的发送方库提供一个函数来发送一个崩溃报告服务器崩溃。它接受一个接收崩溃的服务器的URL,一个映射的键-值参数,将伴随转储,通往一个转储文件本身。每个键-值参数和多个不同部分dump作为HTTP POST请求使用平台的本地HTTP工具发送到指定的URL。在Linux上,libcurl用于这个功能,因为它是最接近一个标准的HTTP库在该平台。

未来规划

虽然我们已经取得了巨大的成就与进程内的转储生成遵循我们的指南在异常安全时的代码,我们正在探索选项允许转储中生成一个单独的进程,以进一步增强处理程序库的稳健性。


在Windows上,我们打算提供工具来方便Breakpad的设置管理的本地组策略管理系统。

我们还计划提供工具,很多开发人员将找到理想的环境中处理崩溃,比如程序最后终止,一个机制来确定在发送,计算几组超时的崩溃,或发射崩溃应用程序之间的数量。
我们还在研究方法来捕捉事故发生早期应用程序的启动序列,包括崩溃发生在一个程序的main函数前。

你可能感兴趣的:(Google Breakpad 之四,客户端设计)