Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / browser / power_save_blocker_win.cc
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.Get(), 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.Get(), 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