Chromium Code Reviews| Index: chrome/browser/process_singleton_win.cc |
| diff --git a/chrome/browser/process_singleton_win.cc b/chrome/browser/process_singleton_win.cc |
| index 335215680f0d1063b90260fcd4b1e7b9e39a3248..b0d52e4aeff901b653756272362fbaa0ef47937d 100644 |
| --- a/chrome/browser/process_singleton_win.cc |
| +++ b/chrome/browser/process_singleton_win.cc |
| @@ -6,12 +6,16 @@ |
| #include <shellapi.h> |
| #include <stddef.h> |
| +#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.
|
| + |
| +#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).
|
| #include "base/base_paths.h" |
| #include "base/bind.h" |
| #include "base/command_line.h" |
| #include "base/files/file_path.h" |
| #include "base/macros.h" |
| +#include "base/path_service.h" |
| #include "base/process/process.h" |
| #include "base/process/process_info.h" |
| #include "base/strings/string_number_conversions.h" |
| @@ -26,14 +30,19 @@ |
| #include "chrome/browser/chrome_process_finder_win.h" |
| #include "chrome/browser/shell_integration.h" |
| #include "chrome/browser/ui/simple_message_box.h" |
| +#include "chrome/chrome_watcher/kasko_util.h" |
| +#include "chrome/common/channel_info.h" |
| #include "chrome/common/chrome_constants.h" |
| #include "chrome/common/chrome_paths.h" |
| #include "chrome/common/chrome_paths_internal.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "chrome/grit/chromium_strings.h" |
| +#include "chrome/installer/util/util_constants.h" |
| #include "chrome/installer/util/wmi.h" |
| +#include "components/version_info/version_info.h" |
| #include "content/public/common/result_codes.h" |
| #include "net/base/escape.h" |
| +#include "third_party/kasko/kasko_features.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/gfx/win/hwnd_util.h" |
| @@ -179,6 +188,64 @@ bool DisplayShouldKillMessageBox() { |
| chrome::MESSAGE_BOX_RESULT_NO; |
| } |
| +#if BUILDFLAG(ENABLE_KASKO) |
| +#if BUILDFLAG(ENABLE_KASKO_FAILED_RDV_REPORTS) |
| +// Capture a failed rendez-vous hang report of the other process. Kasko needs |
| +// 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.
|
| +// means we cannot rely on kasko reporters from either browser watcher, and |
| +// instead spin up a new reporter. |
| +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.
|
| + // TODO(manzagop): add a metric for the number of captured hang reports, for |
| + // comparison with uploaded count? |
| + |
| + // 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.
|
| + // is to defend against races that exist in getting a Process from a window |
| + // name (HWND and process id recycling). |
| + // TODO(manzagop): add a metric for the number of times this does not match. |
| + wchar_t exe_name_self[MAX_PATH]; |
| + 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.
|
| + return; |
| + wchar_t exe_name_other[MAX_PATH]; |
| + DWORD exe_name_other_len = MAX_PATH; |
| + if (QueryFullProcessImageName(process.Handle(), 0, exe_name_other, |
| + &exe_name_other_len) == 0) { |
| + DWORD error = GetLastError(); |
|
grt (UTC plus 2)
2016/04/05 17:22:07
remove this
manzagop (departed)
2016/04/06 19:36:02
Done.
|
| + 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.
|
| + return; |
| + } |
| + // Note: FilePath handles the complexity of path comparision (eg case). |
| + 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
|
| + return; |
| + |
| + // Only report on canary (or unspecified). |
| + 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.
|
| + if (channel != version_info::Channel::UNKNOWN && |
| + channel != version_info::Channel::CANARY) { |
| + return; |
| + } |
| + |
| + // Initialize a reporter, capture a report and shutdown the reporter. |
| + base::FilePath watcher_data_directory; |
| + if (PathService::Get(chrome::DIR_WATCHER_DATA, &watcher_data_directory)) { |
| + base::string16 endpoint = |
| + L"chrome_kasko_rdv_" + |
| + base::UintToString16(base::Process::Current().Pid()); |
| + |
| + bool launched_kasko = InitializeKaskoReporter( |
| + endpoint, watcher_data_directory.value().c_str()); |
| + if (launched_kasko) { |
| + DumpHungProcess(thread_id, installer::kChromeChannelCanary, L"failed-rdv", |
| + process); |
| + // We immediately request Kasko shutdown. This may block until the |
| + // 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.
|
| + // not uploaded by this reporter, any other Kasko reporter may upload it. |
| + ShutdownKaskoReporter(); |
| + } |
| + } |
| +} |
| +#endif // BUILDFLAG(ENABLE_KASKO_FAILED_RDV_REPORTS) |
| +#endif // BUILDFLAG(ENABLE_KASKO) |
| + |
| } // namespace |
| // Microsoft's Softricity virtualization breaks the sandbox processes. |
| @@ -249,15 +316,27 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() { |
| break; |
| } |
| + // 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?! ;)
|
| DWORD process_id = 0; |
| DWORD thread_id = ::GetWindowThreadProcessId(remote_window_, &process_id); |
| if (!thread_id || !process_id) { |
| remote_window_ = NULL; |
| return PROCESS_NONE; |
| } |
| + |
| + // Get a handle to the process that created the window. |
| base::Process process = base::Process::Open(process_id); |
| - // The window is hung. Scan for every window to find a visible one. |
| + // Optionally send a failed rendez-vous report. |
| + // Note: we nominate the thread that created the window as the root of the |
| + // search for a hung thread. |
| +#if BUILDFLAG(ENABLE_KASKO) |
| +#if BUILDFLAG(ENABLE_KASKO_FAILED_RDV_REPORTS) |
| + SendFailedRdvReport(process, thread_id); |
| +#endif // BUILDFLAG(ENABLE_KASKO_FAILED_RDV_REPORTS) |
| +#endif // BUILDFLAG(ENABLE_KASKO) |
| + |
| + // Scan for every window to find a visible one. |
| bool visible_window = false; |
| ::EnumThreadWindows(thread_id, |
| &BrowserWindowEnumeration, |