Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(646)

Side by Side Diff: chrome/chrome_watcher/chrome_watcher_main.cc

Issue 915123003: Stretch watcher's lifetime if it sees WM_ENDSESSION before process exit. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <windows.h> 5 #include <windows.h>
6 6
7 #include "base/at_exit.h" 7 #include "base/at_exit.h"
8 #include "base/bind.h" 8 #include "base/bind.h"
9 #include "base/bind_helpers.h" 9 #include "base/bind_helpers.h"
10 #include "base/command_line.h" 10 #include "base/command_line.h"
(...skipping 15 matching lines...) Expand all
26 #include "components/browser_watcher/exit_funnel_win.h" 26 #include "components/browser_watcher/exit_funnel_win.h"
27 27
28 namespace { 28 namespace {
29 29
30 // Use the same log facility as Chrome for convenience. 30 // Use the same log facility as Chrome for convenience.
31 // {7FE69228-633E-4f06-80C1-527FEA23E3A7} 31 // {7FE69228-633E-4f06-80C1-527FEA23E3A7}
32 const GUID kChromeWatcherTraceProviderName = { 32 const GUID kChromeWatcherTraceProviderName = {
33 0x7fe69228, 0x633e, 0x4f06, 33 0x7fe69228, 0x633e, 0x4f06,
34 { 0x80, 0xc1, 0x52, 0x7f, 0xea, 0x23, 0xe3, 0xa7 } }; 34 { 0x80, 0xc1, 0x52, 0x7f, 0xea, 0x23, 0xe3, 0xa7 } };
35 35
36 // The amount of time we wait around for a WM_ENDSESSION or a process exit.
37 const int kDelayTimeSeconds = 30;
38
36 // Takes care of monitoring a browser. This class watches for a browser's exit 39 // 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 40 // code, as well as listening for WM_ENDSESSION messages. Events are recorded in
38 // an exit funnel, for reporting the next time Chrome runs. 41 // an exit funnel, for reporting the next time Chrome runs.
39 class BrowserMonitor { 42 class BrowserMonitor {
40 public: 43 public:
41 BrowserMonitor(base::RunLoop* run_loop, const base::char16* registry_path); 44 BrowserMonitor(base::RunLoop* run_loop, const base::char16* registry_path);
42 ~BrowserMonitor(); 45 ~BrowserMonitor();
43 46
44 // Initiates the asynchronous monitoring process, returns true on success. 47 // Initiates the asynchronous monitoring process, returns true on success.
45 // |on_initialized_event| will be signaled immediately before blocking on the 48 // |on_initialized_event| will be signaled immediately before blocking on the
46 // exit of |process|. 49 // exit of |process|.
47 bool StartWatching(const base::char16* registry_path, 50 bool StartWatching(const base::char16* registry_path,
48 base::Process process, 51 base::Process process,
49 base::win::ScopedHandle on_initialized_event); 52 base::win::ScopedHandle on_initialized_event);
50 53
51 private: 54 private:
52 // Called from EndSessionWatcherWindow on a end session messages. 55 // Called from EndSessionWatcherWindow on a end session messages.
53 void OnEndSessionMessage(UINT message, LPARAM lparam); 56 void OnEndSessionMessage(UINT message, LPARAM lparam);
54 57
55 // Blocking function that runs on |background_thread_|. Signals 58 // Blocking function that runs on |background_thread_|. Signals
56 // |on_initialized_event| before waiting for the browser process to exit. 59 // |on_initialized_event| before waiting for the browser process to exit.
57 void Watch(base::win::ScopedHandle on_initialized_event); 60 void Watch(base::win::ScopedHandle on_initialized_event);
58 61
59 // Posted to main thread from Watch when browser exits. 62 // Posted to main thread from Watch when browser exits.
60 void BrowserExited(); 63 void BrowserExited();
61 64
62 // True if BrowserExited has run.
63 bool browser_exited_;
64
65 // The funnel used to record events for this browser. 65 // The funnel used to record events for this browser.
66 browser_watcher::ExitFunnel exit_funnel_; 66 browser_watcher::ExitFunnel exit_funnel_;
67 67
68 browser_watcher::ExitCodeWatcher exit_code_watcher_; 68 browser_watcher::ExitCodeWatcher exit_code_watcher_;
69 browser_watcher::EndSessionWatcherWindow end_session_watcher_window_; 69 browser_watcher::EndSessionWatcherWindow end_session_watcher_window_;
70 70
71 // The thread that runs Watch(). 71 // The thread that runs Watch().
72 base::Thread background_thread_; 72 base::Thread background_thread_;
73 73
74 // Set when the browser has exited, used to stretch the watcher's lifetime
75 // when WM_ENDSESSION occurs before browser exit.
76 base::WaitableEvent browser_exited_;
77
74 // The run loop for the main thread and its task runner. 78 // The run loop for the main thread and its task runner.
75 base::RunLoop* run_loop_; 79 base::RunLoop* run_loop_;
76 scoped_refptr<base::SequencedTaskRunner> main_thread_; 80 scoped_refptr<base::SequencedTaskRunner> main_thread_;
77 81
78 DISALLOW_COPY_AND_ASSIGN(BrowserMonitor); 82 DISALLOW_COPY_AND_ASSIGN(BrowserMonitor);
79 }; 83 };
80 84
81 BrowserMonitor::BrowserMonitor(base::RunLoop* run_loop, 85 BrowserMonitor::BrowserMonitor(base::RunLoop* run_loop,
82 const base::char16* registry_path) : 86 const base::char16* registry_path) :
83 browser_exited_(false), 87 browser_exited_(true, false), // manual reset, initially non-signalled.
84 exit_code_watcher_(registry_path), 88 exit_code_watcher_(registry_path),
85 end_session_watcher_window_( 89 end_session_watcher_window_(
86 base::Bind(&BrowserMonitor::OnEndSessionMessage, 90 base::Bind(&BrowserMonitor::OnEndSessionMessage,
87 base::Unretained(this))), 91 base::Unretained(this))),
88 background_thread_("BrowserWatcherThread"), 92 background_thread_("BrowserWatcherThread"),
89 run_loop_(run_loop), 93 run_loop_(run_loop),
90 main_thread_(base::MessageLoopProxy::current()) { 94 main_thread_(base::MessageLoopProxy::current()) {
91 } 95 }
92 96
93 BrowserMonitor::~BrowserMonitor() { 97 BrowserMonitor::~BrowserMonitor() {
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
132 exit_funnel_.RecordEvent(L"ES_CloseApp"); 136 exit_funnel_.RecordEvent(L"ES_CloseApp");
133 if (lparam & ENDSESSION_CRITICAL) 137 if (lparam & ENDSESSION_CRITICAL)
134 exit_funnel_.RecordEvent(L"ES_Critical"); 138 exit_funnel_.RecordEvent(L"ES_Critical");
135 if (lparam & ENDSESSION_LOGOFF) 139 if (lparam & ENDSESSION_LOGOFF)
136 exit_funnel_.RecordEvent(L"ES_Logoff"); 140 exit_funnel_.RecordEvent(L"ES_Logoff");
137 const LPARAM kKnownBits = 141 const LPARAM kKnownBits =
138 ENDSESSION_CLOSEAPP | ENDSESSION_CRITICAL | ENDSESSION_LOGOFF; 142 ENDSESSION_CLOSEAPP | ENDSESSION_CRITICAL | ENDSESSION_LOGOFF;
139 if (lparam & ~kKnownBits) 143 if (lparam & ~kKnownBits)
140 exit_funnel_.RecordEvent(L"ES_Other"); 144 exit_funnel_.RecordEvent(L"ES_Other");
141 145
142 // Belt-and-suspenders; make sure our message loop exits ASAP. 146 // If the browser hasn't exited yet, dally for a bit to try and stretch this
143 if (browser_exited_) 147 // process' lifetime to give it some more time to capture the browser exit.
144 run_loop_->Quit(); 148 browser_exited_.TimedWait(base::TimeDelta::FromSeconds(kDelayTimeSeconds));
149
150 run_loop_->Quit();
145 } 151 }
146 152
147 void BrowserMonitor::Watch(base::win::ScopedHandle on_initialized_event) { 153 void BrowserMonitor::Watch(base::win::ScopedHandle on_initialized_event) {
148 // This needs to run on an IO thread. 154 // This needs to run on an IO thread.
149 DCHECK_NE(main_thread_, base::MessageLoopProxy::current()); 155 DCHECK_NE(main_thread_, base::MessageLoopProxy::current());
150 156
151 // Signal our client now that the Kasko reporter is initialized and we have 157 // 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. 158 // cleared all of the obstacles that might lead to an early exit.
153 ::SetEvent(on_initialized_event.Get()); 159 ::SetEvent(on_initialized_event.Get());
154 on_initialized_event.Close(); 160 on_initialized_event.Close();
155 161
156 exit_code_watcher_.WaitForExit(); 162 exit_code_watcher_.WaitForExit();
157 exit_funnel_.RecordEvent(L"BrowserExit"); 163 exit_funnel_.RecordEvent(L"BrowserExit");
158 164
165 // Note that the browser has exited.
166 browser_exited_.Signal();
167
159 main_thread_->PostTask(FROM_HERE, 168 main_thread_->PostTask(FROM_HERE,
160 base::Bind(&BrowserMonitor::BrowserExited, base::Unretained(this))); 169 base::Bind(&BrowserMonitor::BrowserExited, base::Unretained(this)));
161 } 170 }
162 171
163 void BrowserMonitor::BrowserExited() { 172 void BrowserMonitor::BrowserExited() {
164 // This runs in the main thread. 173 // This runs in the main thread.
165 DCHECK_EQ(main_thread_, base::MessageLoopProxy::current()); 174 DCHECK_EQ(main_thread_, base::MessageLoopProxy::current());
166 175
167 // Note that the browser has exited.
168 browser_exited_ = true;
169
170 // Our background thread has served it's purpose. 176 // Our background thread has served it's purpose.
171 background_thread_.Stop(); 177 background_thread_.Stop();
172 178
173 const int exit_code = exit_code_watcher_.exit_code(); 179 const int exit_code = exit_code_watcher_.exit_code();
174 if (exit_code >= 0 && exit_code <= 28) { 180 if (exit_code >= 0 && exit_code <= 28) {
175 // The browser exited with a well-known exit code, quit this process 181 // The browser exited with a well-known exit code, quit this process
176 // immediately. 182 // immediately.
177 run_loop_->Quit(); 183 run_loop_->Quit();
178 } else { 184 } else {
179 // The browser exited abnormally, wait around for a little bit to see 185 // The browser exited abnormally, wait around for a little bit to see
180 // whether this instance will get a logoff message. 186 // whether this instance will get a logoff message.
181 main_thread_->PostDelayedTask(FROM_HERE, 187 main_thread_->PostDelayedTask(
182 run_loop_->QuitClosure(), 188 FROM_HERE,
183 base::TimeDelta::FromSeconds(30)); 189 run_loop_->QuitClosure(),
190 base::TimeDelta::FromSeconds(kDelayTimeSeconds));
184 } 191 }
185 } 192 }
186 193
187 } // namespace 194 } // namespace
188 195
189 // The main entry point to the watcher, declared as extern "C" to avoid name 196 // The main entry point to the watcher, declared as extern "C" to avoid name
190 // mangling. 197 // mangling.
191 extern "C" int WatcherMain(const base::char16* registry_path, 198 extern "C" int WatcherMain(const base::char16* registry_path,
192 HANDLE process_handle, 199 HANDLE process_handle,
193 HANDLE on_initialized_event_handle) { 200 HANDLE on_initialized_event_handle) {
(...skipping 26 matching lines...) Expand all
220 227
221 // Wind logging down. 228 // Wind logging down.
222 logging::LogEventProvider::Uninitialize(); 229 logging::LogEventProvider::Uninitialize();
223 230
224 return 0; 231 return 0;
225 } 232 }
226 233
227 static_assert( 234 static_assert(
228 base::is_same<decltype(&WatcherMain), ChromeWatcherMainFunction>::value, 235 base::is_same<decltype(&WatcherMain), ChromeWatcherMainFunction>::value,
229 "WatcherMain() has wrong type"); 236 "WatcherMain() has wrong type");
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698