Chromium Code Reviews| 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 |