chromium工程代码走读-子进程的创建和子进程的实现---type=crashpad-handler

前言

工程编译好了,修改了winMain函数入口点代码。使之可以弹框打印出ppid/pid/command_line.
启动工程后,遇到弹框,遇到主进程或感兴趣的子进程,附加上去单步观摩代码实现。
chromium工程启动后,首先会启动一个崩溃信息处理程序. 先观摩了这个子进程的创建和子进程的实现。
chromium代码封装的层次挺深的,先看个大概。
chromium的修改都在vs2017中进行。
chromium的编译在cmd中运行
“Z:\chromium\src>autoninja -C out\Default_68_0_3440_84 chrome”
调试和单步用附加弹框的chrome.exe进行

入口代码点的修改

修改点: Z:\chromium\src\chrome\app\chrome_exe_main_win.cc

头文件包含要修改

// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <windows.h>
#include <malloc.h>
#include <stddef.h>
#include <tchar.h>

#include <algorithm>
#include <string>

#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/strings/string16.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "base/win/registry.h"
#include "base/win/win_util.h"
#include "base/win/windows_version.h"
#include "base/process/process_handle.h" // add by ls
#include "chrome/app/main_dll_loader_win.h"
#include "chrome/browser/policy/policy_path_parser.h"
#include "chrome/browser/win/chrome_process_finder.h"
#include "chrome/common/chrome_paths_internal.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/install_static/initialize_from_primary_module.h"
#include "chrome/install_static/install_util.h"
#include "chrome/install_static/user_data_dir.h"
#include "chrome_elf/chrome_elf_main.h"
#include "components/crash/content/app/crash_switches.h"
#include "components/crash/content/app/crashpad.h"
#include "components/crash/content/app/fallback_crash_handling_win.h"
#include "components/crash/content/app/run_as_crashpad_handler_win.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/result_codes.h"

winMain函数的修改

#if !defined(WIN_CONSOLE_APP)
int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prev, wchar_t*, int) {
#else
int main() {
  HINSTANCE instance = GetModuleHandle(nullptr);
#endif

  base::ProcessId my_ppid = base::GetParentProcessId(base::GetCurrentProcessHandle());
  base::ProcessId my_pid = base::GetCurrentProcId();
  DWORD my_mb_style = MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL | MB_APPLMODAL | MB_TOPMOST;

  // 为了抢在建立崩溃处理子进程之前调试
  if (1) {
      wchar_t sz_buf[1024] = { L'\0' };
      memset(sz_buf, 0, sizeof(wchar_t) * 1024);
      wsprintf(sz_buf, L"[ppid/pid] = [%d/%d]", my_ppid, my_pid);
      MessageBox(NULL, sz_buf, L"new chromium entry wWinMain", my_mb_style);
  }

  install_static::InitializeFromPrimaryModule();
  SignalInitializeCrashReporting(); // create sub process : --type=crashpad-handler

  // Initialize the CommandLine singleton from the environment.
  base::CommandLine::Init(0, nullptr);
  const base::CommandLine* command_line =
      base::CommandLine::ForCurrentProcess();

  // show pocess's ppid/pid/command_line
  if (NULL != command_line) {
    // StringType GetArgumentsString()
    // 如果没有命令行参数的chromium进程,就是主进程
    base::CommandLine::StringType str_cmd_line = command_line->GetArgumentsString();
    int len = str_cmd_line.size();
    wchar_t* psz_buf = new wchar_t[len + 4096];
    if (NULL != psz_buf) {
      memset(psz_buf, 0, sizeof(wchar_t) * (len + 4096));
      wsprintf(psz_buf, L"ppid/pid/cmd_line => %d/%d/[%s]", my_ppid, my_pid, str_cmd_line.c_str());
      MessageBox(NULL, psz_buf, L"new chromium entry - command_line", my_mb_style);
      delete[] psz_buf;
      psz_buf = NULL;
    }
    else {
        MessageBox(NULL, L"failed new memory", L"new chromium entry", my_mb_style);
    }
  }
  else {
      // print pid
        wchar_t sz_buf[1024] = { L'\0' };
        memset(sz_buf, 0, sizeof(wchar_t) * 1024);
        wsprintf(sz_buf, L"[ppid/pid] = [%d/%d]", my_ppid, my_pid);
        MessageBox(NULL, sz_buf, L"new chromium entry", my_mb_style);
  }

  const std::string process_type =
      command_line->GetSwitchValueASCII(switches::kProcessType);

  // Confirm that an explicit prefetch profile is used for all process types
  // except for the browser process. Any new process type will have to assign
  // itself a prefetch id. See kPrefetchArgument* constants in
  // content_switches.cc for details.
  DCHECK(process_type.empty() ||
         HasValidWindowsPrefetchArgument(*command_line));

  if (process_type == crash_reporter::switches::kCrashpadHandler) {
    crash_reporter::SetupFallbackCrashHandling(*command_line);

    // The handler process must always be passed the user data dir on the
    // command line.
    DCHECK(command_line->HasSwitch(switches::kUserDataDir));

    base::FilePath user_data_dir =
        command_line->GetSwitchValuePath(switches::kUserDataDir);
    return crash_reporter::RunAsCrashpadHandler(
        *base::CommandLine::ForCurrentProcess(), user_data_dir,
        switches::kProcessType, switches::kUserDataDir);
  } else if (process_type == crash_reporter::switches::kFallbackCrashHandler) {
    return RunFallbackCrashHandler(*command_line);
  }

  const base::TimeTicks exe_entry_point_ticks = base::TimeTicks::Now();

  // Signal Chrome Elf that Chrome has begun to start.
  SignalChromeElf();

  // The exit manager is in charge of calling the dtors of singletons.
  base::AtExitManager exit_manager;

  base::win::EnableHighDPISupport();

  if (AttemptFastNotify(*command_line))
    return 0;

  RemoveAppCompatFlagsEntry();

  // Load and launch the chrome dll. *Everything* happens inside.
  VLOG(1) << "About to load main DLL.";
  MainDllLoader* loader = MakeMainDllLoader();
  int rc = loader->Launch(instance, exe_entry_point_ticks);
  loader->RelaunchChromeBrowserWithNewCommandLineIfNeeded();
  delete loader;
  return rc;
}

子进程的创建–type=crashpad-handler

wWinMain()

install_static::InitializeFromPrimaryModule();
SignalInitializeCrashReporting(); // create sub process : –type=crashpad-handler

崩溃报告子进程的实现(子进程的创建和子进程的实现)在Z:\chromium\src\third_party\crashpad\crashpad\client\crashpad_client_win.cc

// This function is a temporary workaround for https://crbug.com/655788. We
// need to come up with a better way to initialize crash reporting that can
// happen inside DllMain().
void SignalInitializeCrashReporting() {
  if (!elf_crash::InitializeCrashReporting()) { // create sub process
#ifdef _DEBUG
    assert(false);
#endif  // _DEBUG
  }
}
namespace elf_crash {

// NOTE: This function will be called from DllMain during DLL_PROCESS_ATTACH
// (while we have the loader lock), so do not misbehave.
bool InitializeCrashReporting() {
#ifdef _DEBUG
  assert(g_crash_reports == nullptr);
  assert(g_set_unhandled_exception_filter == nullptr);
#endif  // _DEBUG

  // No global objects with destructors, so using global pointers.
  // DllMain on detach will clean these up.
  g_crash_reports = new std::vector<crash_reporter::Report>;
  g_set_unhandled_exception_filter = new elf_hook::IATHook();

  ChromeCrashReporterClient::InitializeCrashReportingForProcess(); // create sub process

  g_crash_helper_enabled = true;
  return true;
}
#if !defined(NACL_WIN64)
// static
void ChromeCrashReporterClient::InitializeCrashReportingForProcess() {
  static ChromeCrashReporterClient* instance = nullptr;
  if (instance)
    return;

  instance = new ChromeCrashReporterClient();
  ANNOTATE_LEAKING_OBJECT_PTR(instance);

  std::wstring process_type = install_static::GetSwitchValueFromCommandLine(
      ::GetCommandLine(), install_static::kProcessType);
  // Don't set up Crashpad crash reporting in the Crashpad handler itself, nor
  // in the fallback crash handler for the Crashpad handler process.
  if (process_type != install_static::kCrashpadHandler &&
      process_type != install_static::kFallbackHandler) {
    crash_reporter::SetCrashReporterClient(instance);

    std::wstring user_data_dir;
    if (process_type.empty())
      install_static::GetUserDataDirectory(&user_data_dir, nullptr);

    crash_reporter::InitializeCrashpadWithEmbeddedHandler(
        process_type.empty(), install_static::UTF16ToUTF8(process_type),
        install_static::UTF16ToUTF8(user_data_dir), base::FilePath());
  }
}
#endif  // !defined(NACL_WIN64)
#if defined(OS_WIN)
void InitializeCrashpadWithEmbeddedHandler(bool initial_client,
                                           const std::string& process_type,
                                           const std::string& user_data_dir,
                                           const base::FilePath& exe_path) {
  // create sub process
  InitializeCrashpadImpl(initial_client, process_type, user_data_dir, exe_path,
                         true);
}
#endif  // OS_WIN
void InitializeCrashpadImpl(bool initial_client,
                            const std::string& process_type,
                            const std::string& user_data_dir,
                            const base::FilePath& exe_path,
                            bool embedded_handler) {
  static bool initialized = false;
  DCHECK(!initialized);
  initialized = true;

  const bool browser_process = process_type.empty();
  CrashReporterClient* crash_reporter_client = GetCrashReporterClient();

  if (initial_client) {
#if defined(OS_MACOSX)
    // "relauncher" is hard-coded because it's a Chrome --type, but this
    // component can't see Chrome's switches. This is only used for argument
    // sanitization.
    DCHECK(browser_process || process_type == "relauncher");
#elif defined(OS_WIN)
    // "Chrome Installer" is the name historically used for installer binaries
    // as processed by the backend.
    DCHECK(browser_process || process_type == "Chrome Installer" ||
           process_type == "notification-helper");
#elif defined(OS_LINUX) || defined(OS_ANDROID)
    DCHECK(browser_process);
#else
#error Port.
#endif  // OS_MACOSX
  } else {
    DCHECK(!browser_process);
  }

  // database_path is only valid in the browser process.
  // create sub process
  base::FilePath database_path = internal::PlatformCrashpadInitialization(
      initial_client, browser_process, embedded_handler, user_data_dir,
      exe_path);
base::FilePath PlatformCrashpadInitialization(bool initial_client,
                                              bool browser_process,
                                              bool embedded_handler,
                                              const std::string& user_data_dir,
                                              const base::FilePath& exe_path) {
  base::FilePath database_path;  // Only valid in the browser process.
  base::FilePath metrics_path;  // Only valid in the browser process.

  const char kPipeNameVar[] = "CHROME_CRASHPAD_PIPE_NAME";
  const char kServerUrlVar[] = "CHROME_CRASHPAD_SERVER_URL";
  std::unique_ptr<base::Environment> env(base::Environment::Create());
  if (initial_client) {
    CrashReporterClient* crash_reporter_client = GetCrashReporterClient();

    base::string16 database_path_str;
    if (crash_reporter_client->GetCrashDumpLocation(&database_path_str))
      database_path = base::FilePath(database_path_str);

    base::string16 metrics_path_str;
    if (crash_reporter_client->GetCrashMetricsLocation(&metrics_path_str)) {
      metrics_path = base::FilePath(metrics_path_str);
      CHECK(base::CreateDirectoryAndGetError(metrics_path, nullptr));
    }

    std::map<std::string, std::string> process_annotations;
    GetPlatformCrashpadAnnotations(&process_annotations);

#if defined(GOOGLE_CHROME_BUILD)
    std::string url = "https://clients2.google.com/cr/report";
#else
    std::string url;
#endif

    // Allow the crash server to be overridden for testing. If the variable
    // isn't present in the environment then the default URL will remain.
    env->GetVar(kServerUrlVar, &url);

    base::FilePath exe_file(exe_path);
    if (exe_file.empty()) {
      wchar_t exe_file_path[MAX_PATH] = {};
      CHECK(::GetModuleFileName(nullptr, exe_file_path,
                                arraysize(exe_file_path)));

      exe_file = base::FilePath(exe_file_path);
    }

    if (crash_reporter_client->GetShouldDumpLargerDumps()) {
      const uint32_t kIndirectMemoryLimit = 4 * 1024 * 1024;
      crashpad::CrashpadInfo::GetCrashpadInfo()
          ->set_gather_indirectly_referenced_memory(
              crashpad::TriState::kEnabled, kIndirectMemoryLimit);
    }

    // If the handler is embedded in the binary (e.g. chrome, setup), we
    // reinvoke it with --type=crashpad-handler. Otherwise, we use the
    // standalone crashpad_handler.exe (for tests, etc.).
    std::vector<std::string> start_arguments;
    if (embedded_handler) {
      start_arguments.push_back(std::string("--type=") +
                                switches::kCrashpadHandler);
      if (!user_data_dir.empty()) {
        start_arguments.push_back(std::string("--user-data-dir=") +
                                  user_data_dir);
      }
      // The prefetch argument added here has to be documented in
      // chrome_switches.cc, below the kPrefetchArgument* constants. A constant
      // can't be used here because crashpad can't depend on Chrome.
      start_arguments.push_back("/prefetch:7");
    } else {
      base::FilePath exe_dir = exe_file.DirName();
      exe_file = exe_dir.Append(FILE_PATH_LITERAL("crashpad_handler.exe"));
    }

    std::vector<std::string> arguments(start_arguments);

    if (crash_reporter_client->ShouldMonitorCrashHandlerExpensively()) {
      arguments.push_back("--monitor-self");
      for (const std::string& start_argument : start_arguments) {
        arguments.push_back(std::string("--monitor-self-argument=") +
                            start_argument);
      }
    }

    // Set up --monitor-self-annotation even in the absence of --monitor-self so
    // that minidumps produced by Crashpad's generate_dump tool will contain
    // these annotations.
    arguments.push_back(std::string("--monitor-self-annotation=ptype=") +
                        switches::kCrashpadHandler);

    // create sub process
    GetCrashpadClient().StartHandler(exe_file, database_path, metrics_path, url,
                                     process_annotations, arguments, false,
                                     false);
bool CrashpadClient::StartHandler(
    const base::FilePath& handler,
    const base::FilePath& database,
    const base::FilePath& metrics_dir,
    const std::string& url,
    const std::map<std::string, std::string>& annotations,
    const std::vector<std::string>& arguments,
    bool restartable,
    bool asynchronous_start) {
  DCHECK(ipc_pipe_.empty());

  // Both the pipe and the signalling events have to be created on the main
  // thread (not the spawning thread) so that they're valid after we return from
  // this function.
  ScopedFileHANDLE ipc_pipe_handle;
  CreatePipe(&ipc_pipe_, &ipc_pipe_handle);

  SECURITY_ATTRIBUTES security_attributes = {0};
  security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  security_attributes.bInheritHandle = true;

  g_signal_exception =
      CreateEvent(&security_attributes, false /* auto reset */, false, nullptr);
  g_signal_non_crash_dump =
      CreateEvent(&security_attributes, false /* auto reset */, false, nullptr);
  g_non_crash_dump_done =
      CreateEvent(&security_attributes, false /* auto reset */, false, nullptr);

  CommonInProcessInitialization();

  RegisterHandlers();

  auto data = new BackgroundHandlerStartThreadData(handler,
                                                   database,
                                                   metrics_dir,
                                                   url,
                                                   annotations,
                                                   arguments,
                                                   ipc_pipe_,
                                                   std::move(ipc_pipe_handle));

  if (asynchronous_start) {
    // It is important that the current thread not be synchronized with the
    // thread that is created here. StartHandler() needs to be callable inside a
    // DllMain(). In that case, the background thread will not start until the
    // current DllMain() completes, which would cause deadlock if it was waited
    // upon.
    handler_start_thread_.reset(CreateThread(nullptr,
                                             0,
                                             &BackgroundHandlerStartThreadProc,
                                             reinterpret_cast<void*>(data),
                                             0,
                                             nullptr));
    if (!handler_start_thread_.is_valid()) {
      PLOG(ERROR) << "CreateThread";
      SetHandlerStartupState(StartupState::kFailed);
      return false;
    }

    // In asynchronous mode, we can't report on the overall success or failure
    // of initialization at this point.
    return true;
  } else {
  // start sub process
    return StartHandlerProcess(
        std::unique_ptr<BackgroundHandlerStartThreadData>(data));
  }
}
bool StartHandlerProcess(
    std::unique_ptr<BackgroundHandlerStartThreadData> data) {
  ScopedCallSetHandlerStartupState scoped_startup_state_caller;

  std::wstring command_line;
  AppendCommandLineArgument(data->handler.value(), &command_line);
  for (const std::string& argument : data->arguments) {
    AppendCommandLineArgument(base::UTF8ToUTF16(argument), &command_line);
  }
  if (!data->database.value().empty()) {
    AppendCommandLineArgument(
        FormatArgumentString("database", data->database.value()),
        &command_line);
  }
  if (!data->metrics_dir.value().empty()) {
    AppendCommandLineArgument(
        FormatArgumentString("metrics-dir", data->metrics_dir.value()),
        &command_line);
  }
  if (!data->url.empty()) {
    AppendCommandLineArgument(
        FormatArgumentString("url", base::UTF8ToUTF16(data->url)),
        &command_line);
  }
  for (const auto& kv : data->annotations) {
    AppendCommandLineArgument(
        FormatArgumentString("annotation",
                             base::UTF8ToUTF16(kv.first + '=' + kv.second)),
        &command_line);
  }

  ScopedKernelHANDLE this_process(
      OpenProcess(kXPProcessAllAccess, true, GetCurrentProcessId()));
  if (!this_process.is_valid()) {
    PLOG(ERROR) << "OpenProcess";
    return false;
  }

  InitialClientData initial_client_data(
      g_signal_exception,
      g_signal_non_crash_dump,
      g_non_crash_dump_done,
      data->ipc_pipe_handle.get(),
      this_process.get(),
      FromPointerCast<WinVMAddress>(&g_crash_exception_information),
      FromPointerCast<WinVMAddress>(&g_non_crash_exception_information),
      FromPointerCast<WinVMAddress>(&g_critical_section_with_debug_info));
  AppendCommandLineArgument(
      base::UTF8ToUTF16(std::string("--initial-client-data=") +
                        initial_client_data.StringRepresentation()),
      &command_line);

  BOOL rv;
  DWORD creation_flags;
  STARTUPINFOEX startup_info = {};
  startup_info.StartupInfo.dwFlags = STARTF_USESTDHANDLES;
  startup_info.StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
  startup_info.StartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
  startup_info.StartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);

  std::vector<HANDLE> handle_list;
  std::unique_ptr<uint8_t[]> proc_thread_attribute_list_storage;
  ScopedProcThreadAttributeList proc_thread_attribute_list_owner;

  static const auto initialize_proc_thread_attribute_list =
      GET_FUNCTION(L"kernel32.dll", ::InitializeProcThreadAttributeList);
  static const auto update_proc_thread_attribute =
      initialize_proc_thread_attribute_list
          ? GET_FUNCTION(L"kernel32.dll", ::UpdateProcThreadAttribute)
          : nullptr;
  if (!initialize_proc_thread_attribute_list || !update_proc_thread_attribute) {
    // The OS doesn’t allow handle inheritance to be restricted, so the handler
    // will inherit every inheritable handle.
    creation_flags = 0;
    startup_info.StartupInfo.cb = sizeof(startup_info.StartupInfo);
  } else {
    // Restrict handle inheritance to just those needed in the handler.

    creation_flags = EXTENDED_STARTUPINFO_PRESENT;
    startup_info.StartupInfo.cb = sizeof(startup_info);
    SIZE_T size;
    rv = initialize_proc_thread_attribute_list(nullptr, 1, 0, &size);
    if (rv) {
      LOG(ERROR) << "InitializeProcThreadAttributeList (size) succeeded, "
                    "expected failure";
      return false;
    } else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
      PLOG(ERROR) << "InitializeProcThreadAttributeList (size)";
      return false;
    }

    proc_thread_attribute_list_storage.reset(new uint8_t[size]);
    startup_info.lpAttributeList =
        reinterpret_cast<PPROC_THREAD_ATTRIBUTE_LIST>(
            proc_thread_attribute_list_storage.get());
    rv = initialize_proc_thread_attribute_list(
        startup_info.lpAttributeList, 1, 0, &size);
    if (!rv) {
      PLOG(ERROR) << "InitializeProcThreadAttributeList";
      return false;
    }
    proc_thread_attribute_list_owner.reset(startup_info.lpAttributeList);

    handle_list.reserve(8);
    handle_list.push_back(g_signal_exception);
    handle_list.push_back(g_signal_non_crash_dump);
    handle_list.push_back(g_non_crash_dump_done);
    handle_list.push_back(data->ipc_pipe_handle.get());
    handle_list.push_back(this_process.get());
    AddHandleToListIfValidAndInheritable(&handle_list,
                                         startup_info.StartupInfo.hStdInput);
    AddHandleToListIfValidAndInheritable(&handle_list,
                                         startup_info.StartupInfo.hStdOutput);
    AddHandleToListIfValidAndInheritable(&handle_list,
                                         startup_info.StartupInfo.hStdError);
    rv = update_proc_thread_attribute(
        startup_info.lpAttributeList,
        0,
        PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
        &handle_list[0],
        handle_list.size() * sizeof(handle_list[0]),
        nullptr,
        nullptr);
    if (!rv) {
      PLOG(ERROR) << "UpdateProcThreadAttribute";
      return false;
    }
  }

  PROCESS_INFORMATION process_info;
  // create sub process
  rv = CreateProcess(data->handler.value().c_str(),
                     &command_line[0],
                     nullptr,
                     nullptr,
                     true,
                     creation_flags,
                     nullptr,
                     nullptr,
                     &startup_info.StartupInfo,
                     &process_info);

子进程的实现

wWinMain()

得到process_type = “crashpad-handler”

  const std::string process_type =
      command_line->GetSwitchValueASCII(switches::kProcessType);

无限等待要检测的进程结束,然后崩溃处理子进程就退出了

  if (process_type == crash_reporter::switches::kCrashpadHandler) {
    crash_reporter::SetupFallbackCrashHandling(*command_line);

    // The handler process must always be passed the user data dir on the
    // command line.
    DCHECK(command_line->HasSwitch(switches::kUserDataDir));

    base::FilePath user_data_dir =
        command_line->GetSwitchValuePath(switches::kUserDataDir);
    // 进入一个循环,死等目标进程结束
    return crash_reporter::RunAsCrashpadHandler(
        *base::CommandLine::ForCurrentProcess(), user_data_dir,
        switches::kProcessType, switches::kUserDataDir);
  } else if (process_type == crash_reporter::switches::kFallbackCrashHandler) {
    return RunFallbackCrashHandler(*command_line);
  }
int RunAsCrashpadHandler(const base::CommandLine& command_line,
                         const base::FilePath& user_data_dir,
                         const char* process_type_switch,
                         const char* user_data_dir_switch) {
  // Make sure this process terminates on OOM in the same mode as other Chrome
  // processes.
  base::EnableTerminationOnOutOfMemory();

  // If the handler is started with --monitor-self, it'll need a ptype
  // annotation set. It'll normally set one itself by being invoked with
  // --monitor-self-annotation=ptype=crashpad-handler, but that leaves a window
  // during self-monitoring initialization when the ptype is not set at all, so
  // provide one here.
  const std::string process_type =
      command_line.GetSwitchValueASCII(process_type_switch);
  if (!process_type.empty()) {
    crashpad::SimpleStringDictionary* annotations =
        new crashpad::SimpleStringDictionary();
    annotations->SetKeyValue("ptype", process_type.c_str());
    crashpad::CrashpadInfo* crashpad_info =
        crashpad::CrashpadInfo::GetCrashpadInfo();
    DCHECK(!crashpad_info->simple_annotations());
    crashpad_info->set_simple_annotations(annotations);
  }

  std::vector<base::string16> argv = command_line.argv();
  const base::string16 process_type_arg_prefix =
      base::string16(L"--") + base::UTF8ToUTF16(process_type_switch) + L"=";
  const base::string16 user_data_dir_arg_prefix =
      base::string16(L"--") + base::UTF8ToUTF16(user_data_dir_switch) + L"=";
  argv.erase(
      std::remove_if(argv.begin(), argv.end(),
                     [&process_type_arg_prefix,
                      &user_data_dir_arg_prefix](const base::string16& str) {
                       return base::StartsWith(str, process_type_arg_prefix,
                                               base::CompareCase::SENSITIVE) ||
                              base::StartsWith(str, user_data_dir_arg_prefix,
                                               base::CompareCase::SENSITIVE) ||
                              (!str.empty() && str[0] == L'/');
                     }),
      argv.end());

  std::unique_ptr<char* []> argv_as_utf8(new char*[argv.size() + 1]);
  std::vector<std::string> storage;
  storage.reserve(argv.size());
  for (size_t i = 0; i < argv.size(); ++i) {
    storage.push_back(base::UTF16ToUTF8(argv[i]));
    argv_as_utf8[i] = &storage[i][0];
  }
  argv_as_utf8[argv.size()] = nullptr;
  argv.clear();

  crashpad::UserStreamDataSources user_stream_data_sources;
  // Interpret an empty user data directory as a missing value.
  if (!user_data_dir.empty()) {
    // Register an extension to collect stability information. The extension
    // will be invoked for any registered process' crashes, but information only
    // exists for instrumented browser processes.
    user_stream_data_sources.push_back(
        std::make_unique<browser_watcher::StabilityReportUserStreamDataSource>(
            user_data_dir));
  }

    // 死等目标进程结束
  return crashpad::HandlerMain(static_cast<int>(storage.size()),
                               argv_as_utf8.get(), &user_stream_data_sources);
}

崩溃处理子进程也启动了一个子进程,用途未知,没有去跟了。

int HandlerMain(int argc,
                char* argv[],
                const UserStreamDataSources* user_stream_sources) {
  InstallCrashHandler();
  CallMetricsRecordNormalExit metrics_record_normal_exit;

  const base::FilePath argv0(
      ToolSupport::CommandLineArgumentToFilePathStringType(argv[0]));
  const base::FilePath me(argv0.BaseName());

  enum OptionFlags {
    // Long options without short equivalents.
    kOptionLastChar = 255,
    kOptionAnnotation,
    kOptionDatabase,
#if defined(OS_MACOSX)
    kOptionHandshakeFD,
#endif  // OS_MACOSX
#if defined(OS_WIN)
    kOptionInitialClientData,
#endif  // OS_WIN
#if defined(OS_MACOSX)
    kOptionMachService,
#endif  // OS_MACOSX
    kOptionMetrics,
    kOptionMonitorSelf,
    kOptionMonitorSelfAnnotation,
    kOptionMonitorSelfArgument,
    kOptionNoIdentifyClientViaUrl,
    kOptionNoPeriodicTasks,
    kOptionNoRateLimit,
    kOptionNoUploadGzip,
#if defined(OS_WIN)
    kOptionPipeName,
#endif  // OS_WIN
#if defined(OS_MACOSX)
    kOptionResetOwnCrashExceptionPortToSystemDefault,
#endif  // OS_MACOSX
#if defined(OS_LINUX) || defined(OS_ANDROID)
    kOptionTraceParentWithException,
    kOptionInitialClientFD,
#endif
    kOptionURL,

    // Standard options.
    kOptionHelp = -2,
    kOptionVersion = -3,
  };

  static constexpr option long_options[] = {
    {"annotation", required_argument, nullptr, kOptionAnnotation},
    {"database", required_argument, nullptr, kOptionDatabase},
#if defined(OS_MACOSX)
    {"handshake-fd", required_argument, nullptr, kOptionHandshakeFD},
#endif  // OS_MACOSX
#if defined(OS_WIN)
    {"initial-client-data",
     required_argument,
     nullptr,
     kOptionInitialClientData},
#endif  // OS_MACOSX
#if defined(OS_MACOSX)
    {"mach-service", required_argument, nullptr, kOptionMachService},
#endif  // OS_MACOSX
    {"metrics-dir", required_argument, nullptr, kOptionMetrics},
    {"monitor-self", no_argument, nullptr, kOptionMonitorSelf},
    {"monitor-self-annotation",
     required_argument,
     nullptr,
     kOptionMonitorSelfAnnotation},
    {"monitor-self-argument",
     required_argument,
     nullptr,
     kOptionMonitorSelfArgument},
    {"no-identify-client-via-url",
     no_argument,
     nullptr,
     kOptionNoIdentifyClientViaUrl},
    {"no-periodic-tasks", no_argument, nullptr, kOptionNoPeriodicTasks},
    {"no-rate-limit", no_argument, nullptr, kOptionNoRateLimit},
    {"no-upload-gzip", no_argument, nullptr, kOptionNoUploadGzip},
#if defined(OS_WIN)
    {"pipe-name", required_argument, nullptr, kOptionPipeName},
#endif  // OS_WIN
#if defined(OS_MACOSX)
    {"reset-own-crash-exception-port-to-system-default",
     no_argument,
     nullptr,
     kOptionResetOwnCrashExceptionPortToSystemDefault},
#endif  // OS_MACOSX
#if defined(OS_LINUX) || defined(OS_ANDROID)
    {"trace-parent-with-exception",
     required_argument,
     nullptr,
     kOptionTraceParentWithException},
    {"initial-client-fd", required_argument, nullptr, kOptionInitialClientFD},
#endif  // OS_LINUX || OS_ANDROID
    {"url", required_argument, nullptr, kOptionURL},
    {"help", no_argument, nullptr, kOptionHelp},
    {"version", no_argument, nullptr, kOptionVersion},
    {nullptr, 0, nullptr, 0},
  };

  Options options = {};
#if defined(OS_MACOSX)
  options.handshake_fd = -1;
#endif
  options.identify_client_via_url = true;
  options.periodic_tasks = true;
  options.rate_limit = true;
  options.upload_gzip = true;
#if defined(OS_LINUX) || defined(OS_ANDROID)
  options.exception_information_address = 0;
  options.initial_client_fd = kInvalidFileHandle;
#endif

  int opt;
  while ((opt = getopt_long(argc, argv, "", long_options, nullptr)) != -1) {
    switch (opt) {
      case kOptionAnnotation: {
        if (!AddKeyValueToMap(&options.annotations, optarg, "--annotation")) {
          return ExitFailure();
        }
        break;
      }
      case kOptionDatabase: {
        options.database = base::FilePath(
            ToolSupport::CommandLineArgumentToFilePathStringType(optarg));
        break;
      }
#if defined(OS_MACOSX)
      case kOptionHandshakeFD: {
        if (!StringToNumber(optarg, &options.handshake_fd) ||
            options.handshake_fd < 0) {
          ToolSupport::UsageHint(me,
                                 "--handshake-fd requires a file descriptor");
          return ExitFailure();
        }
        break;
      }
      case kOptionMachService: {
        options.mach_service = optarg;
        break;
      }
#endif  // OS_MACOSX
#if defined(OS_WIN)
      case kOptionInitialClientData: {
        if (!options.initial_client_data.InitializeFromString(optarg)) {
          ToolSupport::UsageHint(
              me, "failed to parse --initial-client-data");
          return ExitFailure();
        }
        break;
      }
#endif  // OS_WIN
      case kOptionMetrics: {
        options.metrics_dir = base::FilePath(
            ToolSupport::CommandLineArgumentToFilePathStringType(optarg));
        break;
      }
      case kOptionMonitorSelf: {
        options.monitor_self = true;
        break;
      }
      case kOptionMonitorSelfAnnotation: {
        if (!AddKeyValueToMap(&options.monitor_self_annotations,
                              optarg,
                              "--monitor-self-annotation")) {
          return ExitFailure();
        }
        break;
      }
      case kOptionMonitorSelfArgument: {
        options.monitor_self_arguments.push_back(optarg);
        break;
      }
      case kOptionNoIdentifyClientViaUrl: {
        options.identify_client_via_url = false;
        break;
      }
      case kOptionNoPeriodicTasks: {
        options.periodic_tasks = false;
        break;
      }
      case kOptionNoRateLimit: {
        options.rate_limit = false;
        break;
      }
      case kOptionNoUploadGzip: {
        options.upload_gzip = false;
        break;
      }
#if defined(OS_WIN)
      case kOptionPipeName: {
        options.pipe_name = optarg;
        break;
      }
#endif  // OS_WIN
#if defined(OS_MACOSX)
      case kOptionResetOwnCrashExceptionPortToSystemDefault: {
        options.reset_own_crash_exception_port_to_system_default = true;
        break;
      }
#endif  // OS_MACOSX
#if defined(OS_LINUX) || defined(OS_ANDROID)
      case kOptionTraceParentWithException: {
        if (!StringToNumber(optarg, &options.exception_information_address)) {
          ToolSupport::UsageHint(
              me, "failed to parse --trace-parent-with-exception");
          return ExitFailure();
        }
        break;
      }
      case kOptionInitialClientFD: {
        if (!base::StringToInt(optarg, &options.initial_client_fd)) {
          ToolSupport::UsageHint(me, "failed to parse --initial-client-fd");
          return ExitFailure();
        }
        break;
      }
#endif  // OS_LINUX || OS_ANDROID
      case kOptionURL: {
        options.url = optarg;
        break;
      }
      case kOptionHelp: {
        Usage(me);
        MetricsRecordExit(Metrics::LifetimeMilestone::kExitedEarly);
        return EXIT_SUCCESS;
      }
      case kOptionVersion: {
        ToolSupport::Version(me);
        MetricsRecordExit(Metrics::LifetimeMilestone::kExitedEarly);
        return EXIT_SUCCESS;
      }
      default: {
        ToolSupport::UsageHint(me, nullptr);
        return ExitFailure();
      }
    }
  }
  argc -= optind;
  argv += optind;

#if defined(OS_MACOSX)
  if (options.handshake_fd < 0 && options.mach_service.empty()) {
    ToolSupport::UsageHint(me, "--handshake-fd or --mach-service is required");
    return ExitFailure();
  }
  if (options.handshake_fd >= 0 && !options.mach_service.empty()) {
    ToolSupport::UsageHint(
        me, "--handshake-fd and --mach-service are incompatible");
    return ExitFailure();
  }
#elif defined(OS_WIN)
  if (!options.initial_client_data.IsValid() && options.pipe_name.empty()) {
    ToolSupport::UsageHint(me,
                           "--initial-client-data or --pipe-name is required");
    return ExitFailure();
  }
  if (options.initial_client_data.IsValid() && !options.pipe_name.empty()) {
    ToolSupport::UsageHint(
        me, "--initial-client-data and --pipe-name are incompatible");
    return ExitFailure();
  }
#elif defined(OS_LINUX) || defined(OS_ANDROID)
  if (!options.exception_information_address &&
      options.initial_client_fd == kInvalidFileHandle) {
    ToolSupport::UsageHint(
        me,
        "--exception_information_address or --initial_client_fd is required");
    return ExitFailure();
  }
#endif  // OS_MACOSX

  if (options.database.empty()) {
    ToolSupport::UsageHint(me, "--database is required");
    return ExitFailure();
  }

  if (argc) {
    ToolSupport::UsageHint(me, nullptr);
    return ExitFailure();
  }

#if defined(OS_MACOSX)
  if (options.reset_own_crash_exception_port_to_system_default) {
    CrashpadClient::UseSystemDefaultHandler();
  }
#endif  // OS_MACOSX

  if (options.monitor_self) {
    MonitorSelf(options);
  }

  if (!options.monitor_self_annotations.empty()) {
    // Establish these annotations even if --monitor-self is not present, in
    // case something such as generate_dump wants to try to access them later.
    //
    // If the handler is part of a multi-purpose executable, simple annotations
    // may already be present for this module. If they are, use them.
    CrashpadInfo* crashpad_info = CrashpadInfo::GetCrashpadInfo();
    SimpleStringDictionary* module_annotations =
        crashpad_info->simple_annotations();
    if (!module_annotations) {
      module_annotations = new SimpleStringDictionary();
      crashpad_info->set_simple_annotations(module_annotations);
    }

    for (const auto& iterator : options.monitor_self_annotations) {
      module_annotations->SetKeyValue(iterator.first.c_str(),
                                      iterator.second.c_str());
    }
  }

  std::unique_ptr<CrashReportDatabase> database(
      CrashReportDatabase::Initialize(options.database));
  if (!database) {
    return ExitFailure();
  }

  ScopedStoppable upload_thread;
  if (!options.url.empty()) {
    // TODO(scottmg): options.rate_limit should be removed when we have a
    // configurable database setting to control upload limiting.
    // See https://crashpad.chromium.org/bug/23.
    CrashReportUploadThread::Options upload_thread_options;
    upload_thread_options.identify_client_via_url =
        options.identify_client_via_url;
    upload_thread_options.rate_limit = options.rate_limit;
    upload_thread_options.upload_gzip = options.upload_gzip;
    upload_thread_options.watch_pending_reports = options.periodic_tasks;

    upload_thread.Reset(new CrashReportUploadThread(
        database.get(), options.url, upload_thread_options));
    upload_thread.Get()->Start();
  }

  CrashReportExceptionHandler exception_handler(
      database.get(),
      static_cast<CrashReportUploadThread*>(upload_thread.Get()),
      &options.annotations,
      user_stream_sources);

 #if defined(OS_LINUX) || defined(OS_ANDROID)
  if (options.exception_information_address) {
    return exception_handler.HandleException(getppid(),
                                      options.exception_information_address) ?
    EXIT_SUCCESS : ExitFailure();
  }
#endif  // OS_LINUX || OS_ANDROID

  ScopedStoppable prune_thread;
  if (options.periodic_tasks) {
    prune_thread.Reset(new PruneCrashReportThread(
        database.get(), PruneCondition::GetDefault()));
    prune_thread.Get()->Start();
  }

#if defined(OS_MACOSX)
  if (options.mach_service.empty()) {
    // Don’t do this when being run by launchd. See launchd.plist(5).
    CloseStdinAndStdout();
  }

  base::mac::ScopedMachReceiveRight receive_right;

  if (options.handshake_fd >= 0) {
    receive_right.reset(
        ChildPortHandshake::RunServerForFD(
            base::ScopedFD(options.handshake_fd),
            ChildPortHandshake::PortRightType::kReceiveRight));
  } else if (!options.mach_service.empty()) {
    receive_right = BootstrapCheckIn(options.mach_service);
  }

  if (!receive_right.is_valid()) {
    return ExitFailure();
  }

  ExceptionHandlerServer exception_handler_server(
      std::move(receive_right), !options.mach_service.empty());
  base::AutoReset<ExceptionHandlerServer*> reset_g_exception_handler_server(
      &g_exception_handler_server, &exception_handler_server);

  struct sigaction old_sigterm_action;
  ScopedResetSIGTERM reset_sigterm;
  if (!options.mach_service.empty()) {
    // When running from launchd, no no-senders notification could ever be
    // triggered, because launchd maintains a send right to the service. When
    // launchd wants the job to exit, it will send a SIGTERM. See
    // launchd.plist(5).
    //
    // Set up a SIGTERM handler that will call exception_handler_server.Stop().
    // This replaces the HandleTerminateSignal handler for SIGTERM.
    if (Signals::InstallHandler(
            SIGTERM, HandleSIGTERM, 0, &old_sigterm_action)) {
      reset_sigterm.reset(&old_sigterm_action);
    }
  }

  RecordFileLimitAnnotation();
#elif defined(OS_WIN)
  // Shut down as late as possible relative to programs we're watching.
  if (!SetProcessShutdownParameters(0x100, SHUTDOWN_NORETRY))
    PLOG(ERROR) << "SetProcessShutdownParameters";

  ExceptionHandlerServer exception_handler_server(!options.pipe_name.empty());

  if (!options.pipe_name.empty()) {
    exception_handler_server.SetPipeName(base::UTF8ToUTF16(options.pipe_name));
  }
#elif defined(OS_FUCHSIA)
  // These handles are logically "moved" into these variables when retrieved by
  // zx_get_startup_handle(). Both are given to ExceptionHandlerServer which
  // owns them in this process. There is currently no "connect-later" mode on
  // Fuchsia, all the binding must be done by the client before starting
  // crashpad_handler.
  base::ScopedZxHandle root_job(zx_get_startup_handle(PA_HND(PA_USER0, 0)));
  if (!root_job.is_valid()) {
    LOG(ERROR) << "no process handle passed in startup handle 0";
    return EXIT_FAILURE;
  }

  base::ScopedZxHandle exception_port(
      zx_get_startup_handle(PA_HND(PA_USER0, 1)));
  if (!exception_port.is_valid()) {
    LOG(ERROR) << "no exception port handle passed in startup handle 1";
    return EXIT_FAILURE;
  }

  ExceptionHandlerServer exception_handler_server(std::move(root_job),
                                                  std::move(exception_port));
#elif defined(OS_LINUX) || defined(OS_ANDROID)
  ExceptionHandlerServer exception_handler_server;
#endif  // OS_MACOSX

  base::GlobalHistogramAllocator* histogram_allocator = nullptr;
  if (!options.metrics_dir.empty()) {
    static constexpr char kMetricsName[] = "CrashpadMetrics";
    constexpr size_t kMetricsFileSize = 1 << 20;
    if (base::GlobalHistogramAllocator::CreateWithActiveFileInDir(
            options.metrics_dir, kMetricsFileSize, 0, kMetricsName)) {
      histogram_allocator = base::GlobalHistogramAllocator::Get();
      histogram_allocator->CreateTrackingHistograms(kMetricsName);
    }
  }

  Metrics::HandlerLifetimeMilestone(Metrics::LifetimeMilestone::kStarted);

#if defined(OS_WIN)
  if (options.initial_client_data.IsValid()) {
    exception_handler_server.InitializeWithInheritedDataForInitialClient(
        options.initial_client_data, &exception_handler);
  }
#elif defined(OS_LINUX) || defined(OS_ANDROID)
  if (options.initial_client_fd == kInvalidFileHandle ||
             !exception_handler_server.InitializeWithClient(
                 ScopedFileHandle(options.initial_client_fd))) {
    return ExitFailure();
  }
#endif  // OS_WIN

// 死等目标进程结束
  exception_handler_server.Run(&exception_handler);

  return EXIT_SUCCESS;
}

// Z:\chromium\src\third_party\crashpad\crashpad\util\win\exception_handler_server.cc

void ExceptionHandlerServer::Run(Delegate* delegate) {
  uint64_t shutdown_token = base::RandUint64();
  ScopedKernelHANDLE thread_handles[kPipeInstances];
  for (size_t i = 0; i < arraysize(thread_handles); ++i) {
    HANDLE pipe;
    if (first_pipe_instance_.is_valid()) {
      pipe = first_pipe_instance_.release();
    } else {
      pipe = CreateNamedPipeInstance(pipe_name_, i == 0);
      PCHECK(pipe != INVALID_HANDLE_VALUE) << "CreateNamedPipe";
    }

    // Ownership of this object (and the pipe instance) is given to the new
    // thread. We close the thread handles at the end of the scope. They clean
    // up the context object and the pipe instance on termination.
    internal::PipeServiceContext* context =
        new internal::PipeServiceContext(port_.get(),
                                         pipe,
                                         delegate,
                                         &clients_lock_,
                                         &clients_,
                                         shutdown_token);
    thread_handles[i].reset(
        CreateThread(nullptr, 0, &PipeServiceProc, context, 0, nullptr));
    PCHECK(thread_handles[i].is_valid()) << "CreateThread";
  }

  delegate->ExceptionHandlerServerStarted();

  // This is the main loop of the server. Most work is done on the threadpool,
  // other than process end handling which is posted back to this main thread,
  // as we must unregister the threadpool waits here.
  // 在主程序和其他子程序运行时,就在这个循环中打转,所有进程都结束后,才跳出循环返回上一级,去崩溃进程处理结束。
  for (;;) {
    OVERLAPPED* ov = nullptr;
    ULONG_PTR key = 0;
    DWORD bytes = 0;
    GetQueuedCompletionStatus(port_.get(), &bytes, &key, &ov, INFINITE);
    if (!key) {
      // Shutting down.
      break;
    }

    // Otherwise, this is a request to unregister and destroy the given client.
    // delete'ing the ClientData blocks in UnregisterWaitEx to ensure all
    // outstanding threadpool waits are complete. This is important because the
    // process handle can be signalled *before* the dump request is signalled.
    internal::ClientData* client = reinterpret_cast<internal::ClientData*>(key);
    base::AutoLock lock(clients_lock_);
    clients_.erase(client);
    delete client;
    if (!persistent_ && clients_.empty())
      break;
  }

猜你喜欢

转载自blog.csdn.net/LostSpeed/article/details/81432613