• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2013 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/extensions/api/power/power_api_manager.h"
6 
7 #include "base/bind.h"
8 #include "base/lazy_instance.h"
9 #include "chrome/browser/chrome_notification_types.h"
10 #include "content/public/browser/notification_service.h"
11 #include "extensions/browser/extension_registry.h"
12 #include "extensions/common/extension.h"
13 
14 namespace extensions {
15 
16 namespace {
17 
18 const char kPowerSaveBlockerReason[] = "extension";
19 
20 content::PowerSaveBlocker::PowerSaveBlockerType
LevelToPowerSaveBlockerType(api::power::Level level)21 LevelToPowerSaveBlockerType(api::power::Level level) {
22   switch (level) {
23     case api::power::LEVEL_SYSTEM:
24       return content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension;
25     case api::power::LEVEL_DISPLAY:  // fallthrough
26     case api::power::LEVEL_NONE:
27       return content::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep;
28   }
29   NOTREACHED() << "Unhandled level " << level;
30   return content::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep;
31 }
32 
33 base::LazyInstance<BrowserContextKeyedAPIFactory<PowerApiManager> > g_factory =
34     LAZY_INSTANCE_INITIALIZER;
35 
36 }  // namespace
37 
38 // static
Get(content::BrowserContext * context)39 PowerApiManager* PowerApiManager::Get(content::BrowserContext* context) {
40   return BrowserContextKeyedAPIFactory<PowerApiManager>::Get(context);
41 }
42 
43 // static
44 BrowserContextKeyedAPIFactory<PowerApiManager>*
GetFactoryInstance()45 PowerApiManager::GetFactoryInstance() {
46   return g_factory.Pointer();
47 }
48 
AddRequest(const std::string & extension_id,api::power::Level level)49 void PowerApiManager::AddRequest(const std::string& extension_id,
50                                  api::power::Level level) {
51   extension_levels_[extension_id] = level;
52   UpdatePowerSaveBlocker();
53 }
54 
RemoveRequest(const std::string & extension_id)55 void PowerApiManager::RemoveRequest(const std::string& extension_id) {
56   extension_levels_.erase(extension_id);
57   UpdatePowerSaveBlocker();
58 }
59 
SetCreateBlockerFunctionForTesting(CreateBlockerFunction function)60 void PowerApiManager::SetCreateBlockerFunctionForTesting(
61     CreateBlockerFunction function) {
62   create_blocker_function_ = !function.is_null() ? function :
63       base::Bind(&content::PowerSaveBlocker::Create);
64 }
65 
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)66 void PowerApiManager::Observe(int type,
67                               const content::NotificationSource& source,
68                               const content::NotificationDetails& details) {
69   DCHECK_EQ(type, chrome::NOTIFICATION_APP_TERMINATING);
70   power_save_blocker_.reset();
71 }
72 
OnExtensionUnloaded(content::BrowserContext * browser_context,const Extension * extension,UnloadedExtensionInfo::Reason reason)73 void PowerApiManager::OnExtensionUnloaded(
74     content::BrowserContext* browser_context,
75     const Extension* extension,
76     UnloadedExtensionInfo::Reason reason) {
77   RemoveRequest(extension->id());
78   UpdatePowerSaveBlocker();
79 }
80 
PowerApiManager(content::BrowserContext * context)81 PowerApiManager::PowerApiManager(content::BrowserContext* context)
82     : browser_context_(context),
83       create_blocker_function_(base::Bind(&content::PowerSaveBlocker::Create)),
84       current_level_(api::power::LEVEL_SYSTEM) {
85   ExtensionRegistry::Get(browser_context_)->AddObserver(this);
86   registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
87                  content::NotificationService::AllSources());
88 }
89 
~PowerApiManager()90 PowerApiManager::~PowerApiManager() {}
91 
UpdatePowerSaveBlocker()92 void PowerApiManager::UpdatePowerSaveBlocker() {
93   if (extension_levels_.empty()) {
94     power_save_blocker_.reset();
95     return;
96   }
97 
98   api::power::Level new_level = api::power::LEVEL_SYSTEM;
99   for (ExtensionLevelMap::const_iterator it = extension_levels_.begin();
100        it != extension_levels_.end(); ++it) {
101     if (it->second == api::power::LEVEL_DISPLAY)
102       new_level = it->second;
103   }
104 
105   // If the level changed and we need to create a new blocker, do a swap
106   // to ensure that there isn't a brief period where power management is
107   // unblocked.
108   if (!power_save_blocker_ || new_level != current_level_) {
109     content::PowerSaveBlocker::PowerSaveBlockerType type =
110         LevelToPowerSaveBlockerType(new_level);
111     scoped_ptr<content::PowerSaveBlocker> new_blocker(
112         create_blocker_function_.Run(type, kPowerSaveBlockerReason));
113     power_save_blocker_.swap(new_blocker);
114     current_level_ = new_level;
115   }
116 }
117 
Shutdown()118 void PowerApiManager::Shutdown() {
119   // Unregister here rather than in the d'tor; otherwise this call will recreate
120   // the already-deleted ExtensionRegistry.
121   ExtensionRegistry::Get(browser_context_)->RemoveObserver(this);
122 }
123 
124 }  // namespace extensions
125