Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / browser / power_save_blocker_win.cc
blob6d2841146ba1d7be1fac219ff419203c63c86818
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.
5 #include "content/browser/power_save_blocker_impl.h"
7 #include <windows.h>
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"
15 namespace content {
16 namespace {
18 int g_blocker_count[2];
20 HANDLE CreatePowerRequest(POWER_REQUEST_TYPE type,
21 const std::string& description) {
22 typedef HANDLE (WINAPI* PowerCreateRequestPtr)(PREASON_CONTEXT);
23 typedef BOOL (WINAPI* PowerSetRequestPtr)(HANDLE, POWER_REQUEST_TYPE);
25 if (type == PowerRequestExecutionRequired &&
26 base::win::GetVersion() < base::win::VERSION_WIN8) {
27 return INVALID_HANDLE_VALUE;
30 static PowerCreateRequestPtr PowerCreateRequestFn = NULL;
31 static PowerSetRequestPtr PowerSetRequestFn = NULL;
33 if (!PowerCreateRequestFn || !PowerSetRequestFn) {
34 HMODULE module = GetModuleHandle(L"kernel32.dll");
35 PowerCreateRequestFn = reinterpret_cast<PowerCreateRequestPtr>(
36 GetProcAddress(module, "PowerCreateRequest"));
37 PowerSetRequestFn = reinterpret_cast<PowerSetRequestPtr>(
38 GetProcAddress(module, "PowerSetRequest"));
40 if (!PowerCreateRequestFn || !PowerSetRequestFn)
41 return INVALID_HANDLE_VALUE;
43 base::string16 wide_description = base::ASCIIToUTF16(description);
44 REASON_CONTEXT context = {0};
45 context.Version = POWER_REQUEST_CONTEXT_VERSION;
46 context.Flags = POWER_REQUEST_CONTEXT_SIMPLE_STRING;
47 context.Reason.SimpleReasonString =
48 const_cast<wchar_t*>(wide_description.c_str());
50 base::win::ScopedHandle handle(PowerCreateRequestFn(&context));
51 if (!handle.IsValid())
52 return INVALID_HANDLE_VALUE;
54 if (PowerSetRequestFn(handle.Get(), type))
55 return handle.Take();
57 // Something went wrong.
58 return INVALID_HANDLE_VALUE;
61 // Takes ownership of the |handle|.
62 void DeletePowerRequest(POWER_REQUEST_TYPE type, HANDLE handle) {
63 base::win::ScopedHandle request_handle(handle);
64 if (!request_handle.IsValid())
65 return;
67 if (type == PowerRequestExecutionRequired &&
68 base::win::GetVersion() < base::win::VERSION_WIN8) {
69 return;
72 typedef BOOL (WINAPI* PowerClearRequestPtr)(HANDLE, POWER_REQUEST_TYPE);
73 HMODULE module = GetModuleHandle(L"kernel32.dll");
74 PowerClearRequestPtr PowerClearRequestFn =
75 reinterpret_cast<PowerClearRequestPtr>(
76 GetProcAddress(module, "PowerClearRequest"));
78 if (!PowerClearRequestFn)
79 return;
81 BOOL success = PowerClearRequestFn(request_handle.Get(), type);
82 DCHECK(success);
85 void ApplySimpleBlock(PowerSaveBlocker::PowerSaveBlockerType type,
86 int delta) {
87 g_blocker_count[type] += delta;
88 DCHECK_GE(g_blocker_count[type], 0);
90 if (g_blocker_count[type] > 1)
91 return;
93 DWORD this_flag = 0;
94 if (type == PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension)
95 this_flag |= ES_SYSTEM_REQUIRED;
96 else
97 this_flag |= ES_DISPLAY_REQUIRED;
99 DCHECK(this_flag);
101 static DWORD flags = ES_CONTINUOUS;
102 if (!g_blocker_count[type])
103 flags &= ~this_flag;
104 else
105 flags |= this_flag;
107 SetThreadExecutionState(flags);
110 } // namespace
112 class PowerSaveBlockerImpl::Delegate
113 : public base::RefCountedThreadSafe<PowerSaveBlockerImpl::Delegate> {
114 public:
115 Delegate(PowerSaveBlockerType type, const std::string& description)
116 : type_(type), description_(description) {}
118 // Does the actual work to apply or remove the desired power save block.
119 void ApplyBlock();
120 void RemoveBlock();
122 // Returns the equivalent POWER_REQUEST_TYPE for this request.
123 POWER_REQUEST_TYPE RequestType();
125 private:
126 friend class base::RefCountedThreadSafe<Delegate>;
127 ~Delegate() {}
129 PowerSaveBlockerType type_;
130 const std::string description_;
131 base::win::ScopedHandle handle_;
133 DISALLOW_COPY_AND_ASSIGN(Delegate);
136 void PowerSaveBlockerImpl::Delegate::ApplyBlock() {
137 DCHECK_CURRENTLY_ON(BrowserThread::UI);
138 if (base::win::GetVersion() < base::win::VERSION_WIN7)
139 return ApplySimpleBlock(type_, 1);
141 handle_.Set(CreatePowerRequest(RequestType(), description_));
144 void PowerSaveBlockerImpl::Delegate::RemoveBlock() {
145 DCHECK_CURRENTLY_ON(BrowserThread::UI);
146 if (base::win::GetVersion() < base::win::VERSION_WIN7)
147 return ApplySimpleBlock(type_, -1);
149 DeletePowerRequest(RequestType(), handle_.Take());
152 POWER_REQUEST_TYPE PowerSaveBlockerImpl::Delegate::RequestType() {
153 if (type_ == kPowerSaveBlockPreventDisplaySleep)
154 return PowerRequestDisplayRequired;
156 if (base::win::GetVersion() < base::win::VERSION_WIN8)
157 return PowerRequestSystemRequired;
159 return PowerRequestExecutionRequired;
162 PowerSaveBlockerImpl::PowerSaveBlockerImpl(PowerSaveBlockerType type,
163 Reason reason,
164 const std::string& description)
165 : delegate_(new Delegate(type, description)) {
166 BrowserThread::PostTask(
167 BrowserThread::UI, FROM_HERE,
168 base::Bind(&Delegate::ApplyBlock, delegate_));
171 PowerSaveBlockerImpl::~PowerSaveBlockerImpl() {
172 BrowserThread::PostTask(
173 BrowserThread::UI, FROM_HERE,
174 base::Bind(&Delegate::RemoveBlock, delegate_));
177 } // namespace content