blob: bbe23fb1e10b3e1c29d8c6e5605a1a698f32f400 [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_trace_processor.h"
#include "components/input/features.h"
#include "components/input/utils.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
namespace input {
class InputBrowserTest : public content::ContentBrowserTest {
public:
bool IsRenderInputRouterCreatedOnViz() {
base::test::TestTraceProcessor ttp;
ttp.StartTrace("input");
content::RenderFrameSubmissionObserver render_frame_submission_observer(
shell()->web_contents());
EXPECT_TRUE(content::NavigateToURL(
shell(), GURL("data:text/html,<!doctype html>"
"<body style='background-color: magenta;'></body>")));
if (render_frame_submission_observer.render_frame_count() == 0) {
render_frame_submission_observer.WaitForAnyFrameSubmission();
}
absl::Status status = ttp.StopAndParseTrace();
EXPECT_TRUE(status.ok()) << status.message();
std::string query = R"(SELECT COUNT(*) as cnt
FROM slice
JOIN thread_track ON slice.track_id = thread_track.id
JOIN thread USING(utid)
WHERE slice.name = 'RenderInputRouter::RenderInputRouter'
AND thread.name = 'VizCompositorThread'
)";
auto result = ttp.RunQuery(query);
EXPECT_TRUE(result.has_value());
// `result.value()` would look something like this: {{"cnt"}, {"<num>"}.
EXPECT_EQ(result.value().size(), 2u);
EXPECT_EQ(result.value()[1].size(), 1u);
const std::string slice_count = result.value()[1][0];
return slice_count == "1";
}
};
#if !BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_F(InputBrowserTest,
RenderInputRouterNotCreatedOnNonAndroid) {
EXPECT_FALSE(IsRenderInputRouterCreatedOnViz());
}
#else
class AndroidInputBrowserTest : public InputBrowserTest,
public ::testing::WithParamInterface<bool> {
public:
AndroidInputBrowserTest() {
scoped_feature_list_.InitWithFeatureState(features::kInputOnViz,
/* enabled= */ GetParam());
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
IN_PROC_BROWSER_TEST_P(AndroidInputBrowserTest, RenderInputRouterCreation) {
const bool expected_creation = InputUtils::IsTransferInputToVizSupported();
EXPECT_EQ(IsRenderInputRouterCreatedOnViz(), expected_creation);
}
// Tests whether RenderWidgetHostInputEventRouter was created with different
// grouping id's for different WebContents.
IN_PROC_BROWSER_TEST_P(AndroidInputBrowserTest,
RenderWidgetHostInputEventRouterCreated) {
base::test::TestTraceProcessor ttp;
ttp.StartTrace("viz");
GURL url = GURL(
"data:text/html,<!doctype html>"
"<body style='background-color: magenta;'></body>");
// Loads a URL in two separate web contents.
{
content::RenderFrameSubmissionObserver render_frame_submission_observer(
shell()->web_contents());
ASSERT_TRUE(NavigateToURL(shell(), url));
if (render_frame_submission_observer.render_frame_count() == 0) {
render_frame_submission_observer.WaitForAnyFrameSubmission();
}
}
{
auto* second_shell = content::Shell::CreateNewWindow(
shell()->web_contents()->GetBrowserContext(), url, nullptr, {800, 600});
content::RenderFrameSubmissionObserver render_frame_submission_observer(
second_shell->web_contents());
if (render_frame_submission_observer.render_frame_count() == 0) {
render_frame_submission_observer.WaitForAnyFrameSubmission();
}
}
absl::Status status = ttp.StopAndParseTrace();
EXPECT_TRUE(status.ok()) << status.message();
// Select the count of distinct grouping_id's.
std::string query = R"(
SELECT COUNT(DISTINCT EXTRACT_ARG(arg_set_id, 'debug.grouping_id'))
AS distinct_grouping_ids
FROM slice
WHERE slice.name = 'RenderWidgetHostInputEventRouterCreated'
)";
auto result = ttp.RunQuery(query);
EXPECT_TRUE(result.has_value());
// `result.value()` would look something like this: {{"id"}, {"<num>"},
// {"<num>"}}.
EXPECT_EQ(result.value()[0].size(), 1u);
if (InputUtils::IsTransferInputToVizSupported()) {
EXPECT_EQ(result.value().size(), 2u);
// Expect the distinct grouping_id count to be 2 for different WebContents.
EXPECT_THAT(
result.value(),
testing::ElementsAre(testing::ElementsAre("distinct_grouping_ids"),
testing::ElementsAre("2")));
} else {
EXPECT_EQ(result.value().size(), 2u);
EXPECT_THAT(
result.value(),
testing::ElementsAre(testing::ElementsAre("distinct_grouping_ids"),
testing::ElementsAre("0")));
}
}
IN_PROC_BROWSER_TEST_P(AndroidInputBrowserTest, AndroidInputReceiverCreated) {
base::HistogramTester histogram_tester;
content::RenderFrameSubmissionObserver render_frame_submission_observer(
shell()->web_contents());
EXPECT_TRUE(content::NavigateToURL(
shell(), GURL("data:text/html,<!doctype html>"
"<body style='background-color: magenta;'></body>")));
if (render_frame_submission_observer.render_frame_count() == 0) {
render_frame_submission_observer.WaitForAnyFrameSubmission();
}
// By this point a root compositor frame sink should have been created as
// well, and if an input receiver were to be created it should have been
// since it happens when root compositor frame sink is created.
const int expected_count =
InputUtils::IsTransferInputToVizSupported() ? 1 : 0;
content::FetchHistogramsFromChildProcesses();
histogram_tester.ExpectUniqueSample(
"Android.InputOnViz.InputReceiverCreationResult",
/*kSuccessfullyCreated*/ 0, expected_count);
}
IN_PROC_BROWSER_TEST_P(AndroidInputBrowserTest,
VizInputTransferTokenReceivedOnBrowser) {
base::test::TestTraceProcessor ttp;
ttp.StartTrace("input,Java");
content::RenderFrameSubmissionObserver render_frame_submission_observer(
shell()->web_contents());
EXPECT_TRUE(content::NavigateToURL(
shell(), GURL("data:text/html,<!doctype html>"
"<body style='background-color: magenta;'></body>")));
if (render_frame_submission_observer.render_frame_count() == 0) {
render_frame_submission_observer.WaitForAnyFrameSubmission();
}
// By this point a root compositor frame sink should have been created as
// well, and if an input receiver were to be created it should have been
// since it happens when root compositor frame sink is created.
absl::Status status = ttp.StopAndParseTrace();
EXPECT_TRUE(status.ok()) << status.message();
std::string query = R"(SELECT COUNT(*) as cnt
FROM slice
WHERE slice.name = 'Storing InputTransferToken')";
auto result = ttp.RunQuery(query);
EXPECT_TRUE(result.has_value());
// `result.value()` would look something like this: {{"cnt"}, {"<num>"}.
EXPECT_EQ(result.value().size(), 2u);
EXPECT_EQ(result.value()[1].size(), 1u);
const std::string slice_count = result.value()[1][0];
const std::string expected_count =
InputUtils::IsTransferInputToVizSupported() ? "1" : "0";
EXPECT_EQ(slice_count, expected_count);
}
// TODO(crbug.com/381039758): Re-enable after investigation.
IN_PROC_BROWSER_TEST_P(AndroidInputBrowserTest,
DISABLED_ReuseSingleInputReceiver) {
base::HistogramTester histogram_tester;
GURL url = GURL(
"data:text/html,<!doctype html>"
"<body style='background-color: magenta;'></body>");
{
content::RenderFrameSubmissionObserver render_frame_submission_observer(
shell()->web_contents());
EXPECT_TRUE(content::NavigateToURL(shell(), url));
if (render_frame_submission_observer.render_frame_count() == 0) {
render_frame_submission_observer.WaitForAnyFrameSubmission();
}
}
auto* second_shell = content::Shell::CreateNewWindow(
shell()->web_contents()->GetBrowserContext(), url, nullptr, {800, 600});
{
content::RenderFrameSubmissionObserver render_frame_submission_observer(
second_shell->web_contents());
if (render_frame_submission_observer.render_frame_count() == 0) {
render_frame_submission_observer.WaitForAnyFrameSubmission();
}
}
const int expected_count =
InputUtils::IsTransferInputToVizSupported() ? 1 : 0;
content::FetchHistogramsFromChildProcesses();
histogram_tester.ExpectBucketCount(
"Android.InputOnViz.InputReceiverCreationResult",
/*kReuseExistingInputReceiver*/ 7, expected_count);
}
INSTANTIATE_TEST_SUITE_P(All,
AndroidInputBrowserTest,
::testing::Bool(),
[](auto& info) {
return info.param ? "InputOnViz_Enabled"
: "InputOnViz_Disabled";
});
#endif // !BUILDFLAG(IS_ANDROID)
} // namespace input