Apply _RELATIVE relocations ahead of others.
[chromium-blink-merge.git] / content / browser / power_save_blocker_win.cc
blob4cbecf4447a8957bd066e83dc43f376b32f766f0
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, const std::string& reason) {
21 typedef HANDLE (WINAPI* PowerCreateRequestPtr)(PREASON_CONTEXT);
22 typedef BOOL (WINAPI* PowerSetRequestPtr)(HANDLE, POWER_REQUEST_TYPE);
24 if (type == PowerRequestExecutionRequired &&
25 base::win::GetVersion() < base::win::VERSION_WIN8) {
26 return INVALID_HANDLE_VALUE;
29 static PowerCreateRequestPtr PowerCreateRequestFn = NULL;
30 static PowerSetRequestPtr PowerSetRequestFn = NULL;
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"));
39 if (!PowerCreateRequestFn || !PowerSetRequestFn)
40 return INVALID_HANDLE_VALUE;
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());
48 base::win::ScopedHandle handle(PowerCreateRequestFn(&context));
49 if (!handle.IsValid())
50 return INVALID_HANDLE_VALUE;
52 if (PowerSetRequestFn(handle.Get(), type))
53 return handle.Take();
55 // Something went wrong.
56 return INVALID_HANDLE_VALUE;
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;
65 if (type == PowerRequestExecutionRequired &&
66 base::win::GetVersion() < base::win::VERSION_WIN8) {
67 return;
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"));
76 if (!PowerClearRequestFn)
77 return;
79 BOOL success = PowerClearRequestFn(request_handle.Get(), type);
80 DCHECK(success);
83 void ApplySimpleBlock(PowerSaveBlocker::PowerSaveBlockerType type,
84 int delta) {
85 g_blocker_count[type] += delta;
86 DCHECK_GE(g_blocker_count[type], 0);
88 if (g_blocker_count[type] > 1)
89 return;
91 DWORD this_flag = 0;
92 if (type == PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension)
93 this_flag |= ES_SYSTEM_REQUIRED;
94 else
95 this_flag |= ES_DISPLAY_REQUIRED;
97 DCHECK(this_flag);
99 static DWORD flags = ES_CONTINUOUS;
100 if (!g_blocker_count[type])
101 flags &= ~this_flag;
102 else
103 flags |= this_flag;
105 SetThreadExecutionState(flags);
108 } // namespace
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) {}
116 // Does the actual work to apply or remove the desired power save block.
117 void ApplyBlock();
118 void RemoveBlock();
120 // Returns the equivalent POWER_REQUEST_TYPE for this request.
121 POWER_REQUEST_TYPE RequestType();
123 private:
124 friend class base::RefCountedThreadSafe<Delegate>;
125 ~Delegate() {}
127 PowerSaveBlockerType type_;
128 const std::string reason_;
129 base::win::ScopedHandle handle_;
131 DISALLOW_COPY_AND_ASSIGN(Delegate);
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);
139 handle_.Set(CreatePowerRequest(RequestType(), reason_));
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);
147 DeletePowerRequest(RequestType(), handle_.Take());
150 POWER_REQUEST_TYPE PowerSaveBlockerImpl::Delegate::RequestType() {
151 if (type_ == kPowerSaveBlockPreventDisplaySleep)
152 return PowerRequestDisplayRequired;
154 if (base::win::GetVersion() < base::win::VERSION_WIN8)
155 return PowerRequestSystemRequired;
157 return PowerRequestExecutionRequired;
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_));
168 PowerSaveBlockerImpl::~PowerSaveBlockerImpl() {
169 BrowserThread::PostTask(
170 BrowserThread::UI, FROM_HERE,
171 base::Bind(&Delegate::RemoveBlock, delegate_));
174 } // namespace content