[WebView] Reword crash handler message.
[chromium-blink-merge.git] / chrome / chrome_watcher / chrome_watcher_main.cc
blob4e294dc523ccb6a80655f45d6434814916d1d6f3
1 // Copyright (c) 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <windows.h>
7 #include "base/at_exit.h"
8 #include "base/bind.h"
9 #include "base/bind_helpers.h"
10 #include "base/command_line.h"
11 #include "base/logging_win.h"
12 #include "base/macros.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/message_loop/message_loop_proxy.h"
16 #include "base/process/process.h"
17 #include "base/run_loop.h"
18 #include "base/sequenced_task_runner.h"
19 #include "base/synchronization/waitable_event.h"
20 #include "base/template_util.h"
21 #include "base/threading/thread.h"
22 #include "base/time/time.h"
23 #include "chrome/chrome_watcher/chrome_watcher_main_api.h"
24 #include "components/browser_watcher/endsession_watcher_window_win.h"
25 #include "components/browser_watcher/exit_code_watcher_win.h"
26 #include "components/browser_watcher/exit_funnel_win.h"
28 namespace {
30 // Use the same log facility as Chrome for convenience.
31 // {7FE69228-633E-4f06-80C1-527FEA23E3A7}
32 const GUID kChromeWatcherTraceProviderName = {
33 0x7fe69228, 0x633e, 0x4f06,
34 { 0x80, 0xc1, 0x52, 0x7f, 0xea, 0x23, 0xe3, 0xa7 } };
36 // Takes care of monitoring a browser. This class watches for a browser's exit
37 // code, as well as listening for WM_ENDSESSION messages. Events are recorded in
38 // an exit funnel, for reporting the next time Chrome runs.
39 class BrowserMonitor {
40 public:
41 BrowserMonitor(base::RunLoop* run_loop, const base::char16* registry_path);
42 ~BrowserMonitor();
44 // Initiates the asynchronous monitoring process, returns true on success.
45 // |on_initialized_event| will be signaled immediately before blocking on the
46 // exit of |process|.
47 bool StartWatching(const base::char16* registry_path,
48 base::Process process,
49 base::win::ScopedHandle on_initialized_event);
51 private:
52 // Called from EndSessionWatcherWindow on a end session messages.
53 void OnEndSessionMessage(UINT message, LPARAM lparam);
55 // Blocking function that runs on |background_thread_|. Signals
56 // |on_initialized_event| before waiting for the browser process to exit.
57 void Watch(base::win::ScopedHandle on_initialized_event);
59 // Posted to main thread from Watch when browser exits.
60 void BrowserExited();
62 // True if BrowserExited has run.
63 bool browser_exited_;
65 // The funnel used to record events for this browser.
66 browser_watcher::ExitFunnel exit_funnel_;
68 browser_watcher::ExitCodeWatcher exit_code_watcher_;
69 browser_watcher::EndSessionWatcherWindow end_session_watcher_window_;
71 // The thread that runs Watch().
72 base::Thread background_thread_;
74 // The run loop for the main thread and its task runner.
75 base::RunLoop* run_loop_;
76 scoped_refptr<base::SequencedTaskRunner> main_thread_;
78 DISALLOW_COPY_AND_ASSIGN(BrowserMonitor);
81 BrowserMonitor::BrowserMonitor(base::RunLoop* run_loop,
82 const base::char16* registry_path) :
83 browser_exited_(false),
84 exit_code_watcher_(registry_path),
85 end_session_watcher_window_(
86 base::Bind(&BrowserMonitor::OnEndSessionMessage,
87 base::Unretained(this))),
88 background_thread_("BrowserWatcherThread"),
89 run_loop_(run_loop),
90 main_thread_(base::MessageLoopProxy::current()) {
93 BrowserMonitor::~BrowserMonitor() {
96 bool BrowserMonitor::StartWatching(
97 const base::char16* registry_path,
98 base::Process process,
99 base::win::ScopedHandle on_initialized_event) {
100 if (!exit_code_watcher_.Initialize(process.Pass()))
101 return false;
103 if (!exit_funnel_.Init(registry_path,
104 exit_code_watcher_.process().Handle())) {
105 return false;
108 if (!background_thread_.StartWithOptions(
109 base::Thread::Options(base::MessageLoop::TYPE_IO, 0))) {
110 return false;
113 if (!background_thread_.task_runner()->PostTask(
114 FROM_HERE, base::Bind(&BrowserMonitor::Watch, base::Unretained(this),
115 base::Passed(on_initialized_event.Pass())))) {
116 background_thread_.Stop();
117 return false;
120 return true;
123 void BrowserMonitor::OnEndSessionMessage(UINT message, LPARAM lparam) {
124 DCHECK_EQ(main_thread_, base::MessageLoopProxy::current());
126 if (message == WM_QUERYENDSESSION) {
127 exit_funnel_.RecordEvent(L"WatcherQueryEndSession");
128 } else if (message == WM_ENDSESSION) {
129 exit_funnel_.RecordEvent(L"WatcherEndSession");
131 if (lparam & ENDSESSION_CLOSEAPP)
132 exit_funnel_.RecordEvent(L"ES_CloseApp");
133 if (lparam & ENDSESSION_CRITICAL)
134 exit_funnel_.RecordEvent(L"ES_Critical");
135 if (lparam & ENDSESSION_LOGOFF)
136 exit_funnel_.RecordEvent(L"ES_Logoff");
137 const LPARAM kKnownBits =
138 ENDSESSION_CLOSEAPP | ENDSESSION_CRITICAL | ENDSESSION_LOGOFF;
139 if (lparam & ~kKnownBits)
140 exit_funnel_.RecordEvent(L"ES_Other");
142 // Belt-and-suspenders; make sure our message loop exits ASAP.
143 if (browser_exited_)
144 run_loop_->Quit();
147 void BrowserMonitor::Watch(base::win::ScopedHandle on_initialized_event) {
148 // This needs to run on an IO thread.
149 DCHECK_NE(main_thread_, base::MessageLoopProxy::current());
151 // Signal our client now that the Kasko reporter is initialized and we have
152 // cleared all of the obstacles that might lead to an early exit.
153 ::SetEvent(on_initialized_event.Get());
154 on_initialized_event.Close();
156 exit_code_watcher_.WaitForExit();
157 exit_funnel_.RecordEvent(L"BrowserExit");
159 main_thread_->PostTask(FROM_HERE,
160 base::Bind(&BrowserMonitor::BrowserExited, base::Unretained(this)));
163 void BrowserMonitor::BrowserExited() {
164 // This runs in the main thread.
165 DCHECK_EQ(main_thread_, base::MessageLoopProxy::current());
167 // Note that the browser has exited.
168 browser_exited_ = true;
170 // Our background thread has served it's purpose.
171 background_thread_.Stop();
173 const int exit_code = exit_code_watcher_.exit_code();
174 if (exit_code >= 0 && exit_code <= 28) {
175 // The browser exited with a well-known exit code, quit this process
176 // immediately.
177 run_loop_->Quit();
178 } else {
179 // The browser exited abnormally, wait around for a little bit to see
180 // whether this instance will get a logoff message.
181 main_thread_->PostDelayedTask(FROM_HERE,
182 run_loop_->QuitClosure(),
183 base::TimeDelta::FromSeconds(30));
187 } // namespace
189 // The main entry point to the watcher, declared as extern "C" to avoid name
190 // mangling.
191 extern "C" int WatcherMain(const base::char16* registry_path,
192 HANDLE process_handle,
193 HANDLE on_initialized_event_handle) {
194 base::Process process(process_handle);
195 base::win::ScopedHandle on_initialized_event(on_initialized_event_handle);
197 // The exit manager is in charge of calling the dtors of singletons.
198 base::AtExitManager exit_manager;
199 // Initialize the commandline singleton from the environment.
200 base::CommandLine::Init(0, nullptr);
202 logging::LogEventProvider::Initialize(kChromeWatcherTraceProviderName);
204 // Arrange to be shut down as late as possible, as we want to outlive
205 // chrome.exe in order to report its exit status.
206 ::SetProcessShutdownParameters(0x100, SHUTDOWN_NORETRY);
208 // Run a UI message loop on the main thread.
209 base::MessageLoop msg_loop(base::MessageLoop::TYPE_UI);
210 msg_loop.set_thread_name("WatcherMainThread");
212 base::RunLoop run_loop;
213 BrowserMonitor monitor(&run_loop, registry_path);
214 if (!monitor.StartWatching(registry_path, process.Pass(),
215 on_initialized_event.Pass())) {
216 return 1;
219 run_loop.Run();
221 // Wind logging down.
222 logging::LogEventProvider::Uninitialize();
224 return 0;
227 static_assert(
228 base::is_same<decltype(&WatcherMain), ChromeWatcherMainFunction>::value,
229 "WatcherMain() has wrong type");