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

Side by Side Diff: chrome/browser/process_singleton_win.cc

Issue 1844023002: Capture a report on failed browser rendez-vous. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Executable name check Created 4 years, 8 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 (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "chrome/browser/process_singleton.h" 5 #include "chrome/browser/process_singleton.h"
6 6
7 #include <shellapi.h> 7 #include <shellapi.h>
8 #include <stddef.h> 8 #include <stddef.h>
9 #include <winbase.h>
grt (UTC plus 2) 2016/04/05 17:22:08 change this to #include <windows.h> and move it ab
manzagop (departed) 2016/04/06 19:36:02 Done.
10
11 #include <cwchar>
grt (UTC plus 2) 2016/04/05 17:22:07 why? wchar_t is a keyword. is there something else
manzagop (departed) 2016/04/06 19:36:01 Done. Dead code (was using wcscmp at one point).
9 12
10 #include "base/base_paths.h" 13 #include "base/base_paths.h"
11 #include "base/bind.h" 14 #include "base/bind.h"
12 #include "base/command_line.h" 15 #include "base/command_line.h"
13 #include "base/files/file_path.h" 16 #include "base/files/file_path.h"
14 #include "base/macros.h" 17 #include "base/macros.h"
18 #include "base/path_service.h"
15 #include "base/process/process.h" 19 #include "base/process/process.h"
16 #include "base/process/process_info.h" 20 #include "base/process/process_info.h"
17 #include "base/strings/string_number_conversions.h" 21 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/stringprintf.h" 22 #include "base/strings/stringprintf.h"
19 #include "base/strings/utf_string_conversions.h" 23 #include "base/strings/utf_string_conversions.h"
20 #include "base/time/time.h" 24 #include "base/time/time.h"
21 #include "base/win/registry.h" 25 #include "base/win/registry.h"
22 #include "base/win/scoped_handle.h" 26 #include "base/win/scoped_handle.h"
23 #include "base/win/windows_version.h" 27 #include "base/win/windows_version.h"
24 #include "chrome/browser/browser_process.h" 28 #include "chrome/browser/browser_process.h"
25 #include "chrome/browser/browser_process_platform_part.h" 29 #include "chrome/browser/browser_process_platform_part.h"
26 #include "chrome/browser/chrome_process_finder_win.h" 30 #include "chrome/browser/chrome_process_finder_win.h"
27 #include "chrome/browser/shell_integration.h" 31 #include "chrome/browser/shell_integration.h"
28 #include "chrome/browser/ui/simple_message_box.h" 32 #include "chrome/browser/ui/simple_message_box.h"
33 #include "chrome/chrome_watcher/kasko_util.h"
34 #include "chrome/common/channel_info.h"
29 #include "chrome/common/chrome_constants.h" 35 #include "chrome/common/chrome_constants.h"
30 #include "chrome/common/chrome_paths.h" 36 #include "chrome/common/chrome_paths.h"
31 #include "chrome/common/chrome_paths_internal.h" 37 #include "chrome/common/chrome_paths_internal.h"
32 #include "chrome/common/chrome_switches.h" 38 #include "chrome/common/chrome_switches.h"
33 #include "chrome/grit/chromium_strings.h" 39 #include "chrome/grit/chromium_strings.h"
40 #include "chrome/installer/util/util_constants.h"
34 #include "chrome/installer/util/wmi.h" 41 #include "chrome/installer/util/wmi.h"
42 #include "components/version_info/version_info.h"
35 #include "content/public/common/result_codes.h" 43 #include "content/public/common/result_codes.h"
36 #include "net/base/escape.h" 44 #include "net/base/escape.h"
45 #include "third_party/kasko/kasko_features.h"
37 #include "ui/base/l10n/l10n_util.h" 46 #include "ui/base/l10n/l10n_util.h"
38 #include "ui/gfx/win/hwnd_util.h" 47 #include "ui/gfx/win/hwnd_util.h"
39 48
40 namespace { 49 namespace {
41 50
42 const char kLockfile[] = "lockfile"; 51 const char kLockfile[] = "lockfile";
43 52
44 // A helper class that acquires the given |mutex| while the AutoLockMutex is in 53 // A helper class that acquires the given |mutex| while the AutoLockMutex is in
45 // scope. 54 // scope.
46 class AutoLockMutex { 55 class AutoLockMutex {
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
172 return true; 181 return true;
173 } 182 }
174 183
175 bool DisplayShouldKillMessageBox() { 184 bool DisplayShouldKillMessageBox() {
176 return chrome::ShowQuestionMessageBox( 185 return chrome::ShowQuestionMessageBox(
177 NULL, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME), 186 NULL, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
178 l10n_util::GetStringUTF16(IDS_BROWSER_HUNGBROWSER_MESSAGE)) != 187 l10n_util::GetStringUTF16(IDS_BROWSER_HUNGBROWSER_MESSAGE)) !=
179 chrome::MESSAGE_BOX_RESULT_NO; 188 chrome::MESSAGE_BOX_RESULT_NO;
180 } 189 }
181 190
191 #if BUILDFLAG(ENABLE_KASKO)
192 #if BUILDFLAG(ENABLE_KASKO_FAILED_RDV_REPORTS)
193 // Capture a failed rendez-vous hang report of the other process. Kasko needs
194 // the exception context to live either in the dumper of the dumpee. This
grt (UTC plus 2) 2016/04/05 17:22:07 of -> or?
manzagop (departed) 2016/04/06 19:36:01 Done.
195 // means we cannot rely on kasko reporters from either browser watcher, and
196 // instead spin up a new reporter.
197 void SendFailedRdvReport(const base::Process& process, const DWORD thread_id) {
grt (UTC plus 2) 2016/04/05 17:22:07 remove "const"
manzagop (departed) 2016/04/06 19:36:02 Done.
198 // TODO(manzagop): add a metric for the number of captured hang reports, for
199 // comparison with uploaded count?
200
201 // Ensure the target process shares the current process' executable name. This
grt (UTC plus 2) 2016/04/05 17:22:08 nit: process's
manzagop (departed) 2016/04/06 19:36:02 Done.
202 // is to defend against races that exist in getting a Process from a window
203 // name (HWND and process id recycling).
204 // TODO(manzagop): add a metric for the number of times this does not match.
205 wchar_t exe_name_self[MAX_PATH];
206 if (GetModuleFileName(nullptr, exe_name_self, MAX_PATH) == 0)
Patrick Monette 2016/04/04 23:33:40 You can use PathService::Get(FILE_EXE) instead;
manzagop (departed) 2016/04/06 19:36:02 Done.
207 return;
208 wchar_t exe_name_other[MAX_PATH];
209 DWORD exe_name_other_len = MAX_PATH;
210 if (QueryFullProcessImageName(process.Handle(), 0, exe_name_other,
211 &exe_name_other_len) == 0) {
212 DWORD error = GetLastError();
grt (UTC plus 2) 2016/04/05 17:22:07 remove this
manzagop (departed) 2016/04/06 19:36:02 Done.
213 DPLOG(INFO) << "Failed to get executable name for other process: " << error;
grt (UTC plus 2) 2016/04/05 17:22:07 The *P* class of log functions automatically add t
manzagop (departed) 2016/04/06 19:36:02 Done.
214 return;
215 }
216 // Note: FilePath handles the complexity of path comparision (eg case).
217 if (base::FilePath(exe_name_self) != base::FilePath(exe_name_other))
Patrick Monette 2016/04/04 23:33:40 Can you move the exe name comparison to a function
Sigurður Ásgeirsson 2016/04/05 13:52:29 @grt may be familiar with cases where this compari
grt (UTC plus 2) 2016/04/05 17:22:08 We generally use base::FilePath::CompareEqualIgnor
manzagop (departed) 2016/04/06 19:36:02 Done.
manzagop (departed) 2016/04/06 19:36:02 Acknowledged.
manzagop (departed) 2016/04/06 19:36:02 False negatives are not an issue (though I have a
218 return;
219
220 // Only report on canary (or unspecified).
221 const version_info::Channel channel = chrome::GetChannel();
grt (UTC plus 2) 2016/04/05 17:22:08 consider doing this higher up in the function so t
manzagop (departed) 2016/04/06 19:36:02 Done.
222 if (channel != version_info::Channel::UNKNOWN &&
223 channel != version_info::Channel::CANARY) {
224 return;
225 }
226
227 // Initialize a reporter, capture a report and shutdown the reporter.
228 base::FilePath watcher_data_directory;
229 if (PathService::Get(chrome::DIR_WATCHER_DATA, &watcher_data_directory)) {
230 base::string16 endpoint =
231 L"chrome_kasko_rdv_" +
232 base::UintToString16(base::Process::Current().Pid());
233
234 bool launched_kasko = InitializeKaskoReporter(
235 endpoint, watcher_data_directory.value().c_str());
236 if (launched_kasko) {
237 DumpHungProcess(thread_id, installer::kChromeChannelCanary, L"failed-rdv",
238 process);
239 // We immediately request Kasko shutdown. This may block until the
240 // completion of ongoing background tasks (eg upload). If the report is
grt (UTC plus 2) 2016/04/05 17:22:08 nit: "e.g., upload"
manzagop (departed) 2016/04/06 19:36:01 Done.
241 // not uploaded by this reporter, any other Kasko reporter may upload it.
242 ShutdownKaskoReporter();
243 }
244 }
245 }
246 #endif // BUILDFLAG(ENABLE_KASKO_FAILED_RDV_REPORTS)
247 #endif // BUILDFLAG(ENABLE_KASKO)
248
182 } // namespace 249 } // namespace
183 250
184 // Microsoft's Softricity virtualization breaks the sandbox processes. 251 // Microsoft's Softricity virtualization breaks the sandbox processes.
185 // So, if we detect the Softricity DLL we use WMI Win32_Process.Create to 252 // So, if we detect the Softricity DLL we use WMI Win32_Process.Create to
186 // break out of the virtualization environment. 253 // break out of the virtualization environment.
187 // http://code.google.com/p/chromium/issues/detail?id=43650 254 // http://code.google.com/p/chromium/issues/detail?id=43650
188 bool ProcessSingleton::EscapeVirtualization( 255 bool ProcessSingleton::EscapeVirtualization(
189 const base::FilePath& user_data_dir) { 256 const base::FilePath& user_data_dir) {
190 if (::GetModuleHandle(L"sftldr_wow64.dll") || 257 if (::GetModuleHandle(L"sftldr_wow64.dll") ||
191 ::GetModuleHandle(L"sftldr.dll")) { 258 ::GetModuleHandle(L"sftldr.dll")) {
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
242 case chrome::NOTIFY_SUCCESS: 309 case chrome::NOTIFY_SUCCESS:
243 return PROCESS_NOTIFIED; 310 return PROCESS_NOTIFIED;
244 case chrome::NOTIFY_FAILED: 311 case chrome::NOTIFY_FAILED:
245 remote_window_ = NULL; 312 remote_window_ = NULL;
246 return PROCESS_NONE; 313 return PROCESS_NONE;
247 case chrome::NOTIFY_WINDOW_HUNG: 314 case chrome::NOTIFY_WINDOW_HUNG:
248 // Fall through and potentially terminate the hung browser. 315 // Fall through and potentially terminate the hung browser.
249 break; 316 break;
250 } 317 }
251 318
319 // The window is hung.
grt (UTC plus 2) 2016/04/05 17:22:07 https://youtu.be/O4gqsuww6lw
manzagop (departed) 2016/04/06 19:36:02 Acknowledged?! ;)
252 DWORD process_id = 0; 320 DWORD process_id = 0;
253 DWORD thread_id = ::GetWindowThreadProcessId(remote_window_, &process_id); 321 DWORD thread_id = ::GetWindowThreadProcessId(remote_window_, &process_id);
254 if (!thread_id || !process_id) { 322 if (!thread_id || !process_id) {
255 remote_window_ = NULL; 323 remote_window_ = NULL;
256 return PROCESS_NONE; 324 return PROCESS_NONE;
257 } 325 }
326
327 // Get a handle to the process that created the window.
258 base::Process process = base::Process::Open(process_id); 328 base::Process process = base::Process::Open(process_id);
259 329
260 // The window is hung. Scan for every window to find a visible one. 330 // Optionally send a failed rendez-vous report.
331 // Note: we nominate the thread that created the window as the root of the
332 // search for a hung thread.
333 #if BUILDFLAG(ENABLE_KASKO)
334 #if BUILDFLAG(ENABLE_KASKO_FAILED_RDV_REPORTS)
335 SendFailedRdvReport(process, thread_id);
336 #endif // BUILDFLAG(ENABLE_KASKO_FAILED_RDV_REPORTS)
337 #endif // BUILDFLAG(ENABLE_KASKO)
338
339 // Scan for every window to find a visible one.
261 bool visible_window = false; 340 bool visible_window = false;
262 ::EnumThreadWindows(thread_id, 341 ::EnumThreadWindows(thread_id,
263 &BrowserWindowEnumeration, 342 &BrowserWindowEnumeration,
264 reinterpret_cast<LPARAM>(&visible_window)); 343 reinterpret_cast<LPARAM>(&visible_window));
265 344
266 // If there is a visible browser window, ask the user before killing it. 345 // If there is a visible browser window, ask the user before killing it.
267 if (visible_window && !should_kill_remote_process_callback_.Run()) { 346 if (visible_window && !should_kill_remote_process_callback_.Run()) {
268 // The user denied. Quit silently. 347 // The user denied. Quit silently.
269 return PROCESS_NOTIFIED; 348 return PROCESS_NOTIFIED;
270 } 349 }
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
348 return window_.hwnd() != NULL; 427 return window_.hwnd() != NULL;
349 } 428 }
350 429
351 void ProcessSingleton::Cleanup() { 430 void ProcessSingleton::Cleanup() {
352 } 431 }
353 432
354 void ProcessSingleton::OverrideShouldKillRemoteProcessCallbackForTesting( 433 void ProcessSingleton::OverrideShouldKillRemoteProcessCallbackForTesting(
355 const ShouldKillRemoteProcessCallback& display_dialog_callback) { 434 const ShouldKillRemoteProcessCallback& display_dialog_callback) {
356 should_kill_remote_process_callback_ = display_dialog_callback; 435 should_kill_remote_process_callback_ = display_dialog_callback;
357 } 436 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698