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

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

Issue 886613002: Introduce the ability to wait for the watcher process to initialize. (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
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 23 matching lines...) Expand all
34 { 0x80, 0xc1, 0x52, 0x7f, 0xea, 0x23, 0xe3, 0xa7 } }; 34 { 0x80, 0xc1, 0x52, 0x7f, 0xea, 0x23, 0xe3, 0xa7 } };
35 35
36 // Takes care of monitoring a browser. This class watches for a browser's exit 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 37 // code, as well as listening for WM_ENDSESSION messages. Events are recorded
38 // in an exit funnel, for reporting the next time Chrome runs. 38 // in an exit funnel, for reporting the next time Chrome runs.
39 class BrowserMonitor { 39 class BrowserMonitor {
40 public: 40 public:
41 BrowserMonitor(base::RunLoop* run_loop, const base::char16* registry_path); 41 BrowserMonitor(base::RunLoop* run_loop, const base::char16* registry_path);
42 ~BrowserMonitor(); 42 ~BrowserMonitor();
43 43
44 // Starts the monitor, returns true on success. 44 // Starts the monitor, returns true on success. |on_initialized_event| will be
45 // signaled from the background thread immediately before blocking on the exit
Sigurður Ásgeirsson 2015/01/29 16:59:57 nit: the background thread is implementation detai
erikwright (departed) 2015/01/30 20:39:57 I have made an attempt. Note that the code as it s
46 // of |process|.
45 bool StartWatching(const base::char16* registry_path, 47 bool StartWatching(const base::char16* registry_path,
46 base::Process process); 48 base::Process process,
49 base::win::ScopedHandle on_initialized_event);
47 50
48 private: 51 private:
49 // Called from EndSessionWatcherWindow on a WM_ENDSESSION message. 52 // Called from EndSessionWatcherWindow on a WM_ENDSESSION message.
50 void OnEndSession(LPARAM lparam); 53 void OnEndSession(LPARAM lparam);
51 54
52 // Blocking function that runs on |background_thread_|. 55 // Blocking function that runs on |background_thread_|. Signals
53 void Watch(); 56 // |on_initialized_event| before waiting for the browser process to exit.
57 void Watch(base::win::ScopedHandle on_initialized_event);
54 58
55 // Posted to main thread from Watch when browser exits. 59 // Posted to main thread from Watch when browser exits.
56 void BrowserExited(); 60 void BrowserExited();
57 61
58 // True if BrowserExited has run. 62 // True if BrowserExited has run.
59 bool browser_exited_; 63 bool browser_exited_;
60 64
61 // The funnel used to record events for this browser. 65 // The funnel used to record events for this browser.
62 browser_watcher::ExitFunnel exit_funnel_; 66 browser_watcher::ExitFunnel exit_funnel_;
63 67
(...skipping 17 matching lines...) Expand all
81 end_session_watcher_window_( 85 end_session_watcher_window_(
82 base::Bind(&BrowserMonitor::OnEndSession, base::Unretained(this))), 86 base::Bind(&BrowserMonitor::OnEndSession, base::Unretained(this))),
83 background_thread_("BrowserWatcherThread"), 87 background_thread_("BrowserWatcherThread"),
84 run_loop_(run_loop), 88 run_loop_(run_loop),
85 main_thread_(base::MessageLoopProxy::current()) { 89 main_thread_(base::MessageLoopProxy::current()) {
86 } 90 }
87 91
88 BrowserMonitor::~BrowserMonitor() { 92 BrowserMonitor::~BrowserMonitor() {
89 } 93 }
90 94
91 bool BrowserMonitor::StartWatching(const base::char16* registry_path, 95 bool BrowserMonitor::StartWatching(
92 base::Process process) { 96 const base::char16* registry_path,
97 base::Process process,
98 base::win::ScopedHandle on_initialized_event) {
93 if (!exit_code_watcher_.Initialize(process.Pass())) 99 if (!exit_code_watcher_.Initialize(process.Pass()))
94 return false; 100 return false;
95 101
96 if (!exit_funnel_.Init(registry_path, 102 if (!exit_funnel_.Init(registry_path,
97 exit_code_watcher_.process().Handle())) { 103 exit_code_watcher_.process().Handle())) {
98 return false; 104 return false;
99 } 105 }
100 106
101 if (!background_thread_.StartWithOptions( 107 if (!background_thread_.StartWithOptions(
102 base::Thread::Options(base::MessageLoop::TYPE_IO, 0))) { 108 base::Thread::Options(base::MessageLoop::TYPE_IO, 0))) {
103 return false; 109 return false;
104 } 110 }
105 111
106 if (!background_thread_.task_runner()->PostTask(FROM_HERE, 112 if (!background_thread_.task_runner()->PostTask(
107 base::Bind(&BrowserMonitor::Watch, base::Unretained(this)))) { 113 FROM_HERE, base::Bind(&BrowserMonitor::Watch, base::Unretained(this),
114 base::Passed(&on_initialized_event)))) {
Sigurður Ásgeirsson 2015/01/29 16:59:57 ugh - this syntax irks me, but I guess that's just
erikwright (departed) 2015/01/30 20:39:57 You mean base::Passed(&movable)? I replaced it wit
Sigurður Ásgeirsson 2015/02/02 16:59:20 It's probably just me - but base::Passed(&movable)
erikwright (departed) 2015/02/03 20:05:34 Acknowledged.
108 background_thread_.Stop(); 115 background_thread_.Stop();
109 return false; 116 return false;
110 } 117 }
111 118
112 return true; 119 return true;
113 } 120 }
114 121
115 void BrowserMonitor::OnEndSession(LPARAM lparam) { 122 void BrowserMonitor::OnEndSession(LPARAM lparam) {
116 DCHECK_EQ(main_thread_, base::MessageLoopProxy::current()); 123 DCHECK_EQ(main_thread_, base::MessageLoopProxy::current());
117 124
118 exit_funnel_.RecordEvent(L"WatcherLogoff"); 125 exit_funnel_.RecordEvent(L"WatcherLogoff");
119 if (lparam & ENDSESSION_CLOSEAPP) 126 if (lparam & ENDSESSION_CLOSEAPP)
120 exit_funnel_.RecordEvent(L"ES_CloseApp"); 127 exit_funnel_.RecordEvent(L"ES_CloseApp");
121 if (lparam & ENDSESSION_CRITICAL) 128 if (lparam & ENDSESSION_CRITICAL)
122 exit_funnel_.RecordEvent(L"ES_Critical"); 129 exit_funnel_.RecordEvent(L"ES_Critical");
123 if (lparam & ENDSESSION_LOGOFF) 130 if (lparam & ENDSESSION_LOGOFF)
124 exit_funnel_.RecordEvent(L"ES_Logoff"); 131 exit_funnel_.RecordEvent(L"ES_Logoff");
125 const LPARAM kKnownBits = 132 const LPARAM kKnownBits =
126 ENDSESSION_CLOSEAPP | ENDSESSION_CRITICAL | ENDSESSION_LOGOFF; 133 ENDSESSION_CLOSEAPP | ENDSESSION_CRITICAL | ENDSESSION_LOGOFF;
127 if (lparam & ~kKnownBits) 134 if (lparam & ~kKnownBits)
128 exit_funnel_.RecordEvent(L"ES_Other"); 135 exit_funnel_.RecordEvent(L"ES_Other");
129 136
130 // Belt-and-suspenders; make sure our message loop exits ASAP. 137 // Belt-and-suspenders; make sure our message loop exits ASAP.
131 if (browser_exited_) 138 if (browser_exited_)
132 run_loop_->Quit(); 139 run_loop_->Quit();
133 } 140 }
134 141
135 void BrowserMonitor::Watch() { 142 void BrowserMonitor::Watch(base::win::ScopedHandle on_initialized_event) {
136 // This needs to run on an IO thread. 143 // This needs to run on an IO thread.
137 DCHECK_NE(main_thread_, base::MessageLoopProxy::current()); 144 DCHECK_NE(main_thread_, base::MessageLoopProxy::current());
138 145
146 // Signal our client now that RPC is initialized and we have cleared all of
Sigurður Ásgeirsson 2015/01/29 16:59:57 RPC?
erikwright (departed) 2015/01/30 20:39:57 Done.
147 // the obstacles that might lead to an early exit.
148 ::SetEvent(on_initialized_event.Get());
149 on_initialized_event.Close();
150
139 exit_code_watcher_.WaitForExit(); 151 exit_code_watcher_.WaitForExit();
140 exit_funnel_.RecordEvent(L"BrowserExit"); 152 exit_funnel_.RecordEvent(L"BrowserExit");
141 153
142 main_thread_->PostTask(FROM_HERE, 154 main_thread_->PostTask(FROM_HERE,
143 base::Bind(&BrowserMonitor::BrowserExited, base::Unretained(this))); 155 base::Bind(&BrowserMonitor::BrowserExited, base::Unretained(this)));
144 } 156 }
145 157
146 void BrowserMonitor::BrowserExited() { 158 void BrowserMonitor::BrowserExited() {
147 // This runs in the main thread. 159 // This runs in the main thread.
148 DCHECK_EQ(main_thread_, base::MessageLoopProxy::current()); 160 DCHECK_EQ(main_thread_, base::MessageLoopProxy::current());
(...skipping 16 matching lines...) Expand all
165 run_loop_->QuitClosure(), 177 run_loop_->QuitClosure(),
166 base::TimeDelta::FromSeconds(30)); 178 base::TimeDelta::FromSeconds(30));
167 } 179 }
168 } 180 }
169 181
170 } // namespace 182 } // namespace
171 183
172 // The main entry point to the watcher, declared as extern "C" to avoid name 184 // The main entry point to the watcher, declared as extern "C" to avoid name
173 // mangling. 185 // mangling.
174 extern "C" int WatcherMain(const base::char16* registry_path, 186 extern "C" int WatcherMain(const base::char16* registry_path,
175 HANDLE process_handle) { 187 HANDLE process_handle,
188 HANDLE on_initialized_event_handle) {
176 base::Process process(process_handle); 189 base::Process process(process_handle);
190 base::win::ScopedHandle on_initialized_event(on_initialized_event_handle);
177 191
178 // The exit manager is in charge of calling the dtors of singletons. 192 // The exit manager is in charge of calling the dtors of singletons.
179 base::AtExitManager exit_manager; 193 base::AtExitManager exit_manager;
180 // Initialize the commandline singleton from the environment. 194 // Initialize the commandline singleton from the environment.
181 base::CommandLine::Init(0, nullptr); 195 base::CommandLine::Init(0, nullptr);
182 196
183 logging::LogEventProvider::Initialize(kChromeWatcherTraceProviderName); 197 logging::LogEventProvider::Initialize(kChromeWatcherTraceProviderName);
184 198
185 // Arrange to be shut down as late as possible, as we want to outlive 199 // Arrange to be shut down as late as possible, as we want to outlive
186 // chrome.exe in order to report its exit status. 200 // chrome.exe in order to report its exit status.
187 ::SetProcessShutdownParameters(0x100, SHUTDOWN_NORETRY); 201 ::SetProcessShutdownParameters(0x100, SHUTDOWN_NORETRY);
188 202
189 // Run a UI message loop on the main thread. 203 // Run a UI message loop on the main thread.
190 base::MessageLoop msg_loop(base::MessageLoop::TYPE_UI); 204 base::MessageLoop msg_loop(base::MessageLoop::TYPE_UI);
191 msg_loop.set_thread_name("WatcherMainThread"); 205 msg_loop.set_thread_name("WatcherMainThread");
192 206
193 base::RunLoop run_loop; 207 base::RunLoop run_loop;
194 BrowserMonitor monitor(&run_loop, registry_path); 208 BrowserMonitor monitor(&run_loop, registry_path);
195 if (!monitor.StartWatching(registry_path, process.Pass())) 209 if (!monitor.StartWatching(registry_path, process.Pass(),
210 on_initialized_event.Pass())) {
196 return 1; 211 return 1;
212 }
197 213
198 run_loop.Run(); 214 run_loop.Run();
199 215
200 // Wind logging down. 216 // Wind logging down.
201 logging::LogEventProvider::Uninitialize(); 217 logging::LogEventProvider::Uninitialize();
202 218
203 return 0; 219 return 0;
204 } 220 }
205 221
206 static_assert( 222 static_assert(
207 base::is_same<decltype(&WatcherMain), ChromeWatcherMainFunction>::value, 223 base::is_same<decltype(&WatcherMain), ChromeWatcherMainFunction>::value,
208 "WatcherMain() has wrong type"); 224 "WatcherMain() has wrong type");
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698