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 <windows.h> 8 9 #include "base/logging.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "base/win/scoped_handle.h" 12 #include "base/win/windows_version.h" 13 #include "content/public/browser/browser_thread.h" 14 15 namespace content { 16 namespace { 17 18 int g_blocker_count[2]; 19 20 HANDLE CreatePowerRequest(POWER_REQUEST_TYPE type, const std::string& reason) { 21 typedef HANDLE (WINAPI* PowerCreateRequestPtr)(PREASON_CONTEXT); 22 typedef BOOL (WINAPI* PowerSetRequestPtr)(HANDLE, POWER_REQUEST_TYPE); 23 24 if (type == PowerRequestExecutionRequired && 25 base::win::GetVersion() < base::win::VERSION_WIN8) { 26 return INVALID_HANDLE_VALUE; 27 } 28 29 static PowerCreateRequestPtr PowerCreateRequestFn = NULL; 30 static PowerSetRequestPtr PowerSetRequestFn = NULL; 31 32 if (!PowerCreateRequestFn || !PowerSetRequestFn) { 33 HMODULE module = GetModuleHandle(L"kernel32.dll"); 34 PowerCreateRequestFn = reinterpret_cast<PowerCreateRequestPtr>( 35 GetProcAddress(module, "PowerCreateRequest")); 36 PowerSetRequestFn = reinterpret_cast<PowerSetRequestPtr>( 37 GetProcAddress(module, "PowerSetRequest")); 38 39 if (!PowerCreateRequestFn || !PowerSetRequestFn) 40 return INVALID_HANDLE_VALUE; 41 } 42 base::string16 wide_reason = base::ASCIIToUTF16(reason); 43 REASON_CONTEXT context = {0}; 44 context.Version = POWER_REQUEST_CONTEXT_VERSION; 45 context.Flags = POWER_REQUEST_CONTEXT_SIMPLE_STRING; 46 context.Reason.SimpleReasonString = const_cast<wchar_t*>(wide_reason.c_str()); 47 48 base::win::ScopedHandle handle(PowerCreateRequestFn(&context)); 49 if (!handle.IsValid()) 50 return INVALID_HANDLE_VALUE; 51 52 if (PowerSetRequestFn(handle, type)) 53 return handle.Take(); 54 55 // Something went wrong. 56 return INVALID_HANDLE_VALUE; 57 } 58 59 // Takes ownership of the |handle|. 60 void DeletePowerRequest(POWER_REQUEST_TYPE type, HANDLE handle) { 61 base::win::ScopedHandle request_handle(handle); 62 if (!request_handle.IsValid()) 63 return; 64 65 if (type == PowerRequestExecutionRequired && 66 base::win::GetVersion() < base::win::VERSION_WIN8) { 67 return; 68 } 69 70 typedef BOOL (WINAPI* PowerClearRequestPtr)(HANDLE, POWER_REQUEST_TYPE); 71 HMODULE module = GetModuleHandle(L"kernel32.dll"); 72 PowerClearRequestPtr PowerClearRequestFn = 73 reinterpret_cast<PowerClearRequestPtr>( 74 GetProcAddress(module, "PowerClearRequest")); 75 76 if (!PowerClearRequestFn) 77 return; 78 79 BOOL success = PowerClearRequestFn(request_handle, type); 80 DCHECK(success); 81 } 82 83 void ApplySimpleBlock(PowerSaveBlocker::PowerSaveBlockerType type, 84 int delta) { 85 g_blocker_count[type] += delta; 86 DCHECK_GE(g_blocker_count[type], 0); 87 88 if (g_blocker_count[type] > 1) 89 return; 90 91 DWORD this_flag = 0; 92 if (type == PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension) 93 this_flag |= ES_SYSTEM_REQUIRED; 94 else 95 this_flag |= ES_DISPLAY_REQUIRED; 96 97 DCHECK(this_flag); 98 99 static DWORD flags = ES_CONTINUOUS; 100 if (!g_blocker_count[type]) 101 flags &= ~this_flag; 102 else 103 flags |= this_flag; 104 105 SetThreadExecutionState(flags); 106 } 107 108 } // namespace 109 110 class PowerSaveBlockerImpl::Delegate 111 : public base::RefCountedThreadSafe<PowerSaveBlockerImpl::Delegate> { 112 public: 113 Delegate(PowerSaveBlockerType type, const std::string& reason) 114 : type_(type), reason_(reason) {} 115 116 // Does the actual work to apply or remove the desired power save block. 117 void ApplyBlock(); 118 void RemoveBlock(); 119 120 // Returns the equivalent POWER_REQUEST_TYPE for this request. 121 POWER_REQUEST_TYPE RequestType(); 122 123 private: 124 friend class base::RefCountedThreadSafe<Delegate>; 125 ~Delegate() {} 126 127 PowerSaveBlockerType type_; 128 const std::string reason_; 129 base::win::ScopedHandle handle_; 130 131 DISALLOW_COPY_AND_ASSIGN(Delegate); 132 }; 133 134 void PowerSaveBlockerImpl::Delegate::ApplyBlock() { 135 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 136 if (base::win::GetVersion() < base::win::VERSION_WIN7) 137 return ApplySimpleBlock(type_, 1); 138 139 handle_.Set(CreatePowerRequest(RequestType(), reason_)); 140 } 141 142 void PowerSaveBlockerImpl::Delegate::RemoveBlock() { 143 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 144 if (base::win::GetVersion() < base::win::VERSION_WIN7) 145 return ApplySimpleBlock(type_, -1); 146 147 DeletePowerRequest(RequestType(), handle_.Take()); 148 } 149 150 POWER_REQUEST_TYPE PowerSaveBlockerImpl::Delegate::RequestType() { 151 if (type_ == kPowerSaveBlockPreventDisplaySleep) 152 return PowerRequestDisplayRequired; 153 154 if (base::win::GetVersion() < base::win::VERSION_WIN8) 155 return PowerRequestSystemRequired; 156 157 return PowerRequestExecutionRequired; 158 } 159 160 PowerSaveBlockerImpl::PowerSaveBlockerImpl(PowerSaveBlockerType type, 161 const std::string& reason) 162 : delegate_(new Delegate(type, reason)) { 163 BrowserThread::PostTask( 164 BrowserThread::UI, FROM_HERE, 165 base::Bind(&Delegate::ApplyBlock, delegate_)); 166 } 167 168 PowerSaveBlockerImpl::~PowerSaveBlockerImpl() { 169 BrowserThread::PostTask( 170 BrowserThread::UI, FROM_HERE, 171 base::Bind(&Delegate::RemoveBlock, delegate_)); 172 } 173 174 } // namespace content 175