一两个月前为产品写了一个独立的exe,由于产品使用的捕获dump是一个现成的进程外exe,如果以资源的方式集成它容易出现安全警告,由于时间关系没有寻求新的解决方法,还是遵循旧方案,不捕获dump。 最近业余看了会儿breakpad client,想到一个解决方案——其实也蛮简单的,最后exe大概会增加200多KB。下边从头分析。

  有这样一种需求,希望一个进程启动之后,有另一个进程来“守护”它,当它发生crash时,能生成dump,然后把它重启;还有一个要求,“守护”进程跟工作进程必须是在同一个物理文件里,就像chromium一样,它是多进程的,但只有exe文件只有一个。借助breakpad client,这是很容易实现的事情,“守护”进程即是breakpad client中的服务进程,工作进程即是breakpad client中的客户进程。

一、思路

1、dump捕获,基于breakpad client。

2、守护,在breakpad服务进程的客户端crash回调里重启工作进程(不能直接做重启,需要做些简单处理)。

3、一个物理文件多种功能进程,代码都放在一个物理文件里,不同类进程根据命令行参数做区分。

二、需要注意的问题  

1、首先启动的是工作进程,由工作进程启动守护进程,工作进程需要等待守护进程的初始化完毕(主要是用于进程通信的管道)才开始注册异常处理。现在我看到的chromium代码,没有使用进程外dump,所以没有等待逻辑。

2、工作进程没有后退策略,当守护进程被异常结束时,客户进程崩溃就没法处理了,可以考虑在客户进程的crash回调做处理,但这种处理是在crash线程做的,最好是让异常处理的安全线程在进程外dump触发的情况下仍然启动,作为后备策略,demo暂不考虑这特殊情况。 

3、进程crash之后,全局C++对象的析构函数不会被调用。 

4、守护进程在重启工作进程之前,需要等到工作进程已经退出、守护进程的管道已经停止,才能重启。

三、实现

1、工作进程启动守护进程时,加上命令行参数crash_server=XXX,XXX为GUID Event名,守护进程启动之后置位该Event,工作进程等待该Event置位再继续往下执行。

2、crash发生时,守护进程的主线程等待客户进程退出;接着主线程析构crash_server、启动客户进程;接着主线程等待工作线程的dump上传完毕;最后退出主线程。crash没有发生时:守护进程在主线程等待客户进程退出后退出。

3、chromium的crash_service.cc 为防止server进程上传dump时主线程突然退出,做了几个防止措施:(1)、在客户进程退出时,sleep 1000毫秒给dump上传函数执行的机会,然后再给自己发送WM_CLOSE消息;(2)、dump上传函数跟CrashService类的析构函数有临界区锁,当上传函数未执行完毕时,CrashService不会析构,所以主线程也就不会先退出。我写的demo,守护进程没有创建窗口,也不使用WM_CLOSE消息。

4、chromium也有重启机制,可以在breakpad_win.cc中看到,是在客户进程的crash回调中做的。

部分代码:

Process Entry:

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int /*nCmdShow*/)
{
CmdlineParser cmd_parse(lpstrCmdLine);
std::wstring server_start_event_name = cmd_parse.GetValueByKey(L"crash_server");
if (!server_start_event_name.empty())
{
GuardProcess::GuardProcessMain(server_start_event_name);
return ;
}
else
{
WorkProcess::WorkProcessMain(hInstance);
return ;
}
}

Guard process Main Function:

void GuardProcessMain(const std::wstring& server_start_event_name)
{
if (!CrashServerStart(server_start_event_name))
{
return;
} while(!g_client_exit)
{
::Sleep();
}
if (g_restart_client)
{
delete g_crash_server;
g_crash_server = NULL;
wchar_t lpszFileName[MAX_PATH] = {};
::GetModuleFileName(NULL, lpszFileName, MAX_PATH);
std::wstring strFullName = lpszFileName;
::ShellExecute(NULL, L"open", strFullName.c_str(), NULL, NULL, SW_SHOWNORMAL);
}
if (g_uploadover != NULL)
{
DWORD dwRet = ::WaitForSingleObject(g_uploadover, );
if (dwRet != WAIT_OBJECT_0)
{
//error
}
} }

Work Process Main Function:

    void WorkProcessMain(HINSTANCE hInstance)
{
StartServerExe();
AddExceptionCatch(); HRESULT hRes = ::CoInitialize(NULL);
ATLASSERT(SUCCEEDED(hRes));
::DefWindowProc(NULL, , , 0L);
AtlInitCommonControls(ICC_BAR_CLASSES);
hRes = _Module.Init(NULL, hInstance);
ATLASSERT(SUCCEEDED(hRes)); int nRet = ;
{
CMainDlg dlgMain;
nRet = dlgMain.DoModal();
}
_Module.Term();
::CoUninitialize();
}

四、总结

  本demo的主要难点是在细节的考虑上,思路是比较简单的。breakpad的使用极其方便;一个物理文件多个功能进程的思路也很常见。

五、一些基础

  当然就是breakpad client代码了,我做了一些学习分享放在:

《windows下捕获dump》http://www.cnblogs.com/cswuyg/p/3207576.html

《windows下捕获dump之Google breakpad_client的理解》http://www.cnblogs.com/cswuyg/p/3286244.html

  breakpad client的学习代码可从https://github.com/cswuyg/google_breakpad_client下载到。

windows下捕获dump之守护进程的更多相关文章

  1. windows下捕获dump之Google breakpad_client的理解

    breakpad是Google开源的一套跨平台工具,用于dump的处理.很全的一套东西,我这里只简单涉及breakpad客户端,不涉及纯文本符号生成,不涉及dump解析. 一.使用 最简单的是使用进程 ...

  2. windows下捕获dump

         一般要捕获异常只需要两个函数:SetUnhandledExceptionFilter截获异常:MiniDumpWriteDump写dump文件.但是由于CRT函数可能会在内部调用SetUnh ...

  3. windows下捕获dump之Google breakpad_client

    breakpad是Google开源的一套跨平台工具,用于dump的处理.很全的一套东西,我这里只简单涉及breakpad客户端,不涉及纯文本符号生成,不涉及dump解析. 一.使用 最简单的是使用进程 ...

  4. windows下bat批处理实现守护进程

    本文转自网络,由于找不到原作者,因而无法知道出处.如果有幸让原作者看到,请联系我加上.先转载至此. 最近几天加班加疯掉了,天天晚上没法睡.开发部的一个核心程序总是会自己宕机,然后需要手工去起,而这个服 ...

  5. windows下bat批处理实现守护进程(有日志)

    开发部的一个核心程序总是会自己宕机,然后需要手工去起,而这个服务的安全级别又很高,只有我可以操作,搞得我晚上老没法睡,昨晚实在受不了了,想起以前在hp-ux下写的shell守护进程,这回搞个windo ...

  6. Windows下获取Dump文件以及进程下各线程调用栈的方法总结(转)

    1. Dump文件的用途 Dump文件, 主要用于诊断一个进程的运行状态,尤其是碰到崩溃(Crash)或者挂起(hang)不响应时,需要分析它的工作状态.  除了平时常见的attach到这个进程, 分 ...

  7. ASP.NET Core Linux下为 dotnet 创建守护进程(必备知识)

    前言 在上篇文章中介绍了如何在 Docker 容器中部署我们的 asp.net core 应用程序,本篇主要是怎么样为我们在 Linux 或者 macOs 中部署的 dotnet 程序创建一个守护进程 ...

  8. windows下根据端口号杀死进程

    Windows不像Linux,Unix那样,ps -ef 查出端口和进程号,然后根据进程号直接kill进程. Windows根据端口号杀死进程要分三步: 第一步 根据端口号寻找进程号 C:\>n ...

  9. ASP.ENT Core Linux 下 为 donet创建守护进程(转载)

    原文地址:http://www.cnblogs.com/savorboard/p/dotnetcore-supervisor.html 前言 在上篇文章中介绍了如何在 Docker 容器中部署我们的 ...

随机推荐

  1. windows下使用xShell远程连接virtualbox里面的linux

    第一阶段:基本安装 安装virtual box 在virtualbox里面安装xubuntu:是ubuntu+xfce桌面环境的一个linux的发行版本 在windows下安装Xmanager Ent ...

  2. Codeforces Round #279 (Div. 2) E. Restoring Increasing Sequence 二分

    E. Restoring Increasing Sequence time limit per test 1 second memory limit per test 256 megabytes in ...

  3. jQuery的.click,.bind,.unbind,.on,.off,.delegate,.undelegate

    .click与.bind .click和.bind都是给每个元素绑定事件,对于只绑定一个click事件,.bind事件的简写就是.click那种方式. 这两种方式都会出现两个问题: 第一个问题,如果要 ...

  4. bootstrap 固定定位

    <!DOCTYPE html> <html><head><meta charset="UTF-8"><title>Boo ...

  5. pl/sql developer执行光标所在行

    一.发现问题 需要执行某一行语句时,需要选中该行语句,点击F8才行. 二.解决问题 中文版:工具->首选项->SQL窗口->自动选择语句 英文版:tools->preferen ...

  6. C语言下动态库相互调用

    前段时间需要完成多个模块业务,而这些模块的接口都是一样的,于是为了方便管理就把每个模块都根据接口封装成了SO库,这里就留下SO库调用样例 SO库源文件代码: //TestSo.c #include & ...

  7. 转载 uboot 命令

    1.bootm bootm [addr [arg ...]] - boot application image stored in memory passing arguments 'arg ...' ...

  8. cocoapods ,错误大全

    出现这种警告 Your Podfile has had smart quotes sanitised. To avoid issues in the future, you should not us ...

  9. sql中out与output

    --SQLQuery Create By Faywool         create proc Proc_OutPutTest--创建 @numA int,--numA为存储过程的参数 @numB  ...

  10. IE和主流浏览器

    1.添加事件 addEventListener 主流 attachEvent     IE 2.移除事件 removeEventListener detachEvent 3.获取事件对象 event ...