OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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"); |
OLD | NEW |