diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
commit | 09911bf300f1a419907a9412154760efd0b7abc3 (patch) | |
tree | f131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/tools/crash_service | |
parent | 586acc5fe142f498261f52c66862fa417c3d52d2 (diff) | |
download | chromium_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/SConscript | 99 | ||||
-rw-r--r-- | chrome/tools/crash_service/crash_service.cc | 454 | ||||
-rw-r--r-- | chrome/tools/crash_service/crash_service.exe.manifest | 11 | ||||
-rw-r--r-- | chrome/tools/crash_service/crash_service.h | 138 | ||||
-rw-r--r-- | chrome/tools/crash_service/crash_service.vcproj | 157 | ||||
-rw-r--r-- | chrome/tools/crash_service/main.cc | 84 |
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; +} |