• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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 "content/browser/power_save_blocker_impl.h"
6 
7 #include <IOKit/pwr_mgt/IOPMLib.h>
8 
9 #include "base/bind.h"
10 #include "base/lazy_instance.h"
11 #include "base/mac/scoped_cftyperef.h"
12 #include "base/strings/sys_string_conversions.h"
13 #include "base/threading/platform_thread.h"
14 #include "base/threading/thread.h"
15 
16 namespace content {
17 namespace {
18 
19 // Power management cannot be done on the UI thread. IOPMAssertionCreate does a
20 // synchronous MIG call to configd, so if it is called on the main thread the UI
21 // is at the mercy of another process. See http://crbug.com/79559 and
22 // http://www.opensource.apple.com/source/IOKitUser/IOKitUser-514.16.31/pwr_mgt.subproj/IOPMLibPrivate.c .
23 struct PowerSaveBlockerLazyInstanceTraits {
24   static const bool kRegisterOnExit = false;
25 #ifndef NDEBUG
26   static const bool kAllowedToAccessOnNonjoinableThread = true;
27 #endif
28 
Newcontent::__anon7affa39f0111::PowerSaveBlockerLazyInstanceTraits29   static base::Thread* New(void* instance) {
30     base::Thread* thread = new (instance) base::Thread("PowerSaveBlocker");
31     thread->Start();
32     return thread;
33   }
Deletecontent::__anon7affa39f0111::PowerSaveBlockerLazyInstanceTraits34   static void Delete(base::Thread* instance) { }
35 };
36 base::LazyInstance<base::Thread, PowerSaveBlockerLazyInstanceTraits>
37     g_power_thread = LAZY_INSTANCE_INITIALIZER;
38 
39 }  // namespace
40 
41 class PowerSaveBlockerImpl::Delegate
42     : public base::RefCountedThreadSafe<PowerSaveBlockerImpl::Delegate> {
43  public:
Delegate(PowerSaveBlockerType type,const std::string & reason)44   Delegate(PowerSaveBlockerType type, const std::string& reason)
45       : type_(type), reason_(reason), assertion_(kIOPMNullAssertionID) {}
46 
47   // Does the actual work to apply or remove the desired power save block.
48   void ApplyBlock();
49   void RemoveBlock();
50 
51  private:
52   friend class base::RefCountedThreadSafe<Delegate>;
~Delegate()53   ~Delegate() {}
54   PowerSaveBlockerType type_;
55   std::string reason_;
56   IOPMAssertionID assertion_;
57 };
58 
ApplyBlock()59 void PowerSaveBlockerImpl::Delegate::ApplyBlock() {
60   DCHECK_EQ(base::PlatformThread::CurrentId(),
61             g_power_thread.Pointer()->thread_id());
62 
63   CFStringRef level = NULL;
64   // See QA1340 <http://developer.apple.com/library/mac/#qa/qa1340/> for more
65   // details.
66   switch (type_) {
67     case PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension:
68       level = kIOPMAssertionTypeNoIdleSleep;
69       break;
70     case PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep:
71       level = kIOPMAssertionTypeNoDisplaySleep;
72       break;
73     default:
74       NOTREACHED();
75       break;
76   }
77   if (level) {
78     base::ScopedCFTypeRef<CFStringRef> cf_reason(
79         base::SysUTF8ToCFStringRef(reason_));
80     IOReturn result = IOPMAssertionCreateWithName(level,
81                                                   kIOPMAssertionLevelOn,
82                                                   cf_reason,
83                                                   &assertion_);
84     LOG_IF(ERROR, result != kIOReturnSuccess)
85         << "IOPMAssertionCreate: " << result;
86   }
87 }
88 
RemoveBlock()89 void PowerSaveBlockerImpl::Delegate::RemoveBlock() {
90   DCHECK_EQ(base::PlatformThread::CurrentId(),
91             g_power_thread.Pointer()->thread_id());
92 
93   if (assertion_ != kIOPMNullAssertionID) {
94     IOReturn result = IOPMAssertionRelease(assertion_);
95     LOG_IF(ERROR, result != kIOReturnSuccess)
96         << "IOPMAssertionRelease: " << result;
97   }
98 }
99 
PowerSaveBlockerImpl(PowerSaveBlockerType type,const std::string & reason)100 PowerSaveBlockerImpl::PowerSaveBlockerImpl(PowerSaveBlockerType type,
101                                            const std::string& reason)
102     : delegate_(new Delegate(type, reason)) {
103   g_power_thread.Pointer()->message_loop()->PostTask(
104       FROM_HERE,
105       base::Bind(&Delegate::ApplyBlock, delegate_));
106 }
107 
~PowerSaveBlockerImpl()108 PowerSaveBlockerImpl::~PowerSaveBlockerImpl() {
109   g_power_thread.Pointer()->message_loop()->PostTask(
110       FROM_HERE,
111       base::Bind(&Delegate::RemoveBlock, delegate_));
112 }
113 
114 }  // namespace content
115