Home | History | Annotate | Download | only in power
      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.
      4 
      5 #include "chrome/browser/power/process_power_collector.h"
      6 
      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/browser_test_utils.h"
     19 #include "content/public/test/mock_render_process_host.h"
     20 #include "extensions/browser/app_window/app_window_client.h"
     21 #include "extensions/browser/app_window/app_window_contents.h"
     22 #include "extensions/browser/app_window/app_window_registry.h"
     23 #include "extensions/browser/app_window/native_app_window.h"
     24 #include "extensions/common/extension.h"
     25 #include "testing/gtest/include/gtest/gtest.h"
     26 #include "url/gurl.h"
     27 
     28 #if defined(OS_CHROMEOS)
     29 #include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
     30 #endif
     31 
     32 using power::OriginPowerMap;
     33 using power::OriginPowerMapFactory;
     34 
     35 class BrowserProcessPowerTest : public BrowserWithTestWindowTest {
     36  public:
     37   BrowserProcessPowerTest() {}
     38   virtual ~BrowserProcessPowerTest() {}
     39 
     40   virtual void SetUp() OVERRIDE {
     41     BrowserWithTestWindowTest::SetUp();
     42     collector.reset(new ProcessPowerCollector);
     43 
     44 #if defined(OS_CHROMEOS)
     45     power_manager::PowerSupplyProperties prop;
     46     prop.set_external_power(power_manager::PowerSupplyProperties::AC);
     47     prop.set_battery_state(power_manager::PowerSupplyProperties::DISCHARGING);
     48     prop.set_battery_percent(20.00);
     49     prop.set_battery_discharge_rate(1);
     50     collector->PowerChanged(prop);
     51 #endif
     52 
     53     profile_manager_.reset(
     54         new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
     55     ASSERT_TRUE(profile_manager_->SetUp());
     56   }
     57 
     58   virtual void TearDown() OVERRIDE {
     59     collector.reset();
     60     BrowserWithTestWindowTest::TearDown();
     61   }
     62 
     63   // Mocks out CPU usage for all processes as |value| percent.
     64   double ReturnCpuAsConstant(double value, base::ProcessHandle handle) {
     65     return value;
     66   }
     67 
     68  protected:
     69   content::MockRenderProcessHost* GetProcess(Browser* browser) {
     70     return static_cast<content::MockRenderProcessHost*>(
     71         browser->tab_strip_model()
     72             ->GetActiveWebContents()
     73             ->GetRenderViewHost()
     74             ->GetProcess());
     75   }
     76 
     77   scoped_ptr<base::ProcessHandle> MakeProcessHandle(int process_id) {
     78     scoped_ptr<base::ProcessHandle> proc_handle(new base::ProcessHandle(
     79 #if defined(OS_WIN)
     80         reinterpret_cast<HANDLE>(process_id))
     81 #else
     82         process_id)
     83 #endif
     84                                                 );
     85     return proc_handle.Pass();
     86   }
     87 
     88   scoped_ptr<ProcessPowerCollector> collector;
     89   scoped_ptr<TestingProfileManager> profile_manager_;
     90 };
     91 
     92 class TestAppWindowContents : public extensions::AppWindowContents {
     93  public:
     94   explicit TestAppWindowContents(content::WebContents* web_contents)
     95       : web_contents_(web_contents) {}
     96 
     97   // apps:AppWindowContents
     98   virtual void Initialize(content::BrowserContext* context,
     99                           const GURL& url) OVERRIDE {}
    100   virtual void LoadContents(int32 creator_process_id) OVERRIDE {}
    101   virtual void NativeWindowChanged(
    102       extensions::NativeAppWindow* native_app_window) OVERRIDE {}
    103   virtual void NativeWindowClosed() OVERRIDE {}
    104   virtual void DispatchWindowShownForTests() const OVERRIDE {}
    105   virtual content::WebContents* GetWebContents() const OVERRIDE {
    106     return web_contents_.get();
    107   }
    108 
    109  private:
    110   scoped_ptr<content::WebContents> web_contents_;
    111 };
    112 
    113 TEST_F(BrowserProcessPowerTest, NoSite) {
    114   collector->UpdatePowerConsumptionForTesting();
    115   EXPECT_EQ(0u, collector->metrics_map_for_testing()->size());
    116 }
    117 
    118 TEST_F(BrowserProcessPowerTest, OneSite) {
    119   GURL url("http://www.google.com");
    120   AddTab(browser(), url);
    121   collector->UpdatePowerConsumptionForTesting();
    122   ProcessPowerCollector::ProcessMetricsMap* metrics_map =
    123       collector->metrics_map_for_testing();
    124   EXPECT_EQ(1u, metrics_map->size());
    125 
    126   // Create fake process numbers.
    127   GetProcess(browser())->SetProcessHandle(MakeProcessHandle(1).Pass());
    128 
    129   OriginPowerMap* origin_power_map =
    130       OriginPowerMapFactory::GetForBrowserContext(profile());
    131   EXPECT_EQ(0, origin_power_map->GetPowerForOrigin(url));
    132 
    133   collector->set_cpu_usage_callback_for_testing(
    134       base::Bind(&BrowserProcessPowerTest::ReturnCpuAsConstant,
    135                  base::Unretained(this),
    136                  5));
    137   EXPECT_DOUBLE_EQ(5, collector->UpdatePowerConsumptionForTesting());
    138   EXPECT_EQ(100, origin_power_map->GetPowerForOrigin(url));
    139 }
    140 
    141 TEST_F(BrowserProcessPowerTest, MultipleSites) {
    142   Browser::CreateParams native_params(profile(),
    143                                       chrome::HOST_DESKTOP_TYPE_NATIVE);
    144   GURL url1("http://www.google.com");
    145   GURL url2("http://www.example.com");
    146   GURL url3("https://www.google.com");
    147   scoped_ptr<Browser> browser2(
    148       chrome::CreateBrowserWithTestWindowForParams(&native_params));
    149   scoped_ptr<Browser> browser3(
    150       chrome::CreateBrowserWithTestWindowForParams(&native_params));
    151   AddTab(browser(), url1);
    152   AddTab(browser2.get(), url2);
    153   AddTab(browser3.get(), url3);
    154 
    155   // Create fake process numbers.
    156   GetProcess(browser())->SetProcessHandle(MakeProcessHandle(1).Pass());
    157   GetProcess(browser2.get())->SetProcessHandle(MakeProcessHandle(2).Pass());
    158   GetProcess(browser3.get())->SetProcessHandle(MakeProcessHandle(3).Pass());
    159 
    160   collector->UpdatePowerConsumptionForTesting();
    161   ProcessPowerCollector::ProcessMetricsMap* metrics_map =
    162       collector->metrics_map_for_testing();
    163   EXPECT_EQ(3u, metrics_map->size());
    164 
    165   // Since all handlers are uninitialized, this should be 0.
    166   EXPECT_DOUBLE_EQ(0, collector->UpdatePowerConsumptionForTesting());
    167   OriginPowerMap* origin_power_map =
    168       OriginPowerMapFactory::GetForBrowserContext(profile());
    169   EXPECT_EQ(0, origin_power_map->GetPowerForOrigin(url1));
    170   EXPECT_EQ(0, origin_power_map->GetPowerForOrigin(url2));
    171   EXPECT_EQ(0, origin_power_map->GetPowerForOrigin(url3));
    172 
    173   collector->set_cpu_usage_callback_for_testing(
    174       base::Bind(&BrowserProcessPowerTest::ReturnCpuAsConstant,
    175                  base::Unretained(this),
    176                  5));
    177   EXPECT_DOUBLE_EQ(15, collector->UpdatePowerConsumptionForTesting());
    178   EXPECT_EQ(33, origin_power_map->GetPowerForOrigin(url1));
    179   EXPECT_EQ(33, origin_power_map->GetPowerForOrigin(url2));
    180   EXPECT_EQ(33, origin_power_map->GetPowerForOrigin(url3));
    181 
    182   // Close some tabs and verify that they are removed from the metrics map.
    183   chrome::CloseTab(browser2.get());
    184   chrome::CloseTab(browser3.get());
    185 
    186   collector->UpdatePowerConsumptionForTesting();
    187   EXPECT_EQ(1u, metrics_map->size());
    188 }
    189 
    190 TEST_F(BrowserProcessPowerTest, IncognitoDoesntRecordPowerUsage) {
    191   Browser::CreateParams native_params(profile()->GetOffTheRecordProfile(),
    192                                       chrome::HOST_DESKTOP_TYPE_NATIVE);
    193   scoped_ptr<Browser> incognito_browser(
    194       chrome::CreateBrowserWithTestWindowForParams(&native_params));
    195   GURL url("http://www.google.com");
    196   AddTab(browser(), url);
    197 
    198   GURL hidden_url("http://foo.com");
    199   AddTab(incognito_browser.get(), hidden_url);
    200 
    201   // Create fake process numbers.
    202   GetProcess(browser())->SetProcessHandle(MakeProcessHandle(1).Pass());
    203   GetProcess(incognito_browser.get())
    204       ->SetProcessHandle(MakeProcessHandle(2).Pass());
    205 
    206   EXPECT_DOUBLE_EQ(0, collector->UpdatePowerConsumptionForTesting());
    207   ProcessPowerCollector::ProcessMetricsMap* metrics_map =
    208       collector->metrics_map_for_testing();
    209   EXPECT_EQ(1u, metrics_map->size());
    210 
    211   OriginPowerMap* origin_power_map =
    212       OriginPowerMapFactory::GetForBrowserContext(profile());
    213   EXPECT_EQ(0, origin_power_map->GetPowerForOrigin(url));
    214 
    215   collector->set_cpu_usage_callback_for_testing(
    216       base::Bind(&BrowserProcessPowerTest::ReturnCpuAsConstant,
    217                  base::Unretained(this),
    218                  5));
    219   EXPECT_DOUBLE_EQ(5, collector->UpdatePowerConsumptionForTesting());
    220 
    221   // Verify that the incognito data was not stored.
    222   EXPECT_EQ(100, origin_power_map->GetPowerForOrigin(url));
    223   EXPECT_EQ(0, origin_power_map->GetPowerForOrigin(hidden_url));
    224 
    225   chrome::CloseTab(incognito_browser.get());
    226 }
    227 
    228 TEST_F(BrowserProcessPowerTest, MultipleProfilesRecordSeparately) {
    229   scoped_ptr<Profile> other_profile(CreateProfile());
    230   Browser::CreateParams native_params(other_profile.get(),
    231                                       chrome::HOST_DESKTOP_TYPE_NATIVE);
    232   scoped_ptr<Browser> other_user(
    233       chrome::CreateBrowserWithTestWindowForParams(&native_params));
    234 
    235   GURL url("http://www.google.com");
    236   AddTab(browser(), url);
    237 
    238   GURL hidden_url("http://foo.com");
    239   AddTab(other_user.get(), hidden_url);
    240 
    241   // Create fake process numbers.
    242   GetProcess(browser())->SetProcessHandle(MakeProcessHandle(1).Pass());
    243   GetProcess(other_user.get())->SetProcessHandle(MakeProcessHandle(2).Pass());
    244 
    245   EXPECT_DOUBLE_EQ(0, collector->UpdatePowerConsumptionForTesting());
    246   EXPECT_EQ(2u, collector->metrics_map_for_testing()->size());
    247 
    248   collector->set_cpu_usage_callback_for_testing(
    249       base::Bind(&BrowserProcessPowerTest::ReturnCpuAsConstant,
    250                  base::Unretained(this),
    251                  5));
    252   EXPECT_DOUBLE_EQ(10, collector->UpdatePowerConsumptionForTesting());
    253 
    254   // profile() should have an entry for |url| but not |hidden_url|.
    255   OriginPowerMap* origin_power_map_first =
    256       OriginPowerMapFactory::GetForBrowserContext(profile());
    257   EXPECT_EQ(100, origin_power_map_first->GetPowerForOrigin(url));
    258   EXPECT_EQ(0, origin_power_map_first->GetPowerForOrigin(hidden_url));
    259 
    260   // |other_profile| should have an entry for |hidden_url| but not |url|.
    261   OriginPowerMap* origin_power_map_second =
    262       OriginPowerMapFactory::GetForBrowserContext(other_profile.get());
    263   EXPECT_EQ(0, origin_power_map_second->GetPowerForOrigin(url));
    264   EXPECT_EQ(100, origin_power_map_second->GetPowerForOrigin(hidden_url));
    265 
    266   // Clean up
    267   chrome::CloseTab(other_user.get());
    268 }
    269 
    270 TEST_F(BrowserProcessPowerTest, AppsRecordPowerUsage) {
    271 // Install an app (an extension*).
    272 #if defined(OS_WIN)
    273   base::FilePath extension_path(FILE_PATH_LITERAL("c:\\foo"));
    274 #elif defined(OS_POSIX)
    275   base::FilePath extension_path(FILE_PATH_LITERAL("/foo"));
    276 #endif
    277   base::DictionaryValue manifest;
    278   manifest.SetString("name", "Fake Name");
    279   manifest.SetString("version", "1");
    280   std::string error;
    281   char kTestAppId[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
    282   scoped_refptr<extensions::Extension> extension(
    283       extensions::Extension::Create(extension_path,
    284                                     extensions::Manifest::INTERNAL,
    285                                     manifest,
    286                                     extensions::Extension::NO_FLAGS,
    287                                     kTestAppId,
    288                                     &error));
    289   EXPECT_TRUE(extension.get()) << error;
    290 
    291   Profile* current_profile =
    292       profile_manager_->CreateTestingProfile("Test user");
    293   GURL url("chrome-extension://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
    294   extensions::AppWindow* window = new extensions::AppWindow(
    295       current_profile, new ChromeAppDelegate(scoped_ptr<ScopedKeepAlive>()),
    296       extension.get());
    297   content::WebContents* web_contents(
    298       content::WebContents::Create(content::WebContents::CreateParams(
    299           current_profile,
    300           content::SiteInstance::CreateForURL(current_profile, url))));
    301   window->SetAppWindowContentsForTesting(
    302       scoped_ptr<extensions::AppWindowContents>(
    303           new TestAppWindowContents(web_contents)));
    304   extensions::AppWindowRegistry* app_registry =
    305       extensions::AppWindowRegistry::Get(current_profile);
    306   app_registry->AddAppWindow(window);
    307 
    308   collector->set_cpu_usage_callback_for_testing(
    309       base::Bind(&BrowserProcessPowerTest::ReturnCpuAsConstant,
    310                  base::Unretained(this),
    311                  5));
    312   collector->UpdatePowerConsumptionForTesting();
    313   EXPECT_EQ(1u, collector->metrics_map_for_testing()->size());
    314 
    315   // Clear the AppWindowContents before trying to close.
    316   window->SetAppWindowContentsForTesting(
    317       scoped_ptr<extensions::AppWindowContents>());
    318   window->OnNativeClose();
    319   collector->UpdatePowerConsumptionForTesting();
    320   EXPECT_EQ(0u, collector->metrics_map_for_testing()->size());
    321 }
    322