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 #include <sddl.h> | 6 #include <sddl.h> |
| 7 | 7 |
| 8 #include "base/at_exit.h" | 8 #include "base/at_exit.h" |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 52 { 0x80, 0xc1, 0x52, 0x7f, 0xea, 0x23, 0xe3, 0xa7 } }; | 52 { 0x80, 0xc1, 0x52, 0x7f, 0xea, 0x23, 0xe3, 0xa7 } }; |
| 53 | 53 |
| 54 // The amount of time we wait around for a WM_ENDSESSION or a process exit. | 54 // The amount of time we wait around for a WM_ENDSESSION or a process exit. |
| 55 const int kDelayTimeSeconds = 30; | 55 const int kDelayTimeSeconds = 30; |
| 56 | 56 |
| 57 // Takes care of monitoring a browser. This class watches for a browser's exit | 57 // Takes care of monitoring a browser. This class watches for a browser's exit |
| 58 // code, as well as listening for WM_ENDSESSION messages. Events are recorded in | 58 // code, as well as listening for WM_ENDSESSION messages. Events are recorded in |
| 59 // an exit funnel, for reporting the next time Chrome runs. | 59 // an exit funnel, for reporting the next time Chrome runs. |
| 60 class BrowserMonitor { | 60 class BrowserMonitor { |
| 61 public: | 61 public: |
| 62 BrowserMonitor(base::RunLoop* run_loop, const base::char16* registry_path); | 62 BrowserMonitor(const base::string16& registry_path, base::RunLoop* run_loop); |
| 63 ~BrowserMonitor(); | 63 ~BrowserMonitor(); |
| 64 | 64 |
| 65 // Initiates the asynchronous monitoring process, returns true on success. | 65 // Initiates the asynchronous monitoring process, returns true on success. |
| 66 // |on_initialized_event| will be signaled immediately before blocking on the | 66 // |on_initialized_event| will be signaled immediately before blocking on the |
| 67 // exit of |process|. | 67 // exit of |process|. |
| 68 bool StartWatching(const base::char16* registry_path, | 68 bool StartWatching(base::Process process, |
| 69 base::Process process, | |
| 70 base::win::ScopedHandle on_initialized_event); | 69 base::win::ScopedHandle on_initialized_event); |
| 71 | 70 |
| 72 private: | 71 private: |
| 73 // Called from EndSessionWatcherWindow on a end session messages. | 72 // Called from EndSessionWatcherWindow on a end session messages. |
| 74 void OnEndSessionMessage(UINT message, LPARAM lparam); | 73 void OnEndSessionMessage(UINT message, LPARAM lparam); |
| 75 | 74 |
| 76 // Blocking function that runs on |background_thread_|. Signals | 75 // Blocking function that runs on |background_thread_|. Signals |
| 77 // |on_initialized_event| before waiting for the browser process to exit. | 76 // |on_initialized_event| before waiting for the browser process to exit. |
| 78 void Watch(base::win::ScopedHandle on_initialized_event); | 77 void Watch(base::win::ScopedHandle on_initialized_event); |
| 79 | 78 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 90 // when WM_ENDSESSION occurs before browser exit. | 89 // when WM_ENDSESSION occurs before browser exit. |
| 91 base::WaitableEvent browser_exited_; | 90 base::WaitableEvent browser_exited_; |
| 92 | 91 |
| 93 // The run loop for the main thread and its task runner. | 92 // The run loop for the main thread and its task runner. |
| 94 base::RunLoop* run_loop_; | 93 base::RunLoop* run_loop_; |
| 95 scoped_refptr<base::SequencedTaskRunner> main_thread_; | 94 scoped_refptr<base::SequencedTaskRunner> main_thread_; |
| 96 | 95 |
| 97 DISALLOW_COPY_AND_ASSIGN(BrowserMonitor); | 96 DISALLOW_COPY_AND_ASSIGN(BrowserMonitor); |
| 98 }; | 97 }; |
| 99 | 98 |
| 100 BrowserMonitor::BrowserMonitor(base::RunLoop* run_loop, | 99 BrowserMonitor::BrowserMonitor(const base::string16& registry_path, |
| 101 const base::char16* registry_path) | 100 base::RunLoop* run_loop) |
| 102 : exit_code_watcher_(registry_path), | 101 : exit_code_watcher_(registry_path), |
| 103 end_session_watcher_window_( | 102 end_session_watcher_window_( |
| 104 base::Bind(&BrowserMonitor::OnEndSessionMessage, | 103 base::Bind(&BrowserMonitor::OnEndSessionMessage, |
| 105 base::Unretained(this))), | 104 base::Unretained(this))), |
| 106 background_thread_("BrowserWatcherThread"), | 105 background_thread_("BrowserWatcherThread"), |
| 107 browser_exited_(true, false), // manual reset, initially non-signalled. | 106 browser_exited_(true, false), // manual reset, initially non-signalled. |
| 108 run_loop_(run_loop), | 107 run_loop_(run_loop), |
| 109 main_thread_(base::ThreadTaskRunnerHandle::Get()) { | 108 main_thread_(base::ThreadTaskRunnerHandle::Get()) { |
| 110 } | 109 } |
| 111 | 110 |
| 112 BrowserMonitor::~BrowserMonitor() { | 111 BrowserMonitor::~BrowserMonitor() { |
| 113 } | 112 } |
| 114 | 113 |
| 115 bool BrowserMonitor::StartWatching( | 114 bool BrowserMonitor::StartWatching( |
| 116 const base::char16* registry_path, | |
| 117 base::Process process, | 115 base::Process process, |
| 118 base::win::ScopedHandle on_initialized_event) { | 116 base::win::ScopedHandle on_initialized_event) { |
| 119 if (!exit_code_watcher_.Initialize(process.Pass())) | 117 if (!exit_code_watcher_.Initialize(process.Pass())) |
| 120 return false; | 118 return false; |
| 121 | 119 |
| 122 if (!background_thread_.StartWithOptions( | 120 if (!background_thread_.StartWithOptions( |
| 123 base::Thread::Options(base::MessageLoop::TYPE_IO, 0))) { | 121 base::Thread::Options(base::MessageLoop::TYPE_IO, 0))) { |
| 124 return false; | 122 return false; |
| 125 } | 123 } |
| 126 | 124 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 178 // The browser exited abnormally, wait around for a little bit to see | 176 // The browser exited abnormally, wait around for a little bit to see |
| 179 // whether this instance will get a logoff message. | 177 // whether this instance will get a logoff message. |
| 180 main_thread_->PostDelayedTask( | 178 main_thread_->PostDelayedTask( |
| 181 FROM_HERE, | 179 FROM_HERE, |
| 182 run_loop_->QuitClosure(), | 180 run_loop_->QuitClosure(), |
| 183 base::TimeDelta::FromSeconds(kDelayTimeSeconds)); | 181 base::TimeDelta::FromSeconds(kDelayTimeSeconds)); |
| 184 } | 182 } |
| 185 } | 183 } |
| 186 | 184 |
| 187 void OnWindowEvent( | 185 void OnWindowEvent( |
| 188 const base::string16& registry_path, | |
| 189 base::Process process, | 186 base::Process process, |
| 190 const base::Callback<void(const base::Process&)>& on_hung_callback, | 187 const base::Callback<void(const base::Process&)>& on_hung_callback, |
| 191 browser_watcher::WindowHangMonitor::WindowEvent window_event) { | 188 browser_watcher::WindowHangMonitor::WindowEvent window_event) { |
| 192 if (window_event == browser_watcher::WindowHangMonitor::WINDOW_HUNG && | 189 if (window_event == browser_watcher::WindowHangMonitor::WINDOW_HUNG && |
| 193 !on_hung_callback.is_null()) { | 190 !on_hung_callback.is_null()) { |
| 194 on_hung_callback.Run(process); | 191 on_hung_callback.Run(process); |
| 195 } | 192 } |
| 196 } | 193 } |
| 197 | 194 |
| 198 #if BUILDFLAG(ENABLE_KASKO) | 195 #if BUILDFLAG(ENABLE_KASKO) |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 342 | 339 |
| 343 // TODO(erikwright): Copy minidump to some "last dump" location? | 340 // TODO(erikwright): Copy minidump to some "last dump" location? |
| 344 } | 341 } |
| 345 | 342 |
| 346 #endif // BUILDFLAG(ENABLE_KASKO) | 343 #endif // BUILDFLAG(ENABLE_KASKO) |
| 347 | 344 |
| 348 } // namespace | 345 } // namespace |
| 349 | 346 |
| 350 // The main entry point to the watcher, declared as extern "C" to avoid name | 347 // The main entry point to the watcher, declared as extern "C" to avoid name |
| 351 // mangling. | 348 // mangling. |
| 352 extern "C" int WatcherMain(const base::char16* registry_path, | 349 extern "C" int WatcherMain(const base::string16& registry_path, |
|
Sigurður Ásgeirsson
2016/01/25 20:50:24
this crosses a module boundary and hence an alloca
gab
2016/01/26 02:55:05
Gotcha, would a base::string16* be okay? i.e given
| |
| 353 HANDLE process_handle, | 350 HANDLE process_handle, |
| 354 DWORD main_thread_id, | 351 DWORD main_thread_id, |
| 355 HANDLE on_initialized_event_handle, | 352 HANDLE on_initialized_event_handle, |
| 356 const base::char16* browser_data_directory, | 353 const base::char16* browser_data_directory, |
| 357 const base::char16* message_window_name, | 354 const base::char16* message_window_name, |
| 358 const base::char16* channel_name) { | 355 const base::char16* channel_name) { |
| 359 base::Process process(process_handle); | 356 base::Process process(process_handle); |
| 360 base::win::ScopedHandle on_initialized_event(on_initialized_event_handle); | 357 base::win::ScopedHandle on_initialized_event(on_initialized_event_handle); |
| 361 | 358 |
| 362 // The exit manager is in charge of calling the dtors of singletons. | 359 // The exit manager is in charge of calling the dtors of singletons. |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 397 base::Bind(&DumpHungBrowserProcess, main_thread_id, channel_name); | 394 base::Bind(&DumpHungBrowserProcess, main_thread_id, channel_name); |
| 398 } | 395 } |
| 399 #endif // BUILDFLAG(ENABLE_KASKO_HANG_REPORTS) | 396 #endif // BUILDFLAG(ENABLE_KASKO_HANG_REPORTS) |
| 400 #endif // BUILDFLAG(ENABLE_KASKO) | 397 #endif // BUILDFLAG(ENABLE_KASKO) |
| 401 | 398 |
| 402 // Run a UI message loop on the main thread. | 399 // Run a UI message loop on the main thread. |
| 403 base::MessageLoop msg_loop(base::MessageLoop::TYPE_UI); | 400 base::MessageLoop msg_loop(base::MessageLoop::TYPE_UI); |
| 404 msg_loop.set_thread_name("WatcherMainThread"); | 401 msg_loop.set_thread_name("WatcherMainThread"); |
| 405 | 402 |
| 406 base::RunLoop run_loop; | 403 base::RunLoop run_loop; |
| 407 BrowserMonitor monitor(&run_loop, registry_path); | 404 BrowserMonitor monitor(registry_path, &run_loop); |
| 408 if (!monitor.StartWatching(registry_path, process.Duplicate(), | 405 if (!monitor.StartWatching(process.Duplicate(), |
| 409 on_initialized_event.Pass())) { | 406 on_initialized_event.Pass())) { |
| 410 return 1; | 407 return 1; |
| 411 } | 408 } |
| 412 | 409 |
| 413 { | 410 { |
| 414 // Scoped to force |hang_monitor| destruction before Kasko is shut down. | 411 // Scoped to force |hang_monitor| destruction before Kasko is shut down. |
| 415 browser_watcher::WindowHangMonitor hang_monitor( | 412 browser_watcher::WindowHangMonitor hang_monitor( |
| 416 base::TimeDelta::FromSeconds(60), base::TimeDelta::FromSeconds(20), | 413 base::TimeDelta::FromSeconds(60), base::TimeDelta::FromSeconds(20), |
| 417 base::Bind(&OnWindowEvent, registry_path, | 414 base::Bind(&OnWindowEvent, base::Passed(process.Duplicate()), |
| 418 base::Passed(process.Duplicate()), on_hung_callback)); | 415 on_hung_callback)); |
| 419 hang_monitor.Initialize(process.Duplicate(), message_window_name); | 416 hang_monitor.Initialize(process.Duplicate(), message_window_name); |
| 420 | 417 |
| 421 run_loop.Run(); | 418 run_loop.Run(); |
| 422 } | 419 } |
| 423 | 420 |
| 424 #if BUILDFLAG(ENABLE_KASKO) | 421 #if BUILDFLAG(ENABLE_KASKO) |
| 425 if (launched_kasko) | 422 if (launched_kasko) |
| 426 kasko::api::ShutdownReporter(); | 423 kasko::api::ShutdownReporter(); |
| 427 #endif // BUILDFLAG(ENABLE_KASKO) | 424 #endif // BUILDFLAG(ENABLE_KASKO) |
| 428 | 425 |
| 429 // Wind logging down. | 426 // Wind logging down. |
| 430 logging::LogEventProvider::Uninitialize(); | 427 logging::LogEventProvider::Uninitialize(); |
| 431 | 428 |
| 432 return 0; | 429 return 0; |
| 433 } | 430 } |
| 434 | 431 |
| 435 static_assert( | 432 static_assert( |
| 436 base::is_same<decltype(&WatcherMain), ChromeWatcherMainFunction>::value, | 433 base::is_same<decltype(&WatcherMain), ChromeWatcherMainFunction>::value, |
| 437 "WatcherMain() has wrong type"); | 434 "WatcherMain() has wrong type"); |
| OLD | NEW |