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

Side by Side Diff: components/browser_watcher/window_hang_monitor_win.cc

Issue 1543803005: Added an integration test for kasko hang reports (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebasing Created 4 years, 11 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 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 #include "components/browser_watcher/window_hang_monitor_win.h" 4 #include "components/browser_watcher/window_hang_monitor_win.h"
5 5
6 #include "base/callback.h" 6 #include "base/callback.h"
7 #include "base/location.h" 7 #include "base/location.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h" 9 #include "base/message_loop/message_loop.h"
10 #include "base/win/message_window.h" 10 #include "base/win/message_window.h"
11 11
12 namespace browser_watcher { 12 namespace browser_watcher {
13 13
14 namespace { 14 namespace {
15 15
16 HWND FindNamedWindowForProcess(const base::string16 name, base::ProcessId pid) { 16 // Returns the class name for the |window|.
17 HWND candidate = base::win::MessageWindow::FindWindow(name); 17 base::string16 GetWindowClassName(HWND window) {
18 if (candidate) { 18 const int kClassNameLength = MAX_PATH;
19 wchar_t class_name[kClassNameLength];
20 int nb_copied = ::GetClassName(window, class_name, kClassNameLength);
21 if (nb_copied) {
22 return base::string16(class_name);
23 }
24 return base::string16();
25 }
26
27 // Returns the Chrome message window handle for the specified |pid| or nullptr
28 // if not found.
29 HWND FindChromeMessageWindow(base::ProcessId pid) {
Sigurður Ásgeirsson 2016/01/11 19:42:59 now that I think about it, I'm not sure this is "g
Patrick Monette 2016/01/20 17:21:35 So I'm now also check that the name of the window
30 HWND candidate = ::FindWindowEx(HWND_MESSAGE, nullptr, nullptr, nullptr);
31 while (candidate) {
19 DWORD actual_process_id = 0; 32 DWORD actual_process_id = 0;
20 ::GetWindowThreadProcessId(candidate, &actual_process_id); 33 ::GetWindowThreadProcessId(candidate, &actual_process_id);
21 if (actual_process_id == pid) 34 if (GetWindowClassName(candidate) == L"Chrome_MessageWindow" &&
Sigurður Ásgeirsson 2016/01/11 19:42:59 doesn't matter a whole lot, but you can avoid a bu
Patrick Monette 2016/01/20 17:21:35 Done.
35 actual_process_id == pid) {
22 return candidate; 36 return candidate;
37 }
38 candidate = ::GetNextWindow(candidate, GW_HWNDNEXT);
23 } 39 }
24 return nullptr; 40 return nullptr;
25 } 41 }
26 42
27 } // namespace 43 } // namespace
28 44
29 WindowHangMonitor::WindowHangMonitor(base::TimeDelta ping_interval, 45 WindowHangMonitor::WindowHangMonitor(base::TimeDelta ping_interval,
30 base::TimeDelta timeout, 46 base::TimeDelta timeout,
31 const WindowEventCallback& callback) 47 const WindowEventCallback& callback)
32 : callback_(callback), 48 : callback_(callback),
33 ping_interval_(ping_interval), 49 ping_interval_(ping_interval),
34 hang_timeout_(timeout), 50 hang_timeout_(timeout),
35 timer_(false /* don't retain user task */, false /* don't repeat */), 51 timer_(false /* don't retain user task */, false /* don't repeat */),
36 outstanding_ping_(nullptr) { 52 outstanding_ping_(nullptr) {
37 } 53 }
38 54
39 WindowHangMonitor::~WindowHangMonitor() { 55 WindowHangMonitor::~WindowHangMonitor() {
40 if (outstanding_ping_) { 56 if (outstanding_ping_) {
41 // We have an outstanding ping, disable it and leak it intentionally as 57 // We have an outstanding ping, disable it and leak it intentionally as
42 // if the callback arrives eventually, it'll cause a use-after-free. 58 // if the callback arrives eventually, it'll cause a use-after-free.
43 outstanding_ping_->monitor = nullptr; 59 outstanding_ping_->monitor = nullptr;
44 outstanding_ping_ = nullptr; 60 outstanding_ping_ = nullptr;
45 } 61 }
46 } 62 }
47 63
48 void WindowHangMonitor::Initialize(base::Process process, 64 void WindowHangMonitor::Initialize(base::Process process) {
49 const base::string16& window_name) {
50 window_name_ = window_name;
51 window_process_ = process.Pass(); 65 window_process_ = process.Pass();
52 timer_.SetTaskRunner(base::MessageLoop::current()->task_runner()); 66 timer_.SetTaskRunner(base::MessageLoop::current()->task_runner());
53 67
54 ScheduleFindWindow(); 68 ScheduleFindWindow();
55 } 69 }
56 70
57 void WindowHangMonitor::ScheduleFindWindow() { 71 void WindowHangMonitor::ScheduleFindWindow() {
58 // TODO(erikwright): We could reduce the polling by using WaitForInputIdle, 72 // TODO(erikwright): We could reduce the polling by using WaitForInputIdle,
59 // but it is hard to test (requiring a non-Console executable). 73 // but it is hard to test (requiring a non-Console executable).
60 timer_.Start( 74 timer_.Start(
61 FROM_HERE, ping_interval_, 75 FROM_HERE, ping_interval_,
62 base::Bind(&WindowHangMonitor::PollForWindow, base::Unretained(this))); 76 base::Bind(&WindowHangMonitor::PollForWindow, base::Unretained(this)));
63 } 77 }
64 78
65 void WindowHangMonitor::PollForWindow() { 79 void WindowHangMonitor::PollForWindow() {
66 int exit_code = 0; 80 int exit_code = 0;
67 if (window_process_.WaitForExitWithTimeout(base::TimeDelta(), &exit_code)) { 81 if (window_process_.WaitForExitWithTimeout(base::TimeDelta(), &exit_code)) {
68 callback_.Run(WINDOW_NOT_FOUND); 82 callback_.Run(WINDOW_NOT_FOUND);
69 return; 83 return;
70 } 84 }
71 85
72 HWND hwnd = FindNamedWindowForProcess(window_name_, window_process_.Pid()); 86 HWND hwnd = FindChromeMessageWindow(window_process_.Pid());
73 if (hwnd) { 87 if (hwnd) {
74 // Sends a ping and schedules a timeout task. Upon receiving a ping response 88 // Sends a ping and schedules a timeout task. Upon receiving a ping response
75 // further pings will be scheduled ad infinitum. Will signal any failure now 89 // further pings will be scheduled ad infinitum. Will signal any failure now
76 // or later via the callback. 90 // or later via the callback.
77 SendPing(hwnd); 91 SendPing(hwnd);
78 } else { 92 } else {
79 ScheduleFindWindow(); 93 ScheduleFindWindow();
80 } 94 }
81 } 95 }
82 96
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
122 void WindowHangMonitor::OnHangTimeout(HWND hwnd) { 136 void WindowHangMonitor::OnHangTimeout(HWND hwnd) {
123 DCHECK(window_process_.IsValid()); 137 DCHECK(window_process_.IsValid());
124 138
125 if (outstanding_ping_) { 139 if (outstanding_ping_) {
126 // The ping is still outstanding, the window is hung or has vanished. 140 // The ping is still outstanding, the window is hung or has vanished.
127 // Orphan the outstanding ping. If the callback arrives late, it will 141 // Orphan the outstanding ping. If the callback arrives late, it will
128 // delete it, or if the callback never arrives it'll leak. 142 // delete it, or if the callback never arrives it'll leak.
129 outstanding_ping_->monitor = NULL; 143 outstanding_ping_->monitor = NULL;
130 outstanding_ping_ = NULL; 144 outstanding_ping_ = NULL;
131 145
132 if (hwnd != 146 if (hwnd != FindChromeMessageWindow(window_process_.Pid())) {
133 FindNamedWindowForProcess(window_name_, window_process_.Pid())) {
134 // The window vanished. 147 // The window vanished.
135 callback_.Run(WINDOW_VANISHED); 148 callback_.Run(WINDOW_VANISHED);
136 } else { 149 } else {
137 // The window hung. 150 // The window hung.
138 callback_.Run(WINDOW_HUNG); 151 callback_.Run(WINDOW_HUNG);
139 } 152 }
140 } else { 153 } else {
141 // No ping outstanding, window is not yet hung. Schedule the next retry. 154 // No ping outstanding, window is not yet hung. Schedule the next retry.
142 timer_.Start( 155 timer_.Start(
143 FROM_HERE, hang_timeout_ - ping_interval_, 156 FROM_HERE, hang_timeout_ - ping_interval_,
144 base::Bind(&WindowHangMonitor::OnRetryTimeout, base::Unretained(this))); 157 base::Bind(&WindowHangMonitor::OnRetryTimeout, base::Unretained(this)));
145 } 158 }
146 } 159 }
147 160
148 void WindowHangMonitor::OnRetryTimeout() { 161 void WindowHangMonitor::OnRetryTimeout() {
149 DCHECK(window_process_.IsValid()); 162 DCHECK(window_process_.IsValid());
150 DCHECK(!outstanding_ping_); 163 DCHECK(!outstanding_ping_);
151 // We can't simply hold onto the previously located HWND due to potential 164 // We can't simply hold onto the previously located HWND due to potential
152 // aliasing. 165 // aliasing.
153 // 1. The window handle might have been re-assigned to a different window 166 // 1. The window handle might have been re-assigned to a different window
154 // from the time we found it to the point where we query for its owning 167 // from the time we found it to the point where we query for its owning
155 // process. 168 // process.
156 // 2. The window handle might have been re-assigned to a different process 169 // 2. The window handle might have been re-assigned to a different process
157 // at any point after we found it. 170 // at any point after we found it.
158 HWND hwnd = FindNamedWindowForProcess(window_name_, window_process_.Pid()); 171 HWND hwnd = FindChromeMessageWindow(window_process_.Pid());
159 if (hwnd) 172 if (hwnd)
160 SendPing(hwnd); 173 SendPing(hwnd);
161 else 174 else
162 callback_.Run(WINDOW_VANISHED); 175 callback_.Run(WINDOW_VANISHED);
163 } 176 }
164 177
165 } // namespace browser_watcher 178 } // namespace browser_watcher
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698