blob: 19fa617b74c600914157ac9dcdb56f7977edfccd [file] [log] [blame]
leon.hana0c5fa32017-06-13 08:14:111// Copyright 2017 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/bind.h"
6#include "base/macros.h"
7#include "base/run_loop.h"
Han Leon18ea6202017-06-19 03:34:498#include "base/strings/utf_string_conversions.h"
Eric Seckler8652dcd52018-09-20 10:42:289#include "base/task/post_task.h"
Lukasz Anforowicz2b2699732018-04-12 18:49:1010#include "content/browser/renderer_host/render_process_host_impl.h"
Jay Civelli14aced2a2018-03-14 23:44:3311#include "content/browser/utility_process_host.h"
12#include "content/browser/utility_process_host_client.h"
Eric Seckler8652dcd52018-09-20 10:42:2813#include "content/public/browser/browser_task_traits.h"
Han Leon18ea6202017-06-19 03:34:4914#include "content/public/browser/browser_thread.h"
Han Leon43528ec2017-07-07 02:54:5715#include "content/public/browser/gpu_service_registry.h"
leon.hana0c5fa32017-06-13 08:14:1116#include "content/public/browser/render_frame_host.h"
17#include "content/public/browser/render_process_host.h"
18#include "content/public/browser/web_contents.h"
19#include "content/public/common/service_names.mojom.h"
20#include "content/public/test/browser_test_utils.h"
21#include "content/public/test/content_browser_test.h"
22#include "content/public/test/content_browser_test_utils.h"
23#include "content/shell/browser/shell.h"
24#include "content/shell/common/power_monitor_test.mojom.h"
25#include "mojo/public/cpp/bindings/binding_set.h"
26#include "mojo/public/cpp/bindings/interface_ptr_set.h"
Ke He31d0bb02018-02-24 07:16:2427#include "services/device/public/mojom/constants.mojom.h"
28#include "services/device/public/mojom/power_monitor.mojom.h"
leon.hana0c5fa32017-06-13 08:14:1129#include "services/service_manager/public/cpp/service_context.h"
30
31namespace content {
32
33namespace {
34
35void VerifyPowerStateInChildProcess(mojom::PowerMonitorTest* power_monitor_test,
36 bool expected_state) {
37 base::RunLoop run_loop;
tzike2aca992017-09-05 08:50:5438 power_monitor_test->QueryNextState(base::BindOnce(
leon.hana0c5fa32017-06-13 08:14:1139 [](const base::Closure& quit, bool expected_state,
40 bool on_battery_power) {
41 EXPECT_EQ(expected_state, on_battery_power);
42 quit.Run();
43 },
44 run_loop.QuitClosure(), expected_state));
45 run_loop.Run();
46}
47
Han Leon18ea6202017-06-19 03:34:4948void StartUtilityProcessOnIOThread(mojom::PowerMonitorTestRequest request) {
Jay Civelli14aced2a2018-03-14 23:44:3349 UtilityProcessHost* host =
50 new UtilityProcessHost(/*client=*/nullptr,
51 /*client_task_runner=*/nullptr);
Will Harrisedb011f2018-06-01 20:28:4452 host->SetMetricsName("test_process");
Han Leon18ea6202017-06-19 03:34:4953 host->SetName(base::ASCIIToUTF16("TestProcess"));
54 EXPECT_TRUE(host->Start());
55
56 BindInterface(host, std::move(request));
57}
58
Han Leon43528ec2017-07-07 02:54:5759void BindInterfaceForGpuOnIOThread(mojom::PowerMonitorTestRequest request) {
60 BindInterfaceInGpuProcess(std::move(request));
61}
62
leon.hana0c5fa32017-06-13 08:14:1163class MockPowerMonitorMessageBroadcaster : public device::mojom::PowerMonitor {
64 public:
65 MockPowerMonitorMessageBroadcaster() = default;
66 ~MockPowerMonitorMessageBroadcaster() override = default;
67
68 void Bind(device::mojom::PowerMonitorRequest request) {
69 bindings_.AddBinding(this, std::move(request));
70 }
71
72 // device::mojom::PowerMonitor:
73 void AddClient(
74 device::mojom::PowerMonitorClientPtr power_monitor_client) override {
75 power_monitor_client->PowerStateChange(on_battery_power_);
76 clients_.AddPtr(std::move(power_monitor_client));
77 }
78
79 void OnPowerStateChange(bool on_battery_power) {
80 on_battery_power_ = on_battery_power;
81 clients_.ForAllPtrs(
82 [&on_battery_power](device::mojom::PowerMonitorClient* client) {
83 client->PowerStateChange(on_battery_power);
84 });
85 }
86
87 private:
88 bool on_battery_power_ = false;
89
90 mojo::BindingSet<device::mojom::PowerMonitor> bindings_;
91 mojo::InterfacePtrSet<device::mojom::PowerMonitorClient> clients_;
92
93 DISALLOW_COPY_AND_ASSIGN(MockPowerMonitorMessageBroadcaster);
94};
95
96class PowerMonitorTest : public ContentBrowserTest {
97 public:
Reilly Grant633165602018-07-11 00:48:0398 PowerMonitorTest() {
leon.hana0c5fa32017-06-13 08:14:1199 // Because Device Service also runs in this process(browser process), we can
100 // set our binder to intercept requests for PowerMonitor interface to it.
101 service_manager::ServiceContext::SetGlobalBinderForTesting(
102 device::mojom::kServiceName, device::mojom::PowerMonitor::Name_,
103 base::Bind(&PowerMonitorTest::BindPowerMonitor,
104 base::Unretained(this)));
Reilly Grant633165602018-07-11 00:48:03105 }
Han Leon43528ec2017-07-07 02:54:57106
Reilly Grant633165602018-07-11 00:48:03107 ~PowerMonitorTest() override {
108 service_manager::ServiceContext::ClearGlobalBindersForTesting(
109 device::mojom::kServiceName);
leon.hana0c5fa32017-06-13 08:14:11110 }
111
Ben Goodger21ada1e2017-07-19 14:53:01112 void BindPowerMonitor(const std::string& interface_name,
113 mojo::ScopedMessagePipeHandle handle,
114 const service_manager::BindSourceInfo& source_info) {
Han Leon18ea6202017-06-19 03:34:49115 if (source_info.identity.name() == mojom::kRendererServiceName) {
Lukasz Anforowicz2b2699732018-04-12 18:49:10116 // We can receive binding requests for the spare RenderProcessHost - this
117 // might happen before the test has provided the
118 // |renderer_bound_closure_|.
119 if (renderer_bound_closure_) {
120 ++request_count_from_renderer_;
121 std::move(renderer_bound_closure_).Run();
122 } else {
123 DCHECK(RenderProcessHostImpl::GetSpareRenderProcessHostForTesting());
124 }
Han Leon18ea6202017-06-19 03:34:49125 } else if (source_info.identity.name() == mojom::kUtilityServiceName) {
John Abd-El-Malekef7a3da72018-04-25 13:40:08126 // If the network service is enabled, it will create utility processes
127 // without a utility closure.
128 if (utility_bound_closure_) {
129 ++request_count_from_utility_;
130 std::move(utility_bound_closure_).Run();
131 }
Han Leon43528ec2017-07-07 02:54:57132 } else if (source_info.identity.name() == mojom::kGpuServiceName) {
133 ++request_count_from_gpu_;
134
135 // We ignore null gpu_bound_closure_ here for two possible scenarios:
136 // - TestRendererProcess and TestUtilityProcess also result in spinning
137 // up GPU processes as a side effect, but they do not set valid
138 // gpu_bound_closure_.
139 // - As GPU process is started during setup of browser test suite, so
140 // it's possible that TestGpuProcess execution may have not started
141 // yet when the PowerMonitor bind request comes here, in such case
142 // gpu_bound_closure_ will also be null.
143 if (gpu_bound_closure_)
144 std::move(gpu_bound_closure_).Run();
Han Leon18ea6202017-06-19 03:34:49145 }
146
leon.hana0c5fa32017-06-13 08:14:11147 power_monitor_message_broadcaster_.Bind(
148 device::mojom::PowerMonitorRequest(std::move(handle)));
149 }
150
151 protected:
Han Leon18ea6202017-06-19 03:34:49152 void StartUtilityProcess(mojom::PowerMonitorTestPtr* power_monitor_test,
153 base::Closure utility_bound_closure) {
Tommy Nyquist4b749d02018-03-20 21:46:29154 utility_bound_closure_ = std::move(utility_bound_closure);
Eric Seckler8652dcd52018-09-20 10:42:28155 base::PostTaskWithTraits(
156 FROM_HERE, {BrowserThread::IO},
Han Leon18ea6202017-06-19 03:34:49157 base::BindOnce(&StartUtilityProcessOnIOThread,
158 mojo::MakeRequest(power_monitor_test)));
159 }
160
161 void set_renderer_bound_closure(base::Closure closure) {
Tommy Nyquist4b749d02018-03-20 21:46:29162 renderer_bound_closure_ = std::move(closure);
Han Leon18ea6202017-06-19 03:34:49163 }
164
Han Leon43528ec2017-07-07 02:54:57165 void set_gpu_bound_closure(base::Closure closure) {
Tommy Nyquist4b749d02018-03-20 21:46:29166 gpu_bound_closure_ = std::move(closure);
Han Leon43528ec2017-07-07 02:54:57167 }
168
leon.hana0c5fa32017-06-13 08:14:11169 int request_count_from_renderer() { return request_count_from_renderer_; }
Han Leon18ea6202017-06-19 03:34:49170 int request_count_from_utility() { return request_count_from_utility_; }
Han Leon43528ec2017-07-07 02:54:57171 int request_count_from_gpu() { return request_count_from_gpu_; }
leon.hana0c5fa32017-06-13 08:14:11172
173 void SimulatePowerStateChange(bool on_battery_power) {
174 power_monitor_message_broadcaster_.OnPowerStateChange(on_battery_power);
175 }
176
177 private:
178 int request_count_from_renderer_ = 0;
Han Leon18ea6202017-06-19 03:34:49179 int request_count_from_utility_ = 0;
Han Leon43528ec2017-07-07 02:54:57180 int request_count_from_gpu_ = 0;
Han Leon18ea6202017-06-19 03:34:49181 base::OnceClosure renderer_bound_closure_;
Han Leon43528ec2017-07-07 02:54:57182 base::OnceClosure gpu_bound_closure_;
Han Leon18ea6202017-06-19 03:34:49183 base::OnceClosure utility_bound_closure_;
leon.hana0c5fa32017-06-13 08:14:11184
185 MockPowerMonitorMessageBroadcaster power_monitor_message_broadcaster_;
186
187 DISALLOW_COPY_AND_ASSIGN(PowerMonitorTest);
188};
189
Han Leon18ea6202017-06-19 03:34:49190IN_PROC_BROWSER_TEST_F(PowerMonitorTest, TestRendererProcess) {
leon.hana0c5fa32017-06-13 08:14:11191 ASSERT_EQ(0, request_count_from_renderer());
Han Leon18ea6202017-06-19 03:34:49192 base::RunLoop run_loop;
193 set_renderer_bound_closure(run_loop.QuitClosure());
leon.hana0c5fa32017-06-13 08:14:11194 ASSERT_TRUE(NavigateToURL(shell(), GetTestUrl(".", "simple_page.html")));
Han Leon18ea6202017-06-19 03:34:49195 run_loop.Run();
leon.hana0c5fa32017-06-13 08:14:11196 EXPECT_EQ(1, request_count_from_renderer());
197
198 mojom::PowerMonitorTestPtr power_monitor_renderer;
199 RenderProcessHost* rph =
200 shell()->web_contents()->GetMainFrame()->GetProcess();
201 BindInterface(rph, &power_monitor_renderer);
202
203 SimulatePowerStateChange(true);
204 // Verify renderer process on_battery_power changed to true.
205 VerifyPowerStateInChildProcess(power_monitor_renderer.get(), true);
206
207 SimulatePowerStateChange(false);
208 // Verify renderer process on_battery_power changed to false.
209 VerifyPowerStateInChildProcess(power_monitor_renderer.get(), false);
210}
211
Han Leon18ea6202017-06-19 03:34:49212IN_PROC_BROWSER_TEST_F(PowerMonitorTest, TestUtilityProcess) {
213 mojom::PowerMonitorTestPtr power_monitor_utility;
214
215 ASSERT_EQ(0, request_count_from_utility());
216 base::RunLoop run_loop;
217 StartUtilityProcess(&power_monitor_utility, run_loop.QuitClosure());
218 run_loop.Run();
219 EXPECT_EQ(1, request_count_from_utility());
220
221 SimulatePowerStateChange(true);
222 // Verify utility process on_battery_power changed to true.
223 VerifyPowerStateInChildProcess(power_monitor_utility.get(), true);
224
225 SimulatePowerStateChange(false);
226 // Verify utility process on_battery_power changed to false.
227 VerifyPowerStateInChildProcess(power_monitor_utility.get(), false);
228}
229
Han Leon43528ec2017-07-07 02:54:57230IN_PROC_BROWSER_TEST_F(PowerMonitorTest, TestGpuProcess) {
231 // As gpu process is started automatically during the setup period of browser
232 // test suite, it may have already started and bound PowerMonitor interface to
233 // Device Service before execution of this TestGpuProcess test. So here we
234 // do not wait for the connection if we found it has already been established.
235 if (request_count_from_gpu() != 1) {
236 ASSERT_EQ(0, request_count_from_gpu());
237 base::RunLoop run_loop;
238 set_gpu_bound_closure(run_loop.QuitClosure());
239 // Wait for the connection from gpu process.
240 run_loop.Run();
241 }
242 EXPECT_EQ(1, request_count_from_gpu());
243
244 mojom::PowerMonitorTestPtr power_monitor_gpu;
Eric Seckler8652dcd52018-09-20 10:42:28245 base::PostTaskWithTraits(
246 FROM_HERE, {BrowserThread::IO},
Han Leon43528ec2017-07-07 02:54:57247 base::BindOnce(&BindInterfaceForGpuOnIOThread,
248 mojo::MakeRequest(&power_monitor_gpu)));
249
250 SimulatePowerStateChange(true);
251 // Verify gpu process on_battery_power changed to true.
252 VerifyPowerStateInChildProcess(power_monitor_gpu.get(), true);
253
254 SimulatePowerStateChange(false);
255 // Verify gpu process on_battery_power changed to false.
256 VerifyPowerStateInChildProcess(power_monitor_gpu.get(), false);
257}
258
leon.hana0c5fa32017-06-13 08:14:11259} // namespace
260
261} // namespace content