1 // Copyright 2014 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.
5 #include "chrome/browser/power/process_power_collector.h"
7 #include "chrome/browser/apps/scoped_keep_alive.h"
8 #include "chrome/browser/profiles/profile_manager.h"
9 #include "chrome/browser/ui/apps/chrome_app_delegate.h"
10 #include "chrome/browser/ui/browser_commands.h"
11 #include "chrome/browser/ui/tabs/tab_strip_model.h"
12 #include "chrome/test/base/browser_with_test_window_test.h"
13 #include "chrome/test/base/testing_browser_process.h"
14 #include "chrome/test/base/testing_profile_manager.h"
15 #include "components/power/origin_power_map.h"
16 #include "components/power/origin_power_map_factory.h"
17 #include "content/public/browser/site_instance.h"
18 #include "content/public/test/mock_render_process_host.h"
19 #include "extensions/browser/app_window/app_window_client.h"
20 #include "extensions/browser/app_window/app_window_registry.h"
21 #include "extensions/browser/app_window/native_app_window.h"
22 #include "extensions/browser/app_window/test_app_window_contents.h"
23 #include "extensions/common/extension.h"
24 #include "testing/gtest/include/gtest/gtest.h"
27 #if defined(OS_CHROMEOS)
28 #include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
31 using power::OriginPowerMap
;
32 using power::OriginPowerMapFactory
;
34 class BrowserProcessPowerTest
: public BrowserWithTestWindowTest
{
36 BrowserProcessPowerTest() {}
37 ~BrowserProcessPowerTest() override
{}
39 void SetUp() override
{
40 BrowserWithTestWindowTest::SetUp();
41 collector
.reset(new ProcessPowerCollector
);
43 #if defined(OS_CHROMEOS)
44 power_manager::PowerSupplyProperties prop
;
45 prop
.set_external_power(power_manager::PowerSupplyProperties::AC
);
46 prop
.set_battery_state(power_manager::PowerSupplyProperties::DISCHARGING
);
47 prop
.set_battery_percent(20.00);
48 prop
.set_battery_discharge_rate(1);
49 collector
->PowerChanged(prop
);
52 profile_manager_
.reset(
53 new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
54 ASSERT_TRUE(profile_manager_
->SetUp());
57 void TearDown() override
{
59 BrowserWithTestWindowTest::TearDown();
62 // Mocks out CPU usage for all processes as |value| percent.
63 double ReturnCpuAsConstant(double value
, base::ProcessHandle handle
) {
68 content::MockRenderProcessHost
* GetProcess(Browser
* browser
) {
69 return static_cast<content::MockRenderProcessHost
*>(
70 browser
->tab_strip_model()
71 ->GetActiveWebContents()
76 scoped_ptr
<base::ProcessHandle
> MakeProcessHandle(int process_id
) {
77 scoped_ptr
<base::ProcessHandle
> proc_handle(new base::ProcessHandle(
79 reinterpret_cast<HANDLE
>(process_id
))
84 return proc_handle
.Pass();
87 scoped_ptr
<ProcessPowerCollector
> collector
;
88 scoped_ptr
<TestingProfileManager
> profile_manager_
;
91 TEST_F(BrowserProcessPowerTest
, NoSite
) {
92 collector
->UpdatePowerConsumptionForTesting();
93 EXPECT_EQ(0u, collector
->metrics_map_for_testing()->size());
96 TEST_F(BrowserProcessPowerTest
, OneSite
) {
97 GURL
url("http://www.google.com");
98 AddTab(browser(), url
);
99 collector
->UpdatePowerConsumptionForTesting();
100 ProcessPowerCollector::ProcessMetricsMap
* metrics_map
=
101 collector
->metrics_map_for_testing();
102 EXPECT_EQ(1u, metrics_map
->size());
104 // Create fake process numbers.
105 GetProcess(browser())->SetProcessHandle(MakeProcessHandle(1).Pass());
107 OriginPowerMap
* origin_power_map
=
108 OriginPowerMapFactory::GetForBrowserContext(profile());
109 EXPECT_EQ(0, origin_power_map
->GetPowerForOrigin(url
));
111 collector
->set_cpu_usage_callback_for_testing(
112 base::Bind(&BrowserProcessPowerTest::ReturnCpuAsConstant
,
113 base::Unretained(this),
115 EXPECT_DOUBLE_EQ(5, collector
->UpdatePowerConsumptionForTesting());
116 EXPECT_EQ(100, origin_power_map
->GetPowerForOrigin(url
));
119 TEST_F(BrowserProcessPowerTest
, MultipleSites
) {
120 Browser::CreateParams
native_params(profile(),
121 chrome::HOST_DESKTOP_TYPE_NATIVE
);
122 GURL
url1("http://www.google.com");
123 GURL
url2("http://www.example.com");
124 GURL
url3("https://www.google.com");
125 scoped_ptr
<Browser
> browser2(
126 chrome::CreateBrowserWithTestWindowForParams(&native_params
));
127 scoped_ptr
<Browser
> browser3(
128 chrome::CreateBrowserWithTestWindowForParams(&native_params
));
129 AddTab(browser(), url1
);
130 AddTab(browser2
.get(), url2
);
131 AddTab(browser3
.get(), url3
);
133 // Create fake process numbers.
134 GetProcess(browser())->SetProcessHandle(MakeProcessHandle(1).Pass());
135 GetProcess(browser2
.get())->SetProcessHandle(MakeProcessHandle(2).Pass());
136 GetProcess(browser3
.get())->SetProcessHandle(MakeProcessHandle(3).Pass());
138 collector
->UpdatePowerConsumptionForTesting();
139 ProcessPowerCollector::ProcessMetricsMap
* metrics_map
=
140 collector
->metrics_map_for_testing();
141 EXPECT_EQ(3u, metrics_map
->size());
143 // Since all handlers are uninitialized, this should be 0.
144 EXPECT_DOUBLE_EQ(0, collector
->UpdatePowerConsumptionForTesting());
145 OriginPowerMap
* origin_power_map
=
146 OriginPowerMapFactory::GetForBrowserContext(profile());
147 EXPECT_EQ(0, origin_power_map
->GetPowerForOrigin(url1
));
148 EXPECT_EQ(0, origin_power_map
->GetPowerForOrigin(url2
));
149 EXPECT_EQ(0, origin_power_map
->GetPowerForOrigin(url3
));
151 collector
->set_cpu_usage_callback_for_testing(
152 base::Bind(&BrowserProcessPowerTest::ReturnCpuAsConstant
,
153 base::Unretained(this),
155 EXPECT_DOUBLE_EQ(15, collector
->UpdatePowerConsumptionForTesting());
156 EXPECT_EQ(33, origin_power_map
->GetPowerForOrigin(url1
));
157 EXPECT_EQ(33, origin_power_map
->GetPowerForOrigin(url2
));
158 EXPECT_EQ(33, origin_power_map
->GetPowerForOrigin(url3
));
160 // Close some tabs and verify that they are removed from the metrics map.
161 chrome::CloseTab(browser2
.get());
162 chrome::CloseTab(browser3
.get());
164 collector
->UpdatePowerConsumptionForTesting();
165 EXPECT_EQ(1u, metrics_map
->size());
168 TEST_F(BrowserProcessPowerTest
, IncognitoDoesntRecordPowerUsage
) {
169 Browser::CreateParams
native_params(profile()->GetOffTheRecordProfile(),
170 chrome::HOST_DESKTOP_TYPE_NATIVE
);
171 scoped_ptr
<Browser
> incognito_browser(
172 chrome::CreateBrowserWithTestWindowForParams(&native_params
));
173 GURL
url("http://www.google.com");
174 AddTab(browser(), url
);
176 GURL
hidden_url("http://foo.com");
177 AddTab(incognito_browser
.get(), hidden_url
);
179 // Create fake process numbers.
180 GetProcess(browser())->SetProcessHandle(MakeProcessHandle(1).Pass());
181 GetProcess(incognito_browser
.get())
182 ->SetProcessHandle(MakeProcessHandle(2).Pass());
184 EXPECT_DOUBLE_EQ(0, collector
->UpdatePowerConsumptionForTesting());
185 ProcessPowerCollector::ProcessMetricsMap
* metrics_map
=
186 collector
->metrics_map_for_testing();
187 EXPECT_EQ(1u, metrics_map
->size());
189 OriginPowerMap
* origin_power_map
=
190 OriginPowerMapFactory::GetForBrowserContext(profile());
191 EXPECT_EQ(0, origin_power_map
->GetPowerForOrigin(url
));
193 collector
->set_cpu_usage_callback_for_testing(
194 base::Bind(&BrowserProcessPowerTest::ReturnCpuAsConstant
,
195 base::Unretained(this),
197 EXPECT_DOUBLE_EQ(5, collector
->UpdatePowerConsumptionForTesting());
199 // Verify that the incognito data was not stored.
200 EXPECT_EQ(100, origin_power_map
->GetPowerForOrigin(url
));
201 EXPECT_EQ(0, origin_power_map
->GetPowerForOrigin(hidden_url
));
203 chrome::CloseTab(incognito_browser
.get());
206 TEST_F(BrowserProcessPowerTest
, MultipleProfilesRecordSeparately
) {
207 scoped_ptr
<Profile
> other_profile(CreateProfile());
208 Browser::CreateParams
native_params(other_profile
.get(),
209 chrome::HOST_DESKTOP_TYPE_NATIVE
);
210 scoped_ptr
<Browser
> other_user(
211 chrome::CreateBrowserWithTestWindowForParams(&native_params
));
213 GURL
url("http://www.google.com");
214 AddTab(browser(), url
);
216 GURL
hidden_url("http://foo.com");
217 AddTab(other_user
.get(), hidden_url
);
219 // Create fake process numbers.
220 GetProcess(browser())->SetProcessHandle(MakeProcessHandle(1).Pass());
221 GetProcess(other_user
.get())->SetProcessHandle(MakeProcessHandle(2).Pass());
223 EXPECT_DOUBLE_EQ(0, collector
->UpdatePowerConsumptionForTesting());
224 EXPECT_EQ(2u, collector
->metrics_map_for_testing()->size());
226 collector
->set_cpu_usage_callback_for_testing(
227 base::Bind(&BrowserProcessPowerTest::ReturnCpuAsConstant
,
228 base::Unretained(this),
230 EXPECT_DOUBLE_EQ(10, collector
->UpdatePowerConsumptionForTesting());
232 // profile() should have an entry for |url| but not |hidden_url|.
233 OriginPowerMap
* origin_power_map_first
=
234 OriginPowerMapFactory::GetForBrowserContext(profile());
235 EXPECT_EQ(100, origin_power_map_first
->GetPowerForOrigin(url
));
236 EXPECT_EQ(0, origin_power_map_first
->GetPowerForOrigin(hidden_url
));
238 // |other_profile| should have an entry for |hidden_url| but not |url|.
239 OriginPowerMap
* origin_power_map_second
=
240 OriginPowerMapFactory::GetForBrowserContext(other_profile
.get());
241 EXPECT_EQ(0, origin_power_map_second
->GetPowerForOrigin(url
));
242 EXPECT_EQ(100, origin_power_map_second
->GetPowerForOrigin(hidden_url
));
245 chrome::CloseTab(other_user
.get());
248 TEST_F(BrowserProcessPowerTest
, AppsRecordPowerUsage
) {
249 // Install an app (an extension*).
251 base::FilePath
extension_path(FILE_PATH_LITERAL("c:\\foo"));
252 #elif defined(OS_POSIX)
253 base::FilePath
extension_path(FILE_PATH_LITERAL("/foo"));
255 base::DictionaryValue manifest
;
256 manifest
.SetString("name", "Fake Name");
257 manifest
.SetString("version", "1");
259 char kTestAppId
[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
260 scoped_refptr
<extensions::Extension
> extension(
261 extensions::Extension::Create(extension_path
,
262 extensions::Manifest::INTERNAL
,
264 extensions::Extension::NO_FLAGS
,
267 EXPECT_TRUE(extension
.get()) << error
;
269 Profile
* current_profile
=
270 profile_manager_
->CreateTestingProfile("Test user");
271 GURL
url("chrome-extension://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
272 extensions::AppWindow
* window
= new extensions::AppWindow(
273 current_profile
, new ChromeAppDelegate(scoped_ptr
<ScopedKeepAlive
>()),
275 content::WebContents
* web_contents(
276 content::WebContents::Create(content::WebContents::CreateParams(
278 content::SiteInstance::CreateForURL(current_profile
, url
))));
279 window
->SetAppWindowContentsForTesting(
280 scoped_ptr
<extensions::AppWindowContents
>(
281 new extensions::TestAppWindowContents(web_contents
)));
282 extensions::AppWindowRegistry
* app_registry
=
283 extensions::AppWindowRegistry::Get(current_profile
);
284 app_registry
->AddAppWindow(window
);
286 collector
->set_cpu_usage_callback_for_testing(
287 base::Bind(&BrowserProcessPowerTest::ReturnCpuAsConstant
,
288 base::Unretained(this),
290 collector
->UpdatePowerConsumptionForTesting();
291 EXPECT_EQ(1u, collector
->metrics_map_for_testing()->size());
293 window
->OnNativeClose();
294 collector
->UpdatePowerConsumptionForTesting();
295 EXPECT_EQ(0u, collector
->metrics_map_for_testing()->size());