Commit 7d036129 authored by Greg Thompson's avatar Greg Thompson Committed by Commit Bot

Dump the contents of foreground windows that interfere with ShowAndFocusNativeWindow.

ShowAndFocusNativeWindow often fails on Win 10 bots with an indication
that the foreground window is owned by OpenWith.exe. We don't understand
why this dialog is onscreen. It appears to be leftover from a previous
test on the bot. This CL here includes a textual representation of the
UI accessibility tree of the foreground window when
ShowAndFocusNativeWindow fails. This should shed some light on what the
dialog is asking for. With luck, this understanding will help us find
the culprit and/or close the window so that interactive_ui_tests can
proceed.

BUG=711256
R=sky@chromium.org

Change-Id: If81cca9f8a97c0e25d3810c47416ec37a8bdc2c7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1609898
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@{#659203}
parent 31099d6f
......@@ -5075,6 +5075,8 @@ if (!is_android) {
"base/interactive_ui_tests_main.cc",
"base/save_desktop_snapshot_win.cc",
"base/save_desktop_snapshot_win.h",
"base/window_contents_as_string_win.cc",
"base/window_contents_as_string_win.h",
"ppapi/ppapi_interactive_browsertest.cc",
]
......@@ -5869,6 +5871,8 @@ if (!is_android && !is_fuchsia) {
"base/interactive_test_utils_mac.mm",
"base/interactive_test_utils_win.cc",
"base/interactive_ui_tests_main.cc",
"base/window_contents_as_string_win.cc",
"base/window_contents_as_string_win.h",
]
if (use_aura) {
......
......@@ -14,6 +14,7 @@
#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"
#include "chrome/test/base/window_contents_as_string_win.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/test/ui_controls.h"
#include "ui/base/win/foreground_helper.h"
......@@ -56,6 +57,7 @@ bool ShowAndFocusNativeWindow(gfx::NativeWindow window) {
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);
......@@ -64,9 +66,13 @@ bool ShowAndFocusNativeWindow(gfx::NativeWindow window) {
lineage_str = STRING16_LITERAL(", process lineage: ");
lineage_str.append(lineage.ToString());
}
window_contents = WindowContentsAsString(foreground_window);
}
LOG(ERROR) << "ShowAndFocusNativeWindow failed. foreground window: "
<< foreground_window << ", title: " << window_title << lineage_str;
<< foreground_window << ", title: " << window_title << lineage_str
<< ", contents:" << std::endl
<< window_contents;
const base::FilePath output_dir =
base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/test/base/window_contents_as_string_win.h"
// Needed for <uiautomation.h>
#include <objbase.h>
#include <uiautomation.h>
#include <wrl/client.h>
#include <utility>
#include "base/logging.h"
#include "base/win/com_init_util.h"
#include "base/win/scoped_bstr.h"
#include "base/win/scoped_variant.h"
namespace {
// IDs corresponding to the properties read by CachedElementContentsAsString.
constexpr long kCachedProperties[] = {
UIA_LocalizedControlTypePropertyId,
UIA_NamePropertyId,
UIA_IsInvokePatternAvailablePropertyId,
};
// Returns a string representation of the cached properties of |element|.
base::string16 CachedElementContentsAsString(IUIAutomationElement* element) {
base::string16 contents;
base::win::ScopedVariant variant;
HRESULT result = element->GetCachedPropertyValue(
UIA_IsInvokePatternAvailablePropertyId, variant.Receive());
if (SUCCEEDED(result) && variant.type() == VT_BOOL &&
V_BOOL(variant.ptr()) == VARIANT_TRUE) {
contents.append(STRING16_LITERAL("[invokable] "));
}
base::win::ScopedBstr value;
result = element->get_CachedLocalizedControlType(value.Receive());
if (SUCCEEDED(result))
contents.append(STRING16_LITERAL("type: ")).append(value);
value.Reset();
result = element->get_CachedName(value.Receive());
if (SUCCEEDED(result)) {
if (!contents.empty())
contents.append(STRING16_LITERAL(", "));
contents.append(STRING16_LITERAL("name: ")).append(value);
}
return contents;
}
void TreeAsString(IUIAutomationTreeWalker* walker,
IUIAutomationCacheRequest* cache_request,
IUIAutomationElement* element,
const base::string16& padding,
base::string16* contents) {
contents->append(padding)
.append(CachedElementContentsAsString(element))
.append(STRING16_LITERAL("\n"));
Microsoft::WRL::ComPtr<IUIAutomationElement> child_element;
HRESULT result = walker->GetFirstChildElementBuildCache(
element, cache_request, &child_element);
if (FAILED(result))
return;
const base::string16 next_padding = padding + STRING16_LITERAL(" ");
while (child_element.Get()) {
TreeAsString(walker, cache_request, child_element.Get(), next_padding,
contents);
Microsoft::WRL::ComPtr<IUIAutomationElement> next_element;
result = walker->GetNextSiblingElementBuildCache(
child_element.Get(), cache_request, &next_element);
if (FAILED(result))
return;
child_element = std::move(next_element);
}
}
} // namespace
base::string16 WindowContentsAsString(HWND window_handle) {
DCHECK(window_handle);
base::win::AssertComInitialized();
Microsoft::WRL::ComPtr<IUIAutomation> automation;
HRESULT result =
::CoCreateInstance(CLSID_CUIAutomation, nullptr, CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&automation));
if (FAILED(result))
return base::string16();
Microsoft::WRL::ComPtr<IUIAutomationCacheRequest> cache_request;
result = automation->CreateCacheRequest(&cache_request);
if (FAILED(result))
return base::string16();
for (auto property_id : kCachedProperties)
cache_request->AddProperty(property_id);
Microsoft::WRL::ComPtr<IUIAutomationElement> window_element;
result = automation->ElementFromHandleBuildCache(
window_handle, cache_request.Get(), &window_element);
if (FAILED(result))
return base::string16();
Microsoft::WRL::ComPtr<IUIAutomationTreeWalker> walker;
result = automation->get_RawViewWalker(&walker);
if (FAILED(result))
return base::string16();
base::string16 contents;
TreeAsString(walker.Get(), cache_request.Get(), window_element.Get(),
base::string16(), &contents);
// Strip the trailing newline.
if (!contents.empty())
contents.pop_back();
return contents;
}
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_TEST_BASE_WINDOW_CONTENTS_AS_STRING_WIN_H_
#define CHROME_TEST_BASE_WINDOW_CONTENTS_AS_STRING_WIN_H_
#include "base/strings/string16.h"
#include "base/win/windows_types.h"
// Returns a string representation of the contents of |window| on the basis of
// the elements it exposes via UI automation, or an empty string in case of
// error. In particular, the control type and title of the window's element and
// each UI element within it is emitted, indented an amount corresponding to its
// depth in the UI hierarchy. Elements that are invokable (e.g., buttons) are
// labeled as such. For example:
// type: window, name: Windows can't open this type of file (.adm)
// type: pane, name: Flyout window
// type: pane, name:
// type: pane, name: Immersive Openwith Flyout
// type: text, name: Windows can't open this type of file (.adm)
// type: pane, name:
// type: list, name:
// type: list, name:
// [invokable] type: link, name: More apps
// [invokable] type: button, name: OK
base::string16 WindowContentsAsString(HWND window_handle);
#endif // CHROME_TEST_BASE_WINDOW_CONTENTS_AS_STRING_WIN_H_
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