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