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, |