Commit a2ce45b0 authored by Greg Thompson's avatar Greg Thompson Committed by Commit Bot

Attempt to close windows that get in the way of focusing a native window.

From time to time, a stray window is left behind on the Windows 10 bots
that interferes with interactive_ui_tests (it's usually an OpenWith.exe
dialog asking the user to pick an app to open some file/URL protocol).
This change augments ShowAndFocusNativeWindow so that it makes up to
five attempts to close any window that remains in the foreground despite
its best efforts to bring the desired NativeWindow to the foreground.

BUG=711256
R=sky@chromium.org

Change-Id: Iccb568f34c66b5d0571d6d4dc3648c7b06ac35de
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1610766
Commit-Queue: Greg Thompson <grt@chromium.org>
Auto-Submit: Greg Thompson <grt@chromium.org>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Cr-Commit-Position: refs/heads/master@{#659635}
parent b56d280c
......@@ -6,11 +6,19 @@
#include <Psapi.h>
#include <memory>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/process/process_handle.h"
#include "base/stl_util.h"
#include "base/test/test_timeouts.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "chrome/test/base/interactive_test_utils_aura.h"
#include "chrome/test/base/process_lineage_win.h"
#include "chrome/test/base/save_desktop_snapshot_win.h"
......@@ -41,48 +49,103 @@ bool ShowAndFocusNativeWindow(gfx::NativeWindow window) {
::ShowWindow(hwnd, SW_SHOW);
if (GetForegroundWindow() != hwnd) {
int attempts_left = 5;
bool have_snapshot = false;
while (true) {
if (::GetForegroundWindow() == hwnd)
return true;
VLOG(1) << "Forcefully refocusing front window";
ui::ForegroundHelper::SetForeground(hwnd);
}
// ShowWindow does not necessarily activate the window. In particular if a
// window from another app is the foreground window then the request to
// activate the window fails. See SetForegroundWindow for details.
HWND foreground_window = GetForegroundWindow();
if (foreground_window == hwnd)
return true;
wchar_t window_title[256];
GetWindowText(foreground_window, window_title, base::size(window_title));
base::string16 lineage_str;
base::string16 window_contents;
if (foreground_window) {
DWORD process_id = 0;
GetWindowThreadProcessId(foreground_window, &process_id);
ProcessLineage lineage = ProcessLineage::Create(process_id);
if (!lineage.IsEmpty()) {
lineage_str = STRING16_LITERAL(", process lineage: ");
lineage_str.append(lineage.ToString());
// ShowWindow does not necessarily activate the window. In particular if a
// window from another app is the foreground window then the request to
// activate the window fails. See SetForegroundWindow for details.
HWND foreground_window = ::GetForegroundWindow();
if (foreground_window == hwnd)
return true;
// Emit some diagnostic information about the foreground window and its
// owning process.
wchar_t window_title[256];
GetWindowText(foreground_window, window_title, base::size(window_title));
base::string16 lineage_str;
base::string16 window_contents;
DWORD foreground_process_id = 0;
if (foreground_window) {
GetWindowThreadProcessId(foreground_window, &foreground_process_id);
ProcessLineage lineage = ProcessLineage::Create(foreground_process_id);
if (!lineage.IsEmpty()) {
lineage_str = STRING16_LITERAL(", process lineage: ");
lineage_str.append(lineage.ToString());
}
window_contents = WindowContentsAsString(foreground_window);
}
LOG(ERROR) << "ShowAndFocusNativeWindow found a foreground window: "
<< foreground_window << ", title: " << window_title
<< lineage_str << ", contents:" << std::endl
<< window_contents;
window_contents = WindowContentsAsString(foreground_window);
}
LOG(ERROR) << "ShowAndFocusNativeWindow failed. foreground window: "
<< foreground_window << ", title: " << window_title << lineage_str
<< ", contents:" << std::endl
<< window_contents;
const base::FilePath output_dir =
base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
kSnapshotOutputDir);
if (!output_dir.empty()) {
base::FilePath snapshot_file = SaveDesktopSnapshot(output_dir);
if (!snapshot_file.empty()) {
LOG(ERROR) << "Screenshot saved to file: \"" << snapshot_file.value()
<< "\"";
// Take a snapshot of the screen.
const base::FilePath output_dir =
base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
kSnapshotOutputDir);
if (!have_snapshot && !output_dir.empty()) {
base::FilePath snapshot_file = SaveDesktopSnapshot(output_dir);
if (!snapshot_file.empty()) {
have_snapshot = true;
LOG(ERROR) << "Screenshot saved to file: \"" << snapshot_file.value()
<< "\"";
}
}
if (!attempts_left--) {
LOG(ERROR) << "ShowAndFocusNativeWindow failed after too many attempts.";
break;
}
// Give up if there is no foreground window or if it's mysteriously from
// this process.
if (!foreground_window) {
LOG(ERROR) << "ShowAndFocusNativeWindow failed to focus any window.";
break;
}
if (foreground_process_id == base::GetCurrentProcId()) {
LOG(ERROR) << "ShowAndFocusNativeWindow failed because another window in"
" the test process will not give up focus.";
break;
}
// Attempt to close the offending window.
::PostMessageW(foreground_window, WM_CLOSE, 0, 0);
// Poll to wait for the window to be destroyed. While it is possible to
// avoid polling via use of UI Automation to observe the closing of the
// window, the code to do so is non-trivial and requires use of another
// thread in the MTA.
base::RunLoop run_loop;
base::RepeatingTimer timer(
FROM_HERE, TestTimeouts::tiny_timeout(),
base::BindRepeating(
[](HWND foreground_window,
const base::RepeatingClosure& quit_closure, int* polls) {
if (!*polls-- || ::GetForegroundWindow() != foreground_window)
quit_closure.Run();
},
foreground_window, run_loop.QuitClosure(),
base::Owned(std::make_unique<int>(
TestTimeouts::action_timeout().InMicroseconds() /
TestTimeouts::tiny_timeout().InMicroseconds()))));
timer.Reset();
run_loop.Run();
if (::GetForegroundWindow() == foreground_window) {
LOG(ERROR) << "ShowAndFocusNativeWindow timed out closing the "
"foreground window.";
break;
}
// Otherwise, loop around and try focusing the desired window again.
}
return false;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment