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

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: Set executable bit for python scripts Created 4 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 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/files/file_util.h"
7 #include "base/location.h" 8 #include "base/location.h"
8 #include "base/logging.h" 9 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h" 10 #include "base/message_loop/message_loop.h"
11 #include "base/strings/string_piece.h"
12 #include "base/strings/string_util.h"
10 #include "base/win/message_window.h" 13 #include "base/win/message_window.h"
11 14
12 namespace browser_watcher { 15 namespace browser_watcher {
13 16
14 namespace { 17 namespace {
15 18
16 HWND FindNamedWindowForProcess(const base::string16 name, base::ProcessId pid) { 19 // Returns true if the class name for |window| equals |str|.
17 HWND candidate = base::win::MessageWindow::FindWindow(name); 20 bool WindowClassNameEqualsString(HWND window, base::StringPiece16 str) {
18 if (candidate) { 21 wchar_t class_name[MAX_PATH];
22 int str_length = ::GetClassName(window, class_name, MAX_PATH);
23 return str_length && str.compare(class_name) == 0;
24 }
25
26 // Returns true if the window text is an existing directory. Ensures that
27 // |window| is the right Chrome message window to ping. This could be improved
28 // by testing for a valid profile in the directory.
29 bool WindowNameIsExistingDirectory(HWND window) {
30 base::string16 window_name;
31 int str_length = ::GetWindowText(
32 window, base::WriteInto(&window_name, MAX_PATH), MAX_PATH);
33 window_name.resize(str_length);
34 return base::DirectoryExists(base::FilePath(window_name));
35 }
36
37 // Returns the Chrome message window handle for the specified |pid| or nullptr
38 // if not found.
39 HWND FindChromeMessageWindow(base::ProcessId pid) {
40 HWND candidate = ::FindWindowEx(HWND_MESSAGE, nullptr, nullptr, nullptr);
41 while (candidate) {
19 DWORD actual_process_id = 0; 42 DWORD actual_process_id = 0;
20 ::GetWindowThreadProcessId(candidate, &actual_process_id); 43 ::GetWindowThreadProcessId(candidate, &actual_process_id);
21 if (actual_process_id == pid) 44 if (WindowClassNameEqualsString(candidate, L"Chrome_MessageWindow") &&
45 WindowNameIsExistingDirectory(candidate) && actual_process_id == pid) {
22 return candidate; 46 return candidate;
47 }
48 candidate = ::GetNextWindow(candidate, GW_HWNDNEXT);
23 } 49 }
24 return nullptr; 50 return nullptr;
25 } 51 }
26 52
27 } // namespace 53 } // namespace
28 54
29 WindowHangMonitor::WindowHangMonitor(base::TimeDelta ping_interval, 55 WindowHangMonitor::WindowHangMonitor(base::TimeDelta ping_interval,
30 base::TimeDelta timeout, 56 base::TimeDelta timeout,
31 const WindowEventCallback& callback) 57 const WindowEventCallback& callback)
32 : callback_(callback), 58 : callback_(callback),
33 ping_interval_(ping_interval), 59 ping_interval_(ping_interval),
34 hang_timeout_(timeout), 60 hang_timeout_(timeout),
35 timer_(false /* don't retain user task */, false /* don't repeat */), 61 timer_(false /* don't retain user task */, false /* don't repeat */),
36 outstanding_ping_(nullptr) { 62 outstanding_ping_(nullptr) {
37 } 63 }
38 64
39 WindowHangMonitor::~WindowHangMonitor() { 65 WindowHangMonitor::~WindowHangMonitor() {
40 if (outstanding_ping_) { 66 if (outstanding_ping_) {
41 // We have an outstanding ping, disable it and leak it intentionally as 67 // 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. 68 // if the callback arrives eventually, it'll cause a use-after-free.
43 outstanding_ping_->monitor = nullptr; 69 outstanding_ping_->monitor = nullptr;
44 outstanding_ping_ = nullptr; 70 outstanding_ping_ = nullptr;
45 } 71 }
46 } 72 }
47 73
48 void WindowHangMonitor::Initialize(base::Process process, 74 void WindowHangMonitor::Initialize(base::Process process) {
49 const base::string16& window_name) {
50 window_name_ = window_name;
51 window_process_ = process.Pass(); 75 window_process_ = process.Pass();
52 timer_.SetTaskRunner(base::MessageLoop::current()->task_runner()); 76 timer_.SetTaskRunner(base::MessageLoop::current()->task_runner());
53 77
54 ScheduleFindWindow(); 78 ScheduleFindWindow();
55 } 79 }
56 80
57 void WindowHangMonitor::ScheduleFindWindow() { 81 void WindowHangMonitor::ScheduleFindWindow() {
58 // TODO(erikwright): We could reduce the polling by using WaitForInputIdle, 82 // TODO(erikwright): We could reduce the polling by using WaitForInputIdle,
59 // but it is hard to test (requiring a non-Console executable). 83 // but it is hard to test (requiring a non-Console executable).
60 timer_.Start( 84 timer_.Start(
61 FROM_HERE, ping_interval_, 85 FROM_HERE, ping_interval_,
62 base::Bind(&WindowHangMonitor::PollForWindow, base::Unretained(this))); 86 base::Bind(&WindowHangMonitor::PollForWindow, base::Unretained(this)));
63 } 87 }
64 88
65 void WindowHangMonitor::PollForWindow() { 89 void WindowHangMonitor::PollForWindow() {
66 int exit_code = 0; 90 int exit_code = 0;
67 if (window_process_.WaitForExitWithTimeout(base::TimeDelta(), &exit_code)) { 91 if (window_process_.WaitForExitWithTimeout(base::TimeDelta(), &exit_code)) {
68 callback_.Run(WINDOW_NOT_FOUND); 92 callback_.Run(WINDOW_NOT_FOUND);
69 return; 93 return;
70 } 94 }
71 95
72 HWND hwnd = FindNamedWindowForProcess(window_name_, window_process_.Pid()); 96 HWND hwnd = FindChromeMessageWindow(window_process_.Pid());
73 if (hwnd) { 97 if (hwnd) {
74 // Sends a ping and schedules a timeout task. Upon receiving a ping response 98 // 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 99 // further pings will be scheduled ad infinitum. Will signal any failure now
76 // or later via the callback. 100 // or later via the callback.
77 SendPing(hwnd); 101 SendPing(hwnd);
78 } else { 102 } else {
79 ScheduleFindWindow(); 103 ScheduleFindWindow();
80 } 104 }
81 } 105 }
82 106
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
114 } 138 }
115 139
116 // Issue the count-out callback. 140 // Issue the count-out callback.
117 timer_.Start(FROM_HERE, hang_timeout_, 141 timer_.Start(FROM_HERE, hang_timeout_,
118 base::Bind(&WindowHangMonitor::OnHangTimeout, 142 base::Bind(&WindowHangMonitor::OnHangTimeout,
119 base::Unretained(this), hwnd)); 143 base::Unretained(this), hwnd));
120 } 144 }
121 145
122 void WindowHangMonitor::OnHangTimeout(HWND hwnd) { 146 void WindowHangMonitor::OnHangTimeout(HWND hwnd) {
123 DCHECK(window_process_.IsValid()); 147 DCHECK(window_process_.IsValid());
124
125 if (outstanding_ping_) { 148 if (outstanding_ping_) {
126 // The ping is still outstanding, the window is hung or has vanished. 149 // The ping is still outstanding, the window is hung or has vanished.
127 // Orphan the outstanding ping. If the callback arrives late, it will 150 // Orphan the outstanding ping. If the callback arrives late, it will
128 // delete it, or if the callback never arrives it'll leak. 151 // delete it, or if the callback never arrives it'll leak.
129 outstanding_ping_->monitor = NULL; 152 outstanding_ping_->monitor = NULL;
130 outstanding_ping_ = NULL; 153 outstanding_ping_ = NULL;
131 154
132 if (hwnd != 155 if (hwnd != FindChromeMessageWindow(window_process_.Pid())) {
133 FindNamedWindowForProcess(window_name_, window_process_.Pid())) {
134 // The window vanished. 156 // The window vanished.
135 callback_.Run(WINDOW_VANISHED); 157 callback_.Run(WINDOW_VANISHED);
136 } else { 158 } else {
137 // The window hung. 159 // The window hung.
138 callback_.Run(WINDOW_HUNG); 160 callback_.Run(WINDOW_HUNG);
139 } 161 }
140 } else { 162 } else {
141 // No ping outstanding, window is not yet hung. Schedule the next retry. 163 // No ping outstanding, window is not yet hung. Schedule the next retry.
142 timer_.Start( 164 timer_.Start(
143 FROM_HERE, hang_timeout_ - ping_interval_, 165 FROM_HERE, hang_timeout_ - ping_interval_,
144 base::Bind(&WindowHangMonitor::OnRetryTimeout, base::Unretained(this))); 166 base::Bind(&WindowHangMonitor::OnRetryTimeout, base::Unretained(this)));
145 } 167 }
146 } 168 }
147 169
148 void WindowHangMonitor::OnRetryTimeout() { 170 void WindowHangMonitor::OnRetryTimeout() {
149 DCHECK(window_process_.IsValid()); 171 DCHECK(window_process_.IsValid());
172 DCHECK(window_process_.IsValid());
150 DCHECK(!outstanding_ping_); 173 DCHECK(!outstanding_ping_);
151 // We can't simply hold onto the previously located HWND due to potential 174 // We can't simply hold onto the previously located HWND due to potential
152 // aliasing. 175 // aliasing.
153 // 1. The window handle might have been re-assigned to a different window 176 // 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 177 // from the time we found it to the point where we query for its owning
155 // process. 178 // process.
156 // 2. The window handle might have been re-assigned to a different process 179 // 2. The window handle might have been re-assigned to a different process
157 // at any point after we found it. 180 // at any point after we found it.
158 HWND hwnd = FindNamedWindowForProcess(window_name_, window_process_.Pid()); 181 HWND hwnd = FindChromeMessageWindow(window_process_.Pid());
159 if (hwnd) 182 if (hwnd) {
160 SendPing(hwnd); 183 SendPing(hwnd);
161 else 184 } else {
162 callback_.Run(WINDOW_VANISHED); 185 callback_.Run(WINDOW_VANISHED);
186 }
163 } 187 }
164 188
165 } // namespace browser_watcher 189 } // namespace browser_watcher
OLDNEW
« no previous file with comments | « components/browser_watcher/window_hang_monitor_win.h ('k') | components/browser_watcher/window_hang_monitor_win_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698