diff options
Diffstat (limited to 'chromium/content/browser/power_save_blocker_mac.cc')
-rw-r--r-- | chromium/content/browser/power_save_blocker_mac.cc | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/chromium/content/browser/power_save_blocker_mac.cc b/chromium/content/browser/power_save_blocker_mac.cc new file mode 100644 index 00000000000..ec340a1c2c6 --- /dev/null +++ b/chromium/content/browser/power_save_blocker_mac.cc @@ -0,0 +1,112 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/power_save_blocker_impl.h" + +#include <IOKit/pwr_mgt/IOPMLib.h> + +#include "base/bind.h" +#include "base/lazy_instance.h" +#include "base/mac/scoped_cftyperef.h" +#include "base/strings/sys_string_conversions.h" +#include "base/threading/platform_thread.h" +#include "base/threading/thread.h" + +namespace content { +namespace { + +// Power management cannot be done on the UI thread. IOPMAssertionCreate does a +// synchronous MIG call to configd, so if it is called on the main thread the UI +// is at the mercy of another process. See http://crbug.com/79559 and +// http://www.opensource.apple.com/source/IOKitUser/IOKitUser-514.16.31/pwr_mgt.subproj/IOPMLibPrivate.c . +struct PowerSaveBlockerLazyInstanceTraits { + static const bool kRegisterOnExit = false; + static const bool kAllowedToAccessOnNonjoinableThread = true; + + static base::Thread* New(void* instance) { + base::Thread* thread = new (instance) base::Thread("PowerSaveBlocker"); + thread->Start(); + return thread; + } + static void Delete(base::Thread* instance) { } +}; +base::LazyInstance<base::Thread, PowerSaveBlockerLazyInstanceTraits> + g_power_thread = LAZY_INSTANCE_INITIALIZER; + +} // namespace + +class PowerSaveBlockerImpl::Delegate + : public base::RefCountedThreadSafe<PowerSaveBlockerImpl::Delegate> { + public: + Delegate(PowerSaveBlockerType type, const std::string& reason) + : type_(type), reason_(reason), assertion_(kIOPMNullAssertionID) {} + + // Does the actual work to apply or remove the desired power save block. + void ApplyBlock(); + void RemoveBlock(); + + private: + friend class base::RefCountedThreadSafe<Delegate>; + ~Delegate() {} + PowerSaveBlockerType type_; + std::string reason_; + IOPMAssertionID assertion_; +}; + +void PowerSaveBlockerImpl::Delegate::ApplyBlock() { + DCHECK_EQ(base::PlatformThread::CurrentId(), + g_power_thread.Pointer()->thread_id()); + + CFStringRef level = NULL; + // See QA1340 <http://developer.apple.com/library/mac/#qa/qa1340/> for more + // details. + switch (type_) { + case PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension: + level = kIOPMAssertionTypeNoIdleSleep; + break; + case PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep: + level = kIOPMAssertionTypeNoDisplaySleep; + break; + default: + NOTREACHED(); + break; + } + if (level) { + base::ScopedCFTypeRef<CFStringRef> cf_reason( + base::SysUTF8ToCFStringRef(reason_)); + IOReturn result = IOPMAssertionCreateWithName(level, + kIOPMAssertionLevelOn, + cf_reason, + &assertion_); + LOG_IF(ERROR, result != kIOReturnSuccess) + << "IOPMAssertionCreate: " << result; + } +} + +void PowerSaveBlockerImpl::Delegate::RemoveBlock() { + DCHECK_EQ(base::PlatformThread::CurrentId(), + g_power_thread.Pointer()->thread_id()); + + if (assertion_ != kIOPMNullAssertionID) { + IOReturn result = IOPMAssertionRelease(assertion_); + LOG_IF(ERROR, result != kIOReturnSuccess) + << "IOPMAssertionRelease: " << result; + } +} + +PowerSaveBlockerImpl::PowerSaveBlockerImpl(PowerSaveBlockerType type, + const std::string& reason) + : delegate_(new Delegate(type, reason)) { + g_power_thread.Pointer()->message_loop()->PostTask( + FROM_HERE, + base::Bind(&Delegate::ApplyBlock, delegate_)); +} + +PowerSaveBlockerImpl::~PowerSaveBlockerImpl() { + g_power_thread.Pointer()->message_loop()->PostTask( + FROM_HERE, + base::Bind(&Delegate::RemoveBlock, delegate_)); +} + +} // namespace content |