blob: cebc4c7c9fa08ca44947d3c8cd707556b86bc1dc [file] [log] [blame]
[email protected]92269382012-03-03 09:00:081// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]36e93a772009-10-23 04:18:052// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]56f762c2011-07-15 15:40:455#include "content/browser/power_save_blocker.h"
[email protected]36e93a772009-10-23 04:18:056
7#include <windows.h>
8
[email protected]92269382012-03-03 09:00:089#include "base/logging.h"
[email protected]5dede9472012-06-06 00:23:5710#include "base/utf_string_conversions.h"
11#include "base/win/scoped_handle.h"
12#include "base/win/windows_version.h"
[email protected]c38831a12011-10-28 12:44:4913#include "content/public/browser/browser_thread.h"
[email protected]36e93a772009-10-23 04:18:0514
[email protected]5dede9472012-06-06 00:23:5715namespace {
16
17int g_blocker_count[2];
18
19#if _WIN32_WINNT <= _WIN32_WINNT_WIN7
20POWER_REQUEST_TYPE PowerRequestExecutionRequired =
21 static_cast<POWER_REQUEST_TYPE>(PowerRequestAwayModeRequired + 1);
22#endif
23
24HANDLE CreatePowerRequest(POWER_REQUEST_TYPE type, const std::string& reason) {
25 typedef HANDLE (WINAPI* PowerCreateRequestPtr)(PREASON_CONTEXT);
26 typedef BOOL (WINAPI* PowerSetRequestPtr)(HANDLE, POWER_REQUEST_TYPE);
27
28 if (type == PowerRequestExecutionRequired &&
29 base::win::GetVersion() < base::win::VERSION_WIN8) {
30 return INVALID_HANDLE_VALUE;
31 }
32
33 static PowerCreateRequestPtr PowerCreateRequestFn = NULL;
34 static PowerSetRequestPtr PowerSetRequestFn = NULL;
35
36 if (!PowerCreateRequestFn || !PowerSetRequestFn) {
37 HMODULE module = GetModuleHandle(L"kernel32.dll");
38 PowerCreateRequestFn = reinterpret_cast<PowerCreateRequestPtr>(
39 GetProcAddress(module, "PowerCreateRequest"));
40 PowerSetRequestFn = reinterpret_cast<PowerSetRequestPtr>(
41 GetProcAddress(module, "PowerSetRequest"));
42
43 if (!PowerCreateRequestFn || !PowerSetRequestFn)
44 return INVALID_HANDLE_VALUE;
45 }
46 string16 wide_reason = ASCIIToUTF16(reason);
47 REASON_CONTEXT context = {0};
48 context.Version = POWER_REQUEST_CONTEXT_VERSION;
49 context.Flags = POWER_REQUEST_CONTEXT_SIMPLE_STRING;
50 context.Reason.SimpleReasonString = const_cast<wchar_t*>(wide_reason.c_str());
51
52 base::win::ScopedHandle handle(PowerCreateRequestFn(&context));
53 if (!handle.IsValid())
54 return INVALID_HANDLE_VALUE;
55
56 if (PowerSetRequestFn(handle, type))
57 return handle.Take();
58
59 // Something went wrong.
60 return INVALID_HANDLE_VALUE;
61}
62
63// Takes ownership of the |handle|.
64void DeletePowerRequest(POWER_REQUEST_TYPE type, HANDLE handle) {
65 base::win::ScopedHandle request_handle(handle);
66 if (!request_handle.IsValid())
67 return;
68
69 if (type == PowerRequestExecutionRequired &&
70 base::win::GetVersion() < base::win::VERSION_WIN8) {
71 return;
72 }
73
74 typedef BOOL (WINAPI* PowerClearRequestPtr)(HANDLE, POWER_REQUEST_TYPE);
75 HMODULE module = GetModuleHandle(L"kernel32.dll");
76 PowerClearRequestPtr PowerClearRequestFn =
77 reinterpret_cast<PowerClearRequestPtr>(
78 GetProcAddress(module, "PowerClearRequest"));
79
80 if (!PowerClearRequestFn)
81 return;
82
83 BOOL success = PowerClearRequestFn(request_handle, type);
84 DCHECK(success);
85}
86
87void ApplySimpleBlock(content::PowerSaveBlocker::PowerSaveBlockerType type,
88 int delta) {
89 g_blocker_count[type] += delta;
90 DCHECK_GE(g_blocker_count[type], 0);
91
92 if (g_blocker_count[type] > 1)
93 return;
94
95 DWORD this_flag = 0;
96 if (type == content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension)
97 this_flag |= ES_SYSTEM_REQUIRED;
98 else
99 this_flag |= ES_DISPLAY_REQUIRED;
100
101 DCHECK(this_flag);
102
103 static DWORD flags = ES_CONTINUOUS;
104 if (!g_blocker_count[type])
105 flags &= ~this_flag;
106 else
107 flags |= this_flag;
108
109 SetThreadExecutionState(flags);
110}
111
112} // namespace.
113
114namespace content {
115
116class PowerSaveBlocker::Delegate
117 : public base::RefCountedThreadSafe<PowerSaveBlocker::Delegate> {
118 public:
119 Delegate(PowerSaveBlockerType type, const std::string& reason)
120 : type_(type), reason_(reason) {}
121
122 // Does the actual work to apply or remove the desired power save block.
123 void ApplyBlock();
124 void RemoveBlock();
125
126 // Returns the equivalent POWER_REQUEST_TYPE for this request.
127 POWER_REQUEST_TYPE RequestType();
128
129 private:
[email protected]6b55aec2012-06-11 18:02:03130 friend class base::RefCountedThreadSafe<Delegate>;
[email protected]5dede9472012-06-06 00:23:57131 ~Delegate() {}
132
133 PowerSaveBlockerType type_;
134 const std::string reason_;
135 base::win::ScopedHandle handle_;
136
137 DISALLOW_COPY_AND_ASSIGN(Delegate);
138};
139
140void PowerSaveBlocker::Delegate::ApplyBlock() {
141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]8902dac2012-06-07 21:59:14142 if (base::win::GetVersion() < base::win::VERSION_WIN7)
[email protected]5dede9472012-06-06 00:23:57143 return ApplySimpleBlock(type_, 1);
144
145 handle_.Set(CreatePowerRequest(RequestType(), reason_));
146}
147
148void PowerSaveBlocker::Delegate::RemoveBlock() {
149 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]8902dac2012-06-07 21:59:14150 if (base::win::GetVersion() < base::win::VERSION_WIN7)
[email protected]5dede9472012-06-06 00:23:57151 return ApplySimpleBlock(type_, -1);
152
153 DeletePowerRequest(RequestType(), handle_.Take());
154}
155
156POWER_REQUEST_TYPE PowerSaveBlocker::Delegate::RequestType() {
157 if (type_ == kPowerSaveBlockPreventDisplaySleep)
158 return PowerRequestDisplayRequired;
159
[email protected]8902dac2012-06-07 21:59:14160 if (base::win::GetVersion() < base::win::VERSION_WIN8)
161 return PowerRequestSystemRequired;
162
[email protected]5dede9472012-06-06 00:23:57163 return PowerRequestExecutionRequired;
164}
165
166PowerSaveBlocker::PowerSaveBlocker(PowerSaveBlockerType type,
167 const std::string& reason)
168 : delegate_(new Delegate(type, reason)) {
169 BrowserThread::PostTask(
170 BrowserThread::UI, FROM_HERE,
171 base::Bind(&Delegate::ApplyBlock, delegate_));
172}
173
174PowerSaveBlocker::~PowerSaveBlocker() {
175 BrowserThread::PostTask(
176 BrowserThread::UI, FROM_HERE,
177 base::Bind(&Delegate::RemoveBlock, delegate_));
178}
179
180} // namespace content