Home | History | Annotate | Download | only in browser
      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