
bind.h, callback.h, callback_forward.h, and callback_helpers.h moved into /base/functional/. Update the include paths to directly include them in their new location. Bug: 1364441 Change-Id: I32ec425b9c0e52ec4b50047bf3290fecc5c905ff Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4148554 Reviewed-by: Daniel Cheng <dcheng@chromium.org> Auto-Submit: Avi Drissman <avi@chromium.org> Owners-Override: Avi Drissman <avi@chromium.org> Owners-Override: Daniel Cheng <dcheng@chromium.org> Commit-Queue: Daniel Cheng <dcheng@chromium.org> Cr-Commit-Position: refs/heads/main@{#1091567}
302 lines
11 KiB
C++
302 lines
11 KiB
C++
// Copyright 2017 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include <utility>
|
|
|
|
#include "base/functional/bind.h"
|
|
#include "base/functional/callback_helpers.h"
|
|
#include "base/run_loop.h"
|
|
#include "base/strings/utf_string_conversions.h"
|
|
#include "content/browser/renderer_host/render_process_host_impl.h"
|
|
#include "content/browser/utility_process_host.h"
|
|
#include "content/public/browser/browser_child_process_host.h"
|
|
#include "content/public/browser/browser_task_traits.h"
|
|
#include "content/public/browser/browser_thread.h"
|
|
#include "content/public/browser/child_process_data.h"
|
|
#include "content/public/browser/gpu_service_registry.h"
|
|
#include "content/public/browser/render_frame_host.h"
|
|
#include "content/public/browser/render_process_host.h"
|
|
#include "content/public/browser/web_contents.h"
|
|
#include "content/public/common/content_features.h"
|
|
#include "content/public/common/process_type.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"
|
|
#include "content/shell/common/power_monitor_test.mojom.h"
|
|
#include "mojo/public/cpp/bindings/pending_receiver.h"
|
|
#include "mojo/public/cpp/bindings/pending_remote.h"
|
|
#include "mojo/public/cpp/bindings/receiver_set.h"
|
|
#include "mojo/public/cpp/bindings/remote.h"
|
|
#include "mojo/public/cpp/bindings/remote_set.h"
|
|
#include "services/device/public/mojom/power_monitor.mojom.h"
|
|
|
|
namespace content {
|
|
|
|
namespace {
|
|
|
|
void VerifyPowerStateInChildProcess(mojom::PowerMonitorTest* power_monitor_test,
|
|
bool expected_state) {
|
|
base::RunLoop run_loop;
|
|
power_monitor_test->QueryNextState(base::BindOnce(
|
|
[](base::RunLoop* loop, bool expected_state, bool on_battery_power) {
|
|
EXPECT_EQ(expected_state, on_battery_power);
|
|
loop->Quit();
|
|
},
|
|
&run_loop, expected_state));
|
|
run_loop.Run();
|
|
}
|
|
|
|
class MockPowerMonitorMessageBroadcaster : public device::mojom::PowerMonitor {
|
|
public:
|
|
MockPowerMonitorMessageBroadcaster() = default;
|
|
|
|
MockPowerMonitorMessageBroadcaster(
|
|
const MockPowerMonitorMessageBroadcaster&) = delete;
|
|
MockPowerMonitorMessageBroadcaster& operator=(
|
|
const MockPowerMonitorMessageBroadcaster&) = delete;
|
|
|
|
~MockPowerMonitorMessageBroadcaster() override = default;
|
|
|
|
void Bind(mojo::PendingReceiver<device::mojom::PowerMonitor> receiver) {
|
|
receivers_.Add(this, std::move(receiver));
|
|
}
|
|
|
|
// device::mojom::PowerMonitor:
|
|
void AddClient(mojo::PendingRemote<device::mojom::PowerMonitorClient>
|
|
pending_power_monitor_client) override {
|
|
mojo::Remote<device::mojom::PowerMonitorClient> power_monitor_client(
|
|
std::move(pending_power_monitor_client));
|
|
power_monitor_client->PowerStateChange(on_battery_power_);
|
|
clients_.Add(std::move(power_monitor_client));
|
|
}
|
|
|
|
void OnPowerStateChange(bool on_battery_power) {
|
|
on_battery_power_ = on_battery_power;
|
|
for (auto& client : clients_)
|
|
client->PowerStateChange(on_battery_power);
|
|
}
|
|
|
|
private:
|
|
bool on_battery_power_ = false;
|
|
|
|
mojo::ReceiverSet<device::mojom::PowerMonitor> receivers_;
|
|
mojo::RemoteSet<device::mojom::PowerMonitorClient> clients_;
|
|
};
|
|
|
|
class PowerMonitorTest : public ContentBrowserTest {
|
|
public:
|
|
PowerMonitorTest() {
|
|
// Intercept PowerMonitor binding requests from all types of child
|
|
// processes.
|
|
RenderProcessHost::InterceptBindHostReceiverForTesting(base::BindRepeating(
|
|
&PowerMonitorTest::BindForRenderer, base::Unretained(this)));
|
|
BrowserChildProcessHost::InterceptBindHostReceiverForTesting(
|
|
base::BindRepeating(&PowerMonitorTest::BindForNonRenderer,
|
|
base::Unretained(this)));
|
|
}
|
|
|
|
PowerMonitorTest(const PowerMonitorTest&) = delete;
|
|
PowerMonitorTest& operator=(const PowerMonitorTest&) = delete;
|
|
|
|
~PowerMonitorTest() override {
|
|
RenderProcessHost::InterceptBindHostReceiverForTesting(
|
|
base::NullCallback());
|
|
BrowserChildProcessHost::InterceptBindHostReceiverForTesting(
|
|
base::NullCallback());
|
|
}
|
|
|
|
void BindForRenderer(int render_process_id,
|
|
mojo::GenericPendingReceiver* receiver) {
|
|
auto r = receiver->As<device::mojom::PowerMonitor>();
|
|
if (!r)
|
|
return;
|
|
|
|
GetUIThreadTaskRunner({})->PostTask(
|
|
FROM_HERE,
|
|
base::BindOnce(&PowerMonitorTest::BindForRendererOnMainThread,
|
|
base::Unretained(this), std::move(r)));
|
|
}
|
|
|
|
void BindForNonRenderer(BrowserChildProcessHost* process_host,
|
|
mojo::GenericPendingReceiver* receiver) {
|
|
auto r = receiver->As<device::mojom::PowerMonitor>();
|
|
if (!r)
|
|
return;
|
|
|
|
GetUIThreadTaskRunner({})->PostTask(
|
|
FROM_HERE,
|
|
base::BindOnce(&PowerMonitorTest::BindForNonRendererOnMainThread,
|
|
base::Unretained(this),
|
|
process_host->GetData().process_type, std::move(r)));
|
|
}
|
|
|
|
protected:
|
|
void StartUtilityProcess(
|
|
mojo::Remote<mojom::PowerMonitorTest>* power_monitor_test,
|
|
base::OnceClosure utility_bound_closure) {
|
|
utility_bound_closure_ = std::move(utility_bound_closure);
|
|
|
|
UtilityProcessHost* host = new UtilityProcessHost();
|
|
host->SetMetricsName("test_process");
|
|
host->SetName(u"TestProcess");
|
|
EXPECT_TRUE(host->Start());
|
|
|
|
host->GetChildProcess()->BindReceiver(
|
|
power_monitor_test->BindNewPipeAndPassReceiver());
|
|
}
|
|
|
|
void set_renderer_bound_closure(base::OnceClosure closure) {
|
|
renderer_bound_closure_ = std::move(closure);
|
|
}
|
|
|
|
void set_gpu_bound_closure(base::OnceClosure closure) {
|
|
gpu_bound_closure_ = std::move(closure);
|
|
}
|
|
|
|
int request_count_from_renderer() { return request_count_from_renderer_; }
|
|
int request_count_from_utility() { return request_count_from_utility_; }
|
|
int request_count_from_gpu() { return request_count_from_gpu_; }
|
|
|
|
void SimulatePowerStateChange(bool on_battery_power) {
|
|
power_monitor_message_broadcaster_.OnPowerStateChange(on_battery_power);
|
|
}
|
|
|
|
private:
|
|
void BindForRendererOnMainThread(
|
|
mojo::PendingReceiver<device::mojom::PowerMonitor> receiver) {
|
|
// We can receiver binding requests for the spare RenderProcessHost -- this
|
|
// might happen before the test has provided the |renderer_bound_closure_|.
|
|
if (renderer_bound_closure_) {
|
|
++request_count_from_renderer_;
|
|
std::move(renderer_bound_closure_).Run();
|
|
} else {
|
|
DCHECK(RenderProcessHostImpl::GetSpareRenderProcessHostForTesting());
|
|
}
|
|
|
|
power_monitor_message_broadcaster_.Bind(std::move(receiver));
|
|
}
|
|
|
|
void BindForNonRendererOnMainThread(
|
|
int process_type,
|
|
mojo::PendingReceiver<device::mojom::PowerMonitor> receiver) {
|
|
if (process_type == PROCESS_TYPE_UTILITY) {
|
|
if (utility_bound_closure_) {
|
|
++request_count_from_utility_;
|
|
std::move(utility_bound_closure_).Run();
|
|
}
|
|
} else if (process_type == PROCESS_TYPE_GPU) {
|
|
++request_count_from_gpu_;
|
|
|
|
// We ignore null gpu_bound_closure_ here for two possible scenarios:
|
|
// - TestRendererProcess and TestUtilityProcess also result in spinning
|
|
// up GPU processes as a side effect, but they do not set valid
|
|
// gpu_bound_closure_.
|
|
// - As GPU process is started during setup of browser test suite, so
|
|
// it's possible that TestGpuProcess execution may have not started
|
|
// yet when the PowerMonitor bind request comes here, in such case
|
|
// gpu_bound_closure_ will also be null.
|
|
if (gpu_bound_closure_)
|
|
std::move(gpu_bound_closure_).Run();
|
|
}
|
|
|
|
power_monitor_message_broadcaster_.Bind(std::move(receiver));
|
|
}
|
|
|
|
int request_count_from_renderer_ = 0;
|
|
int request_count_from_utility_ = 0;
|
|
int request_count_from_gpu_ = 0;
|
|
base::OnceClosure renderer_bound_closure_;
|
|
base::OnceClosure gpu_bound_closure_;
|
|
base::OnceClosure utility_bound_closure_;
|
|
|
|
MockPowerMonitorMessageBroadcaster power_monitor_message_broadcaster_;
|
|
};
|
|
|
|
IN_PROC_BROWSER_TEST_F(PowerMonitorTest, TestRendererProcess) {
|
|
ASSERT_EQ(0, request_count_from_renderer());
|
|
base::RunLoop run_loop;
|
|
set_renderer_bound_closure(run_loop.QuitClosure());
|
|
ASSERT_TRUE(NavigateToURL(shell(), GetTestUrl(".", "simple_page.html")));
|
|
run_loop.Run();
|
|
EXPECT_EQ(1, request_count_from_renderer());
|
|
|
|
mojo::Remote<mojom::PowerMonitorTest> power_monitor_renderer;
|
|
RenderProcessHost* rph =
|
|
shell()->web_contents()->GetPrimaryMainFrame()->GetProcess();
|
|
rph->BindReceiver(power_monitor_renderer.BindNewPipeAndPassReceiver());
|
|
|
|
// Ensure that the PowerMonitorTestImpl instance has been created and is
|
|
// observing power state changes in the child process before simulating a
|
|
// power state change.
|
|
power_monitor_renderer.FlushForTesting();
|
|
|
|
SimulatePowerStateChange(true);
|
|
// Verify renderer process on_battery_power changed to true.
|
|
VerifyPowerStateInChildProcess(power_monitor_renderer.get(), true);
|
|
|
|
SimulatePowerStateChange(false);
|
|
// Verify renderer process on_battery_power changed to false.
|
|
VerifyPowerStateInChildProcess(power_monitor_renderer.get(), false);
|
|
}
|
|
|
|
IN_PROC_BROWSER_TEST_F(PowerMonitorTest, TestUtilityProcess) {
|
|
mojo::Remote<mojom::PowerMonitorTest> power_monitor_utility;
|
|
|
|
ASSERT_EQ(0, request_count_from_utility());
|
|
base::RunLoop run_loop;
|
|
StartUtilityProcess(&power_monitor_utility, run_loop.QuitClosure());
|
|
run_loop.Run();
|
|
EXPECT_EQ(1, request_count_from_utility());
|
|
|
|
// Ensure that the PowerMonitorTestImpl instance has been created and is
|
|
// observing power state changes in the child process before simulating a
|
|
// power state change.
|
|
power_monitor_utility.FlushForTesting();
|
|
|
|
SimulatePowerStateChange(true);
|
|
// Verify utility process on_battery_power changed to true.
|
|
VerifyPowerStateInChildProcess(power_monitor_utility.get(), true);
|
|
|
|
SimulatePowerStateChange(false);
|
|
// Verify utility process on_battery_power changed to false.
|
|
VerifyPowerStateInChildProcess(power_monitor_utility.get(), false);
|
|
}
|
|
|
|
IN_PROC_BROWSER_TEST_F(PowerMonitorTest, TestGpuProcess) {
|
|
// As gpu process is started automatically during the setup period of browser
|
|
// test suite, it may have already started and bound PowerMonitor interface to
|
|
// Device Service before execution of this TestGpuProcess test. So here we
|
|
// do not wait for the connection if we found it has already been established.
|
|
if (request_count_from_gpu() != 1) {
|
|
ASSERT_EQ(0, request_count_from_gpu());
|
|
base::RunLoop run_loop;
|
|
set_gpu_bound_closure(run_loop.QuitClosure());
|
|
// Wait for the connection from gpu process.
|
|
run_loop.Run();
|
|
}
|
|
EXPECT_EQ(1, request_count_from_gpu());
|
|
|
|
mojo::Remote<mojom::PowerMonitorTest> power_monitor_gpu;
|
|
BindInterfaceInGpuProcess(power_monitor_gpu.BindNewPipeAndPassReceiver());
|
|
|
|
// Ensure that the PowerMonitorTestImpl instance has been created and is
|
|
// observing power state changes in the child process before simulating a
|
|
// power state change.
|
|
power_monitor_gpu.FlushForTesting();
|
|
|
|
SimulatePowerStateChange(true);
|
|
// Verify gpu process on_battery_power changed to true.
|
|
VerifyPowerStateInChildProcess(power_monitor_gpu.get(), true);
|
|
|
|
SimulatePowerStateChange(false);
|
|
// Verify gpu process on_battery_power changed to false.
|
|
VerifyPowerStateInChildProcess(power_monitor_gpu.get(), false);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
} // namespace content
|