zoukankan      html  css  js  c++  java
  • Breakpad Google的crash捕获、抓取开源库

    简介:

      Breadpad为google chrominum项目下用于处理dump的一套工具;内部采用跨平台方式实现捕获、生成、解析与平台无关的dump,便于统一处理;支持进程内与进程外捕获,当为进程外捕获时,客户端捕获异常并告知服务器端抓取该crash并生成相应dump文件。以下仅针对windows平台下进行分析。

    项目构成:

    Common:公共部分主要有:

      GUIDString:得到唯一的guid符号RFC4122格式

    (%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x)的字符串GUIDToWString,主要用来在MinidumpGenerator中创建生成的dump文件的名称,转化为十六进制大写的不带分隔符的字符串GUIDToSymbolServerWString,主要用来作为symbol服务器ID的标识;

      WindowsStringUtils:字符串转换工具,包括:安全拷贝、多字节与宽字节间的转化、获取文件路径中的文件名称;

      HTTPUpload:一个基于WinInet简单封装的http文件上传类,也包含UTF8与UTF16间的转化,此类用在CrashReportSender中提供上传生成的dump文件(似乎未用到该方式);

    Crash_generation_app:

        一个提供使用示例的demo;测试进程外捕获时需要运行两次该demo,第一个作为服务器,第二次作为客户端,服务器也可以捕获自己的异常crash dump;

    Crash_report_sender:

        崩溃crash报告发送者,内部会使用HTTPUpload上传;

        ReportResult:定义了四种结果状态:

            RESULT_FAILED:连接服务器失败,尝试重试;

            RESULT_REJECTED:发送至服务器成功,但服务器拒绝接收,可不再发送此报告;

            RESULT_SUCCEEDED:发送至服务器成功并接收;

            RESULT_THROTTLED:已到达每天上传的最大报告数;

        checkpoint_file_:报告发送文件检查点文件,主要用来作为一个上传报告的识别标识;

        max_reports_per_day_:每天至多可上传的最大报告数;

        last_sent_date_:最近一次上传报告的时间;格式YYYYMMDD;

        reports_sent_:最近一天得上传报告数目;

        set_max_reports_per_day:设置每天上传的最大报告数目;

        max_reports_per_day:获取当前每天上传的最大报告数目;

        CrashReportSender:构造函数,参数checkpoint_file为检查点文件,并初始化

    max_reports_per_day_值为-1,表示无限制、last_sent_date_值为-1、reports_sent_值为0,此外内部还调用OpenCheckpointFile打开文件和ReadCheckpoint读取到检查点文件的last_sent_date_和reports_sent_值;SendCrashReport:发送crash报告,参数url为指定的服务器地址,parameters为被格式化并将发送的参数信息,dump_file_name为dump文件路径名,report_code为报告请求响应码;

    GetCurrentDate:获取当前日期,内部通过GetSystemTime获取年月日;

    ReportSent:更新检查点文件内容,主要重写回检点点文件(kCheckpointSignature("GBP1 ")、last_sent_date_、reports_sent_);

    总结crash_report_sender:其中的SendCrashReport发送crash报告内部细节为:先获取当前系统时间与文件中读取的比较,若设置了上传上界且达到了上界则不再发送;发送指定的crash文件;重新更新检查点文件内容返回执行结果ReportResult;此外检查点文件格式形如为:

      GBP1

      20151208

      120

    Except_handler:异常捕获器对象,主要用来捕获异常,分为进程外和进程内,进程内可不再需要服务器,进程外需要服务器和客户端并开启服务,此时交由服务器抓取,而客户端则只需要捕获异常并通知服务器来抓取不涉及异常和抓取操作;Except_handler内部针对参数不同执行不同的处理方式,此外服务器也可以捕获自己的异常(只要有Except_handler定义),这样进程内捕获既可以直接使用Except_handler也可以使用服务器但pipe参数设置为NULL即可;

        AppMemory:进程内存区域信息,包含基地址、长度,主要用在保存minidump时用到;

        FilterCallback:任何执行捕获异常前调用的回调函数,可用来过滤、预处理异常信息,该函数返回true则继续进程并导致产生dump文件,否则会忽略该异常,此时若用户需要可以自己再去处理该异常;参数context为回调上下文该参数为Except_handler的构造函数传入的对应参数,exinfo为异常信息,内含异常记录,assertion为断言信息,一般在纯虚函数异常、无效参数异常中用到;

    MinidumpCallback:捕获处理dump后的回调函数,返回值含义同上,参数dump_path为生成dump文件的路径,minidump_id为生成dump文件id,succeeded为是否创建成功;其他参数含义同上;

    HandlerType:捕获类型,包含:

    HANDLER_NONE:捕获任意的异常;

    HANDLER_EXCEPTION:设置SetUnhandledExceptionFilter的异常捕获;

    HANDLER_INVALID_PARAMETER:设置_set_invalid_parameter_handler的异常捕获;

    HANDLER_PURECALL:设置_set_purecall_handler的异常捕获;

    HANDLER_ALL:HANDLER_EXCEPTION、HANDLER_INVALID_PARAMETER、HANDLER_PURECALL;

    ExceptionHandler构造函数:多个重载版本提供外部简单调用的接口,这样可以方便的实现进程内捕获还是进程外捕获便于区分参数传递避免混乱,事实上内部统一调用函数Initialize完成初始化,未提供的参数则使用默认参数;

    Initialize:参数dump_path为生成dump文件路径,filter抓取前滤波器回调函数,callback抓取后回调函数,callback_context传入filter的回调参数,handler_types为将安装的捕获异常类型,dump_type为产生minidump类型;pipe_name为命名管道名称,pipe_handle为命名管道句柄,crash_generation_client为crash生成客户端对象,custom_info为客户端自定义的信息,主要包含客户端信息、软件版本等在进程外捕获模式下会发送给服务器注册时的信息;

    dump_path:获取dump文件路径;

    set_dump_path:设置dump文件路径,内部调用UpdateNextID更新下一个保存dump文件的路径名称和文件名称,文件名称使用_time64获取并转化为格式为"%Y-%m-%d_%H-%M-%S";

    RequestUpload:请求上传某个早期指定的ID的dump文件,用在客户端请求服务器上传某个早期的dump文件;

    WriteMinidump:立即写入minidump文件,一般用在用户独自处理异常时调用的接口,但是该接口适合用在当前线程,此外重置版本提供了一个遍历的接口供外部使用,此时可不需要ExceptionHandler实例即可方便处理异常,参数含义同构造函数;

    WriteMinidumpForException:立即写入minidump文件,用在用户保存自定义的异常信息,也是用在用户独自处理异常时调用;

    WriteMinidumpForChild:立即写入”子”进程的某线程的dump文件,child为某个进程的句柄,child_blamed_thread为改子进程的线程ID,其他参数同构造函数;

    get_requesting_thread_id:获取请求线程ID,该值为WriteMinidump或WriteMinidumpForException的请求线程ID;

    set_handle_debug_exceptions:设置控制EXCEPTION_BREAKPOINT与

    EXCEPTION_SINGLE_STEP异常类型,直接写入dump文件,用在用户自己控制异常的情况;

    IsOutOfProcess:是否为进程外捕获,内部通过获取crash_generation_client_是否为NULL判断是否为进程外捕获;

    RegisterAppMemory:注册保存至dump文件的进程开始基地址和长度;

    UnregisterAppMemory:移除对应的保存至dump文件的进程开始基地址;

    其他私有成员:如设置异常捕获、无效参数、纯虚函数异常、写dump回调、以及其他状态控制变量,不再一一列举;

    总结:ExceptionHandler作为捕获异常类,提供了多次捕获方式,包括进程内捕获、进程外捕获、用户自定义控制捕获、捕获任何异常、捕获无效参数异常、捕获纯虚函数调用异常、用户手动保存dump、用户保存自定义设置的异常并保存dump等;

    重点说明的函数:

    Initialize:初始化操作内部通过参数crash_generation_client、pipe_name、pipe_handle决定是进程内还是进程外捕获,对于进程内捕获,内部通过创建一个专门用于捕获异常、写异常的线程(通过创建两个信号量来实现线程间同步);而对于进程外捕获,将创建一个CrashGenerationClient客户端对象,并将服务器端的必要的参数通过命名管道传回给该客户端,当ExceptionHandler中的HandleException、HandleInvalidParameter、HandlePureVirtualCall捕获到异常时通过该客户端对象的RequestDump方法将异常信号保存到客户端对象,最后通过SignalCrashEventAndWait方法重置服务器端的生成crash事件和crash事件(事实上每个客户端都有一个自己的这两个事件),服务器收到crash事件后保存该客户端保存的异常信号,并设置生成crash事件,完成整个异常捕获、告知、保存、交互的过程;基本上ExceptionHandler就差不多只处理这些工作,其他的操作移交给客户端和服务器端处理,再次说明:捕获进程内异常只需要ExceptionHandler就可以,不需要服务器和客户端;进程外捕获需要客户端和服务器端,另外客户端在其中扮演的角色也比较简单,只是提供捕获通告事件、通告捕获内容、请求服务器上传捕获ID对应dump文件等;

    CrashGenerationClient:客户端,连接服务器、提供异常告知事件、异常捕获内容;

    在ExceptionHandler中创建客户端时,内部执行Register实现注册该客户端到服务器,并构造ProtocolMessage协议消息将客户端必要信息通过命名管道发送给服务器并获取服务器的响应信息(响应信息保护crash事件句柄、crash生成事件句柄、服务器是否存活句柄、服务器进程ID);ExceptionHandler捕获到异常将通过该客户端的接口RequestDump请求服务器抓取,此时没有采用命名管道而是使用事件信号通告;

    CrashGenerationServer:服务器,连接客户端、处理客户端请求、抓取客户端crash并生成dump文件,必要时上传dump文件;构造函数中创建了一个MinidumpGenerator的对象dump_generator_用于保存dump文件,此外服务器封装比较简单,对外只提供了Start接口和pre_fetch_custom_info,Start:开启服务器,监听客户端连接,创建服务器存活句柄、与客户端连接、管道读写用到的事件信号、注册回调事件函数(线程池中),创建命名管道用于与客户端通信,pre_fetch_custom_info:是否预抓取客户进程中自定义内存信息;此外注册的回调事件函数OnPipeConnected内部实现当客户连接请求时,获取到客户信息,并注册客户请求dump回调事件和客户端退出回调事件,保存维护客户列表;

    总结:CrashGenerationServer通过注册OnPipeConnected事件回调实现不同客户端连接时管道通信(包含必要信息相互通告),并内部处理注册客户请求dump回调事件和客户端退出回调事件,此外还有客户请求上传dump(上传请求将调用OnClientUploadRequestCallback回调,服务器需要自己实现上传操作),其他的均采用事件通知的方式而不再是命名管道,减少协议、通信的麻烦;保存dump使用其成员dump_generator_的 WriteMinidump接口,其内部使用ReadProcessMemory读取客户进程下对应的异常信息并调用dbghelp.dll 库中的接口MiniDumpWriteDump保存,具体保存内容、格式,MinidumpGenerator类实现不再详细分析;

    项目总结:

      基本上ExceptionHandler在进程内捕获时采用开启另外一个线程实现捕获抓取,并不再生成客户端和服务器端;进程外捕获时将额外开启服务器进程,此外捕获进程还需要生成客户端;客户端辅助通告服务器连接、请求捕获、请求上传dump;服务器端辅助维护客户端连接、客户端捕获请求、上传请求、dump保存操作;通信基于命名管道、命名管道传递多个事件句柄后期请求捕获通告、客户退出通告将通告事件告知而不再是命名管道,请求上传仍采用管道通知;

      还有其他的工具如ms_symbol_server_converter、dump_syms、symupload暂不分析;其他项目中需要用到的时候仅根据需要结合示例工程Crash_generation_app即可方便使用异常捕获机制,此外可以根据需要设置ExceptionHandler实现自定义捕获的需要。

  • 相关阅读:
    centos安装1
    centos安装
    Yii单表常用语句
    22.2015.08.18第二十三课mvc1,2(mvc环境搭建)
    21.2015.08.13第二十三课ado.net3(增删改查、get传值、post传值、SQL防注入、调存储过程、SQLHELPER)
    20.2015.8.12第二十二课ado.net1,2(增删改查代码)
    17.2015.08.04第十八节课 C#2 (数值类型及调用、引用类型及调用、装拆箱、常量、变量、数据类型转换、算术运算符、赋值运算符、关系运算符、逻辑运算符、字符串的常用方法)
    16、2015.08.03第十七节课 C#1(.net和C#的关系、VS与.net的对应关系、VS2012常用的几种应用程序、C#定义一个类的方法、类页面内容的解释、定义Person的类、调用Person类的方法、命名规范、数值类型)
    sql server 2008 相关错误整理(win7系统)
    刚刚接触的LINQ
  • 原文地址:https://www.cnblogs.com/haomiao/p/5041090.html
Copyright © 2011-2022 走看看