text: // Copyright (c) 2013 GitHub, Inc.
  // Use of this source code is governed by the MIT license that can be
  // found in the LICENSE file.
  
  #include "atom/common/crash_reporter/crash_reporter_win.h"
  
  #include <string>
  
  #include "base/files/file_util.h"
  #include "base/logging.h"
  #include "base/memory/singleton.h"
  #include "base/strings/string_util.h"
  #include "base/strings/utf_string_conversions.h"
  
  namespace crash_reporter {
  
  namespace {
  
  // Minidump with stacks, PEB, TEB, and unloaded module list.
  const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>(
      MiniDumpWithProcessThreadData |  // Get PEB and TEB.
      MiniDumpWithUnloadedModules);  // Get unloaded modules when available.
  
  const wchar_t kWaitEventFormat[] = L"$1CrashServiceWaitEvent";
  const wchar_t kPipeNameFormat[] = L"\\\\.\\pipe\\$1 Crash Service";
  
  }  // namespace
  
  CrashReporterWin::CrashReporterWin() {
  }
  
  CrashReporterWin::~CrashReporterWin() {
  }
  
  void CrashReporterWin::InitBreakpad(const std::string& product_name,
                                      const std::string& version,
                                      const std::string& company_name,
                                      const std::string& submit_url,
                                      bool auto_submit,
                                      bool skip_system_crash_handler) {
    skip_system_crash_handler_ = skip_system_crash_handler;
  
    base::FilePath temp_dir;
    if (!base::GetTempDir(&temp_dir)) {
      LOG(ERROR) << "Cannot get temp directory";
      return;
    }
  
    base::string16 pipe_name = ReplaceStringPlaceholders(
        kPipeNameFormat, base::UTF8ToUTF16(product_name), NULL);
    base::string16 wait_name = ReplaceStringPlaceholders(
        kWaitEventFormat, base::UTF8ToUTF16(product_name), NULL);
  
    // Wait until the crash service is started.
    HANDLE wait_event = ::CreateEventW(NULL, TRUE, FALSE, wait_name.c_str());
    if (wait_event != NULL) {
      WaitForSingleObject(wait_event, 1000);
      CloseHandle(wait_event);
    }
  
    // ExceptionHandler() attaches our handler and ~ExceptionHandler() detaches
    // it, so we must explicitly reset *before* we instantiate our new handler
    // to allow any previous handler to detach in the correct order.
    breakpad_.reset();
  
    int handler_types = google_breakpad::ExceptionHandler::HANDLER_EXCEPTION |
        google_breakpad::ExceptionHandler::HANDLER_PURECALL;
    breakpad_.reset(new google_breakpad::ExceptionHandler(
        temp_dir.value(),
        FilterCallback,
        MinidumpCallback,
        this,
        handler_types,
        kSmallDumpType,
        pipe_name.c_str(),
        GetCustomInfo(product_name, version, company_name)));
  
    if (!breakpad_->IsOutOfProcess())
      LOG(ERROR) << "Cannot initialize out-of-process crash handler";
  }
  
  void CrashReporterWin::SetUploadParameters() {
    upload_parameters_["platform"] = "win32";
  }
  
  // static
  bool CrashReporterWin::FilterCallback(void* context,
                                        EXCEPTION_POINTERS* exinfo,
                                        MDRawAssertionInfo* assertion) {
    return true;
  }
  
  // static
  bool CrashReporterWin::MinidumpCallback(const wchar_t* dump_path,
                                          const wchar_t* minidump_id,
                                          void* context,
                                          EXCEPTION_POINTERS* exinfo,
                                          MDRawAssertionInfo* assertion,
                                          bool succeeded) {
    CrashReporterWin* self = static_cast<CrashReporterWin*>(context);
    if (succeeded && !self->skip_system_crash_handler_)
      return true;
    else
      return false;
  }
  
  google_breakpad::CustomClientInfo* CrashReporterWin::GetCustomInfo(
      const std::string& product_name,
      const std::string& version,
      const std::string& company_name) {
    custom_info_entries_.clear();
    custom_info_entries_.reserve(2 + upload_parameters_.size());
  
    custom_info_entries_.push_back(google_breakpad::CustomInfoEntry(
        L"prod", L"Electron"));
    custom_info_entries_.push_back(google_breakpad::CustomInfoEntry(
        L"ver", base::UTF8ToWide(version).c_str()));
  
    for (StringMap::const_iterator iter = upload_parameters_.begin();
         iter != upload_parameters_.end(); ++iter) {
      custom_info_entries_.push_back(google_breakpad::CustomInfoEntry(
          base::UTF8ToWide(iter->first).c_str(),
          base::UTF8ToWide(iter->second).c_str()));
    }
  
    custom_info_.entries = &custom_info_entries_.front();
    custom_info_.count = custom_info_entries_.size();
    return &custom_info_;
  }
  
  // static
  CrashReporterWin* CrashReporterWin::GetInstance() {
    return Singleton<CrashReporterWin>::get();
  }
  
  // static
  CrashReporter* CrashReporter::GetInstance() {
    return CrashReporterWin::GetInstance();
  }
  
  }  // namespace crash_reporter
  