summaryrefslogtreecommitdiffstats
path: root/chrome/tools/crash_service
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
commit09911bf300f1a419907a9412154760efd0b7abc3 (patch)
treef131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/tools/crash_service
parent586acc5fe142f498261f52c66862fa417c3d52d2 (diff)
downloadchromium_src-09911bf300f1a419907a9412154760efd0b7abc3.zip
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.gz
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.bz2
Add chrome to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/tools/crash_service')
-rw-r--r--chrome/tools/crash_service/SConscript99
-rw-r--r--chrome/tools/crash_service/crash_service.cc454
-rw-r--r--chrome/tools/crash_service/crash_service.exe.manifest11
-rw-r--r--chrome/tools/crash_service/crash_service.h138
-rw-r--r--chrome/tools/crash_service/crash_service.vcproj157
-rw-r--r--chrome/tools/crash_service/main.cc84
6 files changed, 943 insertions, 0 deletions
diff --git a/chrome/tools/crash_service/SConscript b/chrome/tools/crash_service/SConscript
new file mode 100644
index 0000000..b682986
--- /dev/null
+++ b/chrome/tools/crash_service/SConscript
@@ -0,0 +1,99 @@
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Import('env')
+
+env = env.Clone()
+
+env.Prepend(
+ CPPPATH = [
+ '$BREAKPAD_DIR/src',
+ '#/..',
+ ],
+ LINKFLAGS = [
+ '/INCREMENTAL',
+
+ '/DELAYLOAD:"dwmapi.dll"',
+ '/DELAYLOAD:"uxtheme.dll"',
+
+ '/DEBUG',
+ '/MACHINE:X86',
+ '/FIXED:No',
+
+ '/safeseh',
+ '/dynamicbase',
+ '/ignore:4199',
+ '/nxcompat',
+
+ ],
+ LIBS = [
+ 'advapi32.lib',
+ 'comdlg32.lib',
+ 'gdi32.lib',
+ 'kernel32.lib',
+ 'msimg32.lib',
+ 'odbc32.lib',
+ 'odbccp32.lib',
+ 'ole32.lib',
+ 'oleaut32.lib',
+ 'psapi.lib',
+ 'shell32.lib',
+ 'user32.lib',
+ 'usp10.lib',
+ 'uuid.lib',
+ 'version.lib',
+ 'wininet.lib',
+ 'winspool.lib',
+ 'ws2_32.lib',
+
+ 'DelayImp.lib',
+ ],
+)
+
+libs = [
+ '$BASE_DIR/base.lib',
+ '$BASE_DIR/gfx/base_gfx.lib',
+ '$BREAKPAD_DIR/breakpad_handler.lib',
+ '$BREAKPAD_DIR/breakpad_sender.lib',
+ '$CHROME_DIR/common/common.lib',
+ '$ICU38_DIR/icuuc.lib',
+ '$SKIA_DIR/skia.lib',
+ '$ZLIB_DIR/zlib.lib',
+]
+
+
+input_files = [
+ 'main.cc',
+ 'crash_service.cc',
+]
+
+exe = env.Program('crash_service.exe', input_files + libs)
+
+i = env.Install('$TARGET_ROOT', exe)
+Alias('chrome', i)
diff --git a/chrome/tools/crash_service/crash_service.cc b/chrome/tools/crash_service/crash_service.cc
new file mode 100644
index 0000000..172b66a
--- /dev/null
+++ b/chrome/tools/crash_service/crash_service.cc
@@ -0,0 +1,454 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/tools/crash_service/crash_service.h"
+
+#include <windows.h>
+
+#include <iostream>
+#include <fstream>
+#include <map>
+
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "breakpad/src/client/windows/crash_generation/crash_generation_server.h"
+#include "breakpad/src/client/windows/sender/crash_report_sender.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/win_util.h"
+
+// TODO(cpu): Bug 1169078. There is a laundry list of things to do for this
+// application. They will be addressed as they are required.
+
+namespace {
+
+const wchar_t kTestPipeName[] = L"\\\\.\\pipe\\ChromeCrashServices";
+
+const wchar_t kCrashReportURL[] = L"https://www.google.com/cr/report";
+const wchar_t kCheckPointFile[] = L"crash_checkpoint.txt";
+
+typedef std::map<std::wstring, std::wstring> CrashMap;
+
+bool CustomInfoToMap(const google_breakpad::ClientInfo* client_info,
+ const std::wstring& reporter_tag, CrashMap* map) {
+ google_breakpad::CustomClientInfo info = client_info->GetCustomInfo();
+
+ for (int i = 0; i < info.count; ++i) {
+ (*map)[info.entries[i].name] = info.entries[i].value;
+ }
+
+ (*map)[L"rept"] = reporter_tag;
+
+ return (map->size() > 0);
+}
+
+bool WriteCustomInfoToFile(const std::wstring& dump_path, const CrashMap& map) {
+ std::wstring file_path(dump_path);
+ size_t last_dot = file_path.rfind(L'.');
+ if (last_dot == std::wstring::npos)
+ return false;
+ file_path.resize(last_dot);
+ file_path += L".txt";
+
+ std::wofstream file(file_path.c_str(),
+ std::ios_base::out | std::ios_base::app | std::ios::binary);
+ if (!file.is_open())
+ return false;
+
+ CrashMap::const_iterator pos;
+ for (pos = map.begin(); pos != map.end(); ++pos) {
+ std::wstring line = pos->first;
+ line += L':';
+ line += pos->second;
+ line += L'\n';
+ file.write(line.c_str(), static_cast<std::streamsize>(line.length()));
+ }
+ return true;
+}
+
+// The window procedure task is to handle when a) the user logs off.
+// b) the system shuts down or c) when the user closes the window.
+LRESULT __stdcall CrashSvcWndProc(HWND hwnd, UINT message,
+ WPARAM wparam, LPARAM lparam) {
+ switch (message) {
+ case WM_CLOSE:
+ case WM_ENDSESSION:
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+ default:
+ return DefWindowProc(hwnd, message, wparam, lparam);
+ }
+ return 0;
+}
+
+// This is the main and only application window.
+HWND g_top_window = NULL;
+
+bool CreateTopWindow(HINSTANCE instance, bool visible) {
+ WNDCLASSEXW wcx = {0};
+ wcx.cbSize = sizeof(wcx);
+ wcx.style = CS_HREDRAW | CS_VREDRAW;
+ wcx.lpfnWndProc = CrashSvcWndProc;
+ wcx.hInstance = instance;
+ wcx.lpszClassName = L"crash_svc_class";
+ ATOM atom = ::RegisterClassExW(&wcx);
+ DWORD style = visible ? WS_POPUPWINDOW | WS_VISIBLE : WS_OVERLAPPED;
+
+ // The window size is zero but being a popup window still shows in the
+ // task bar and can be closed using the system menu or using task manager.
+ HWND window = CreateWindowExW(0, wcx.lpszClassName, L"crash service", style,
+ CW_USEDEFAULT, CW_USEDEFAULT, 0, 0,
+ NULL, NULL, instance, NULL);
+ if (!window)
+ return false;
+
+ ::UpdateWindow(window);
+ LOG(INFO) << "window handle is " << window;
+ g_top_window = window;
+ return true;
+}
+
+// Simple helper class to keep the process alive until the current request
+// finishes.
+class ProcessingLock {
+ public:
+ ProcessingLock() {
+ ::InterlockedIncrement(&op_count_);
+ }
+ ~ProcessingLock() {
+ ::InterlockedDecrement(&op_count_);
+ }
+ static bool IsWorking() {
+ return (op_count_ != 0);
+ }
+ private:
+ static volatile LONG op_count_;
+};
+
+volatile LONG ProcessingLock::op_count_ = 0;
+
+// This structure contains the information that the worker thread needs to
+// send a crash dump to the server.
+struct DumpJobInfo {
+ DWORD pid;
+ CrashService* self;
+ CrashMap map;
+ std::wstring dump_path;
+
+ DumpJobInfo(DWORD process_id, CrashService* service,
+ const CrashMap& crash_map, const std::wstring& path)
+ : pid(process_id), self(service), map(crash_map), dump_path(path) {
+ }
+};
+
+} // namespace
+
+// Command line switches:
+const wchar_t CrashService::kMaxReports[] = L"max-reports";
+const wchar_t CrashService::kNoWindow[] = L"no-window";
+const wchar_t CrashService::kReporterTag[]= L"reporter";
+
+CrashService::CrashService(const std::wstring& report_dir)
+ : report_path_(report_dir),
+ sender_(NULL),
+ dumper_(NULL),
+ requests_handled_(0),
+ requests_sent_(0),
+ clients_connected_(0),
+ clients_terminated_(0) {
+ chrome::RegisterPathProvider();
+}
+
+CrashService::~CrashService() {
+ AutoLock lock(sending_);
+ delete dumper_;
+ delete sender_;
+}
+
+bool CrashService::Initialize(const std::wstring& command_line) {
+ using google_breakpad::CrashReportSender;
+ using google_breakpad::CrashGenerationServer;
+
+ const wchar_t* pipe_name = kTestPipeName;
+ std::wstring dumps_path;
+ int max_reports = -1;
+
+ // The checkpoint file allows CrashReportSender to enforce the the maximum
+ // reports per day quota. Does not seem to serve any other purpose.
+ std::wstring checkpoint_path = report_path_;
+ file_util::AppendToPath(&checkpoint_path, kCheckPointFile);
+
+ // The dumps path is typically : '<user profile>\Local settings\
+ // Application data\Goggle\Chrome\Crash Reports' and the report path is
+ // Application data\Google\Chrome\Reported Crashes.txt
+ if (!PathService::Get(chrome::DIR_USER_DATA, &report_path_)) {
+ LOG(ERROR) << "could not get DIR_USER_DATA";
+ return false;
+ }
+ file_util::AppendToPath(&report_path_, chrome::kCrashReportLog);
+ if (!PathService::Get(chrome::DIR_CRASH_DUMPS, &dumps_path)) {
+ LOG(ERROR) << "could not get DIR_CRASH_DUMPS";
+ return false;
+ }
+
+ CommandLine cmd_line(command_line);
+
+ // We can override the send reports quota with a command line switch.
+ if (cmd_line.HasSwitch(kMaxReports))
+ max_reports = _wtoi(cmd_line.GetSwitchValue(kMaxReports).c_str());
+
+ if (max_reports > 0) {
+ // Create the http sender object.
+ sender_ = new CrashReportSender(checkpoint_path);
+ if (!sender_) {
+ LOG(ERROR) << "could not create sender";
+ return false;
+ }
+ sender_->set_max_reports_per_day(max_reports);
+ }
+ // Create the OOP crash generator object.
+ dumper_ = new CrashGenerationServer(pipe_name, NULL,
+ &CrashService::OnClientConnected, this,
+ &CrashService::OnClientDumpRequest, this,
+ &CrashService::OnClientExited, this,
+ true, &dumps_path);
+ if (!dumper_) {
+ LOG(ERROR) << "could not create dumper";
+ return false;
+ }
+
+ if (!CreateTopWindow(::GetModuleHandleW(NULL),
+ !cmd_line.HasSwitch(kNoWindow))) {
+ LOG(ERROR) << "could not create window";
+ return false;
+ }
+
+ reporter_tag_ = L"crash svc";
+ if (cmd_line.HasSwitch(kReporterTag))
+ reporter_tag_ = cmd_line.GetSwitchValue(kReporterTag);
+
+ // Log basic information.
+ LOG(INFO) << "pipe name is " << pipe_name;
+ LOG(INFO) << "dumps at " << dumps_path;
+ LOG(INFO) << "reports at " << report_path_;
+
+ if (sender_) {
+ LOG(INFO) << "checkpoint is " << checkpoint_path;
+ LOG(INFO) << "server is " << kCrashReportURL;
+ LOG(INFO) << "maximum " << sender_->max_reports_per_day() << " reports/day";
+ LOG(INFO) << "reporter is " << reporter_tag_;
+ }
+ // Start servicing clients.
+ if (!dumper_->Start()) {
+ LOG(ERROR) << "could not start dumper";
+ return false;
+ }
+
+ // This is throwaway code. We don't need to sync with the browser process
+ // once Google Update is updated to a version supporting OOP crash handling.
+ // Create or open an event to signal the browser process that the crash
+ // service is initialized.
+ HANDLE running_event =
+ ::CreateEventW(NULL, TRUE, TRUE, L"g_chrome_crash_svc");
+ // If the browser already had the event open, the CreateEvent call did not
+ // signal it. We need to do it manually.
+ ::SetEvent(running_event);
+
+ return true;
+}
+
+void CrashService::OnClientConnected(void* context,
+ const google_breakpad::ClientInfo* client_info) {
+ ProcessingLock lock;
+ LOG(INFO) << "client start. pid = " << client_info->pid();
+ CrashService* self = static_cast<CrashService*>(context);
+ ::InterlockedIncrement(&self->clients_connected_);
+}
+
+void CrashService::OnClientExited(void* context,
+ const google_breakpad::ClientInfo* client_info) {
+ ProcessingLock lock;
+ LOG(INFO) << "client end. pid = " << client_info->pid();
+ CrashService* self = static_cast<CrashService*>(context);
+ ::InterlockedIncrement(&self->clients_terminated_);
+
+ if (!self->sender_)
+ return;
+
+ // When we are instructed to send reports we need to exit if there are
+ // no more clients to service. The next client that runs will start us.
+ // Only chrome.exe starts crash_service with a non-zero max_reports.
+ if (self->clients_connected_ > self->clients_terminated_)
+ return;
+ if (self->sender_->max_reports_per_day() > 0) {
+ // Wait for the other thread to send crashes, if applicable. The sender
+ // thread takes the sending_ lock, so the sleep is just to give it a
+ // chance to start.
+ ::Sleep(1000);
+ AutoLock lock(self->sending_);
+ // Some people can restart chrome very fast, check again if we have
+ // a new client before exiting for real.
+ if (self->clients_connected_ == self->clients_terminated_) {
+ LOG(INFO) << "zero clients. exiting";
+ ::PostMessage(g_top_window, WM_CLOSE, 0, 0);
+ }
+ }
+}
+
+void CrashService::OnClientDumpRequest(void* context,
+ const google_breakpad::ClientInfo* client_info,
+ const std::wstring* file_path) {
+ ProcessingLock lock;
+
+ if (!file_path) {
+ LOG(ERROR) << "dump with no file path";
+ return;
+ }
+ if (!client_info) {
+ LOG(ERROR) << "dump with no client info";
+ return;
+ }
+
+ DWORD pid = client_info->pid();
+ LOG(INFO) << "dump for pid = " << pid << " is " << *file_path;
+
+ CrashService* self = static_cast<CrashService*>(context);
+ if (!self) {
+ LOG(ERROR) << "dump with no context";
+ return;
+ }
+
+ CrashMap map;
+ CustomInfoToMap(client_info, self->reporter_tag_, &map);
+
+ if (!WriteCustomInfoToFile(*file_path, map)) {
+ LOG(ERROR) << "could not write custom info file";
+ }
+
+ if (!self->sender_)
+ return;
+
+ // Send the crash dump using a worker thread. This operation has retry
+ // logic in case there is no internet connection at the time.
+ DumpJobInfo* dump_job = new DumpJobInfo(pid, self, map, *file_path);
+ if (!::QueueUserWorkItem(&CrashService::AsyncSendDump,
+ dump_job, WT_EXECUTELONGFUNCTION)) {
+ LOG(ERROR) << "could not queue job";
+ }
+}
+
+// We are going to try sending the report several times. If we can't send,
+// we sleep from one minute to several hours depending on the retry round.
+unsigned long CrashService::AsyncSendDump(void* context) {
+ if (!context)
+ return 0;
+
+ DumpJobInfo* info = static_cast<DumpJobInfo*>(context);
+
+ std::wstring report_id = L"<unsent>";
+
+ const DWORD kOneMinute = 60*1000;
+ const DWORD kOneHour = 60*kOneMinute;
+
+ const DWORD kSleepSchedule[] = {
+ 24*kOneHour,
+ 8*kOneHour,
+ 4*kOneHour,
+ kOneHour,
+ 15*kOneMinute,
+ 0};
+
+ int retry_round = arraysize(kSleepSchedule) - 1;
+
+ do {
+ ::Sleep(kSleepSchedule[retry_round]);
+ {
+ // Take the server lock while sending. This also prevent early
+ // termination of the service object.
+ AutoLock lock(info->self->sending_);
+ LOG(INFO) << "trying to send report for pid = " << info->pid;
+ google_breakpad::ReportResult send_result
+ = info->self->sender_->SendCrashReport(kCrashReportURL, info->map,
+ info->dump_path, &report_id);
+ switch (send_result) {
+ case google_breakpad::RESULT_FAILED:
+ report_id = L"<network issue>";
+ break;
+ case google_breakpad::RESULT_REJECTED:
+ report_id = L"<rejected>";
+ ++info->self->requests_handled_;
+ retry_round = 0;
+ break;
+ case google_breakpad::RESULT_SUCCEEDED:
+ ++info->self->requests_sent_;
+ ++info->self->requests_handled_;
+ retry_round = 0;
+ break;
+ case google_breakpad::RESULT_THROTTLED:
+ report_id = L"<throttled>";
+ break;
+ default:
+ report_id = L"<unknown>";
+ break;
+ };
+ }
+
+ LOG(INFO) << "dump for pid =" << info->pid << " crash2 id =" << report_id;
+ --retry_round;
+ } while(retry_round >= 0);
+
+ if (!::DeleteFileW(info->dump_path.c_str()))
+ LOG(WARNING) << "could not delete " << info->dump_path;
+
+ delete info;
+ return 0;
+}
+
+int CrashService::ProcessingLoop() {
+ MSG msg;
+ while (GetMessage(&msg, NULL, 0, 0)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ LOG(INFO) << "session ending..";
+ while (ProcessingLock::IsWorking()) {
+ ::Sleep(50);
+ }
+
+ LOG(INFO) << "clients connected :" << clients_connected_;
+ LOG(INFO) << "clients terminated :" << clients_terminated_;
+ LOG(INFO) << "dumps serviced :" << requests_handled_;
+ LOG(INFO) << "dumps reported :" << requests_sent_;
+
+ return static_cast<int>(msg.wParam);
+}
diff --git a/chrome/tools/crash_service/crash_service.exe.manifest b/chrome/tools/crash_service/crash_service.exe.manifest
new file mode 100644
index 0000000..28469a3
--- /dev/null
+++ b/chrome/tools/crash_service/crash_service.exe.manifest
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <ms_asmv2:trustInfo xmlns:ms_asmv2="urn:schemas-microsoft-com:asm.v2">
+ <ms_asmv2:security>
+ <ms_asmv2:requestedPrivileges>
+ <ms_asmv2:requestedExecutionLevel level="asInvoker">
+ </ms_asmv2:requestedExecutionLevel>
+ </ms_asmv2:requestedPrivileges>
+ </ms_asmv2:security>
+ </ms_asmv2:trustInfo>
+</assembly>
diff --git a/chrome/tools/crash_service/crash_service.h b/chrome/tools/crash_service/crash_service.h
new file mode 100644
index 0000000..d49f50c
--- /dev/null
+++ b/chrome/tools/crash_service/crash_service.h
@@ -0,0 +1,138 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#ifndef CHROME_TOOLS_CRASH_SERVICE__
+#define CHROME_TOOLS_CRASH_SERVICE__
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/lock.h"
+
+namespace google_breakpad {
+
+class CrashReportSender;
+class CrashGenerationServer;
+class ClientInfo;
+
+}
+
+// This class implements an out-of-process crash server. It uses breakpad's
+// CrashGenerationServer and CrashReportSender to generate and then send the
+// crash dumps. Internally, it uses OS specific pipe to allow applications to
+// register for crash dumps and later on when a registered application crashes
+// it will signal an event that causes this code to wake up and perform a
+// crash dump on the signaling process. The dump is then stored on disk and
+// possibly sent to the crash2 servers.
+class CrashService {
+ public:
+ // The ctor takes a directory that needs to be writable and will create
+ // a subdirectory inside to keep logs, crashes and checkpoint files.
+ CrashService(const std::wstring& report_dir);
+ ~CrashService();
+
+ // Starts servicing crash dumps. The command_line specifies various behaviors,
+ // see below for more information. Returns false if it failed. Do not use
+ // other members in that case.
+ bool Initialize(const std::wstring& command_line);
+
+ // Command line switches:
+ //
+ // --max-reports=<number>
+ // Allows to override the maximum number for reports per day. Normally
+ // the crash dumps are never sent so if you want to send any you must
+ // specify a positive number here.
+ static const wchar_t kMaxReports[];
+ // --no-window
+ // Does not create a visible window on the desktop. The window does not have
+ // any other functionality other than allowing the crash service to be
+ // gracefully closed.
+ static const wchar_t kNoWindow[];
+ // --reporter=<string>
+ // Allows to specify a custom string that appears on the detail crash report
+ // page in the crash server. This should be a 25 chars or less string.
+ // The default tag if not specified is 'crash svc'.
+ static const wchar_t kReporterTag[];
+
+ // Returns the actual report path.
+ std::wstring report_path() const {
+ return report_path_;
+ }
+ // Returns number of crash dumps handled.
+ int requests_handled() const {
+ return requests_handled_;
+ }
+ // Returns number of crash clients registered.
+ int clients_connected() const {
+ return clients_connected_;
+ }
+ // Returns number of crash clients terminated.
+ int clients_terminated() const {
+ return clients_terminated_;
+ }
+
+ // Starts the processing loop. This function does not return unless the
+ // user is logging off or the user closes the crash service window. The
+ // return value is a good number to pass in ExitProcess().
+ int ProcessingLoop();
+
+ private:
+ static void OnClientConnected(void* context,
+ const google_breakpad::ClientInfo* client_info);
+
+ static void OnClientDumpRequest(void* context,
+ const google_breakpad::ClientInfo* client_info,
+ const std::wstring* file_path);
+
+ static void OnClientExited(void* context,
+ const google_breakpad::ClientInfo* client_info);
+
+ // This routine sends the crash dump to the server. It takes the sending_
+ // lock when it is performing the send.
+ static unsigned long __stdcall AsyncSendDump(void* context);
+
+ google_breakpad::CrashGenerationServer* dumper_;
+ google_breakpad::CrashReportSender* sender_;
+
+ // the path to dumps and logs directory.
+ std::wstring report_path_;
+ // the extra tag sent to the server with each dump.
+ std::wstring reporter_tag_;
+
+ // clients serviced statistics:
+ int requests_handled_;
+ int requests_sent_;
+ volatile long clients_connected_;
+ volatile long clients_terminated_;
+ Lock sending_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(CrashService);
+};
+
+
+#endif // CHROME_TOOLS_CRASH_SERVICE__
diff --git a/chrome/tools/crash_service/crash_service.vcproj b/chrome/tools/crash_service/crash_service.vcproj
new file mode 100644
index 0000000..5cbc496
--- /dev/null
+++ b/chrome/tools/crash_service/crash_service.vcproj
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="crash_service"
+ ProjectGUID="{89C1C190-A5D1-4EC4-BD6A-67FF2195C7CC}"
+ RootNamespace="crash_service"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)..\breakpad\using_breakpad.vsprops"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\build\release.vsprops;$(SolutionDir)..\breakpad\using_breakpad.vsprops"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath=".\crash_service.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\crash_service.h"
+ >
+ </File>
+ <File
+ RelativePath=".\main.cc"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/chrome/tools/crash_service/main.cc b/chrome/tools/crash_service/main.cc
new file mode 100644
index 0000000..ab27ddd
--- /dev/null
+++ b/chrome/tools/crash_service/main.cc
@@ -0,0 +1,84 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/tools/crash_service/crash_service.h"
+
+#include <windows.h>
+#include <stdlib.h>
+#include <tchar.h>
+
+#include "base/file_util.h"
+#include "base/logging.h"
+
+namespace {
+
+const wchar_t kStandardLogFile[] = L"operation_log.txt";
+
+bool GetCrashServiceDirectory(std::wstring* dir) {
+ std::wstring temp_dir;
+ if (!file_util::GetTempDir(&temp_dir))
+ return false;
+ file_util::AppendToPath(&temp_dir, L"chrome_crashes");
+ if (!file_util::PathExists(temp_dir)) {
+ if (!file_util::CreateDirectory(temp_dir))
+ return false;
+ }
+ *dir = temp_dir;
+ return true;
+}
+
+} // namespace.
+
+int __stdcall wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd_line,
+ int show_mode) {
+ // We use/create a directory under the user's temp folder, for logging.
+ std::wstring operating_dir;
+ GetCrashServiceDirectory(&operating_dir);
+ std::wstring log_file(operating_dir);
+ file_util::AppendToPath(&log_file, kStandardLogFile);
+
+ // Logging to a file with pid, tid and timestamp.
+ logging::InitLogging(log_file.c_str(), logging::LOG_ONLY_TO_FILE,
+ logging::LOCK_LOG_FILE, logging::APPEND_TO_OLD_LOG_FILE);
+ logging::SetLogItems(true, true, true, false);
+
+ LOG(INFO) << "session start. cmdline is [" << cmd_line << "]";
+
+ CrashService crash_service(operating_dir);
+ if (!crash_service.Initialize(::GetCommandLineW()))
+ return 1;
+
+ LOG(INFO) << "ready to process crash requests";
+
+ // Enter the message loop.
+ int retv = crash_service.ProcessingLoop();
+ // Time to exit.
+ LOG(INFO) << "session end. return code is " << retv;
+ return retv;
+}