summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authorrvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-05-18 21:23:08 +0000
committerrvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-05-18 21:23:08 +0000
commitc8d0c146d5b213326980e360172394ca08f790ba (patch)
tree98da33c9246ff6f3043b3e85d0cbb1b2c548d873 /base
parent0e6ce626ab966908d1a626005a167235020b797a (diff)
downloadchromium_src-c8d0c146d5b213326980e360172394ca08f790ba.zip
chromium_src-c8d0c146d5b213326980e360172394ca08f790ba.tar.gz
chromium_src-c8d0c146d5b213326980e360172394ca08f790ba.tar.bz2
Base: Add power requirements to the System monitor.
The only thing we need in the short term is CPU_REQUIRED, and that part is implemented for all platforms (as far as it makes sense). The other options are implemented for Windows, but given that currently there's no user, I expect the implementation for other platforms to be written when there's an actual need for it. BUG=126591 TEST=none Review URL: https://chromiumcodereview.appspot.com/10406012 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@137960 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r--base/system_monitor/system_monitor.h31
-rw-r--r--base/system_monitor/system_monitor_android.cc18
-rw-r--r--base/system_monitor/system_monitor_posix.cc18
-rw-r--r--base/system_monitor/system_monitor_unittest.cc28
-rw-r--r--base/system_monitor/system_monitor_win.cc148
5 files changed, 240 insertions, 3 deletions
diff --git a/base/system_monitor/system_monitor.h b/base/system_monitor/system_monitor.h
index 3f73b15..e0decc9 100644
--- a/base/system_monitor/system_monitor.h
+++ b/base/system_monitor/system_monitor.h
@@ -6,10 +6,13 @@
#define BASE_SYSTEM_MONITOR_SYSTEM_MONITOR_H_
#pragma once
+#include <map>
#include <string>
+#include <utility>
#include "base/base_export.h"
#include "base/basictypes.h"
+#include "base/threading/thread_checker.h"
#include "build/build_config.h"
// Windows HiRes timers drain the battery faster so we need to know the battery
@@ -46,6 +49,13 @@ class BASE_EXPORT SystemMonitor {
RESUME_EVENT // The system is being resumed.
};
+ enum PowerRequirement {
+ DISPLAY_REQUIRED, // The display should not be shut down.
+ SYSTEM_REQUIRED, // The system should not be suspended.
+ CPU_REQUIRED, // The process should not be suspended.
+ TEST_REQUIRED // This is used by unit tests.
+ };
+
typedef unsigned int DeviceIdType;
// Create SystemMonitor. Only one SystemMonitor instance per application
@@ -145,6 +155,22 @@ class BASE_EXPORT SystemMonitor {
const FilePath& path);
void ProcessMediaDeviceDetached(const DeviceIdType& id);
+ // Enters or leaves a period of time with a given |requirement|. If the
+ // operation has multiple requirements, make sure to use a unique |reason| for
+ // each one. Reusing the same |reason| is OK as far as the |requirement| is
+ // the same in every call, and each BeginPowerRequirement call is paired with
+ // a call to EndPowerRequirement. |reason| is expected to be an ASCII string.
+ // Must be called from the thread that created the SystemMonitor.
+ // Warning: Please remember that sleep deprivation is not a good thing; use
+ // with caution.
+ void BeginPowerRequirement(PowerRequirement requirement,
+ const std::string& reason);
+ void EndPowerRequirement(PowerRequirement requirement,
+ const std::string& reason);
+
+ // Returns the number of outsanding power requirement requests.
+ size_t GetPowerRequirementsCountForTest() const;
+
private:
#if defined(OS_MACOSX)
void PlatformInit();
@@ -176,6 +202,11 @@ class BASE_EXPORT SystemMonitor {
bool battery_in_use_;
bool suspended_;
+#if defined(OS_WIN)
+ std::map<std::string, std::pair<HANDLE, int> > handles_;
+ base::ThreadChecker thread_checker_;
+#endif
+
#if defined(ENABLE_BATTERY_MONITORING)
base::OneShotTimer<SystemMonitor> delayed_battery_check_;
#endif
diff --git a/base/system_monitor/system_monitor_android.cc b/base/system_monitor/system_monitor_android.cc
index c86076d..3f0931a 100644
--- a/base/system_monitor/system_monitor_android.cc
+++ b/base/system_monitor/system_monitor_android.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,6 +6,22 @@
namespace base {
+void SystemMonitor::BeginPowerRequirement(PowerRequirement requirement,
+ const std::string& reason) {
+ if (requirement == CPU_REQUIRED)
+ return;
+
+ NOTIMPLEMENTED();
+}
+
+void SystemMonitor::EndPowerRequirement(PowerRequirement requirement,
+ const std::string& reason) {
+ if (requirement == CPU_REQUIRED)
+ return; // Nothing to do.
+
+ NOTIMPLEMENTED();
+}
+
bool SystemMonitor::IsBatteryPower() {
NOTIMPLEMENTED();
return true;
diff --git a/base/system_monitor/system_monitor_posix.cc b/base/system_monitor/system_monitor_posix.cc
index 6cf01bf..c50407d 100644
--- a/base/system_monitor/system_monitor_posix.cc
+++ b/base/system_monitor/system_monitor_posix.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,6 +6,22 @@
namespace base {
+void SystemMonitor::BeginPowerRequirement(PowerRequirement requirement,
+ const std::string& reason) {
+ if (requirement == CPU_REQUIRED)
+ return;
+
+ NOTIMPLEMENTED();
+}
+
+void SystemMonitor::EndPowerRequirement(PowerRequirement requirement,
+ const std::string& reason) {
+ if (requirement == CPU_REQUIRED)
+ return; // Nothing to do.
+
+ NOTIMPLEMENTED();
+}
+
bool SystemMonitor::IsBatteryPower() {
NOTIMPLEMENTED();
return false;
diff --git a/base/system_monitor/system_monitor_unittest.cc b/base/system_monitor/system_monitor_unittest.cc
index 4f94ce5..4475dcb 100644
--- a/base/system_monitor/system_monitor_unittest.cc
+++ b/base/system_monitor/system_monitor_unittest.cc
@@ -137,4 +137,32 @@ TEST(SystemMonitor, DeviceChangeNotifications) {
loop.RunAllPending();
}
+TEST(SystemMonitor, PowerRequirements) {
+#if defined(OS_WIN)
+ MessageLoop loop;
+ SystemMonitor system_monitor;
+ ASSERT_EQ(0, system_monitor.GetPowerRequirementsCountForTest());
+
+ system_monitor.BeginPowerRequirement(SystemMonitor::TEST_REQUIRED, "foo");
+ ASSERT_EQ(1, system_monitor.GetPowerRequirementsCountForTest());
+
+ system_monitor.BeginPowerRequirement(SystemMonitor::TEST_REQUIRED, "bar");
+ ASSERT_EQ(2, system_monitor.GetPowerRequirementsCountForTest());
+
+ // A second identical request should not increase the request count.
+ system_monitor.BeginPowerRequirement(SystemMonitor::TEST_REQUIRED, "bar");
+ ASSERT_EQ(2, system_monitor.GetPowerRequirementsCountForTest());
+
+ system_monitor.EndPowerRequirement(SystemMonitor::TEST_REQUIRED, "foo");
+ ASSERT_EQ(1, system_monitor.GetPowerRequirementsCountForTest());
+
+ // The request count should not decrease until all identical requests end.
+ system_monitor.EndPowerRequirement(SystemMonitor::TEST_REQUIRED, "bar");
+ ASSERT_EQ(1, system_monitor.GetPowerRequirementsCountForTest());
+
+ system_monitor.EndPowerRequirement(SystemMonitor::TEST_REQUIRED, "bar");
+ ASSERT_EQ(0, system_monitor.GetPowerRequirementsCountForTest());
+#endif // defined(OS_WIN)
+}
+
} // namespace base
diff --git a/base/system_monitor/system_monitor_win.cc b/base/system_monitor/system_monitor_win.cc
index a8cd54a..dfa4f2d0 100644
--- a/base/system_monitor/system_monitor_win.cc
+++ b/base/system_monitor/system_monitor_win.cc
@@ -1,8 +1,110 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/system_monitor/system_monitor.h"
+#include "base/utf_string_conversions.h"
+#include "base/win/windows_version.h"
+
+namespace {
+
+// Maps a request's reason to the handle and requests count.
+typedef std::map<std::string, std::pair<HANDLE, int> > HandleMap;
+
+#if _WIN32_WINNT <= _WIN32_WINNT_WIN7
+POWER_REQUEST_TYPE PowerRequestExecutionRequired =
+ static_cast<POWER_REQUEST_TYPE>(PowerRequestAwayModeRequired + 1);
+#endif
+
+POWER_REQUEST_TYPE PowerRequestTestRequired =
+ static_cast<POWER_REQUEST_TYPE>(PowerRequestExecutionRequired + 10);
+
+POWER_REQUEST_TYPE PowerRequirementToType(
+ base::SystemMonitor::PowerRequirement requirement) {
+ switch (requirement) {
+ case base::SystemMonitor::DISPLAY_REQUIRED:
+ return PowerRequestDisplayRequired;
+ case base::SystemMonitor::SYSTEM_REQUIRED:
+ return PowerRequestSystemRequired;
+ case base::SystemMonitor::CPU_REQUIRED:
+ return PowerRequestExecutionRequired;
+ case base::SystemMonitor::TEST_REQUIRED:
+ return PowerRequestTestRequired;
+ }
+ NOTREACHED();
+ return PowerRequestTestRequired;
+}
+
+HANDLE CreatePowerRequest(POWER_REQUEST_TYPE type, const std::string& reason) {
+ typedef HANDLE (WINAPI* PowerCreateRequestPtr)(PREASON_CONTEXT);
+ typedef BOOL (WINAPI* PowerSetRequestPtr)(HANDLE, POWER_REQUEST_TYPE);
+
+ if (type == PowerRequestTestRequired)
+ return NULL;
+
+ if (type == PowerRequestExecutionRequired &&
+ base::win::GetVersion() < base::win::VERSION_WIN8) {
+ return INVALID_HANDLE_VALUE;
+ }
+
+ static PowerCreateRequestPtr PowerCreateRequestFn = NULL;
+ static PowerSetRequestPtr PowerSetRequestFn = NULL;
+
+ if (!PowerCreateRequestFn || !PowerSetRequestFn) {
+ HMODULE module = GetModuleHandle(L"kernel32.dll");
+ PowerCreateRequestFn = reinterpret_cast<PowerCreateRequestPtr>(
+ GetProcAddress(module, "PowerCreateRequest"));
+ PowerSetRequestFn = reinterpret_cast<PowerSetRequestPtr>(
+ GetProcAddress(module, "PowerSetRequest"));
+
+ if (!PowerCreateRequestFn || !PowerSetRequestFn)
+ return INVALID_HANDLE_VALUE;
+ }
+ string16 wide_reason = ASCIIToUTF16(reason);
+ REASON_CONTEXT context = {0};
+ context.Version = POWER_REQUEST_CONTEXT_VERSION;
+ context.Flags = POWER_REQUEST_CONTEXT_SIMPLE_STRING;
+ context.Reason.SimpleReasonString = const_cast<wchar_t*>(wide_reason.c_str());
+
+ base::win::ScopedHandle handle(PowerCreateRequestFn(&context));
+ if (!handle.IsValid())
+ return INVALID_HANDLE_VALUE;
+
+ if (PowerSetRequestFn(handle, type))
+ return handle.Take();
+
+ // Something went wrong.
+ return INVALID_HANDLE_VALUE;
+}
+
+// Takes ownership of the |handle|.
+void DeletePowerRequest(POWER_REQUEST_TYPE type, HANDLE handle) {
+ if (type == PowerRequestTestRequired)
+ return;
+
+ base::win::ScopedHandle request_handle(handle);
+ if (!request_handle.IsValid())
+ return;
+
+ if (type == PowerRequestExecutionRequired &&
+ base::win::GetVersion() < base::win::VERSION_WIN8) {
+ return;
+ }
+
+ typedef BOOL (WINAPI* PowerClearRequestPtr)(HANDLE, POWER_REQUEST_TYPE);
+ HMODULE module = GetModuleHandle(L"kernel32.dll");
+ PowerClearRequestPtr PowerClearRequestFn =
+ reinterpret_cast<PowerClearRequestPtr>(
+ GetProcAddress(module, "PowerClearRequest"));
+
+ if (!PowerClearRequestFn)
+ return;
+
+ BOOL success = PowerClearRequest(request_handle, type);
+ DCHECK(success);
+}
+
+} // namespace.
namespace base {
@@ -36,6 +138,50 @@ void SystemMonitor::ProcessWmPowerBroadcastMessage(int event_id) {
ProcessPowerMessage(power_event);
}
+void SystemMonitor::BeginPowerRequirement(PowerRequirement requirement,
+ const std::string& reason) {
+ thread_checker_.CalledOnValidThread();
+
+ HandleMap::iterator i = handles_.find(reason);
+ if (i != handles_.end()) {
+ // This is not the first request, just increase the requests count.
+ i->second.second++;
+ DCHECK_GT(i->second.second, 1);
+ return;
+ }
+
+ HANDLE handle = CreatePowerRequest(PowerRequirementToType(requirement),
+ reason);
+
+ if (handle != INVALID_HANDLE_VALUE)
+ handles_[reason] = std::pair<HANDLE, int>(handle, 1);
+}
+
+void SystemMonitor::EndPowerRequirement(PowerRequirement requirement,
+ const std::string& reason) {
+ thread_checker_.CalledOnValidThread();
+
+ HandleMap::iterator i = handles_.find(reason);
+ if (i == handles_.end()) {
+ NOTREACHED();
+ return;
+ }
+
+ // Decrease the requests count and see if this the last request.
+ i->second.second--;
+ DCHECK_GE(i->second.second, 0);
+
+ if (i->second.second)
+ return;
+
+ DeletePowerRequest(PowerRequirementToType(requirement), i->second.first);
+ handles_.erase(i);
+}
+
+size_t SystemMonitor::GetPowerRequirementsCountForTest() const {
+ return handles_.size();
+}
+
// Function to query the system to see if it is currently running on
// battery power. Returns true if running on battery.
bool SystemMonitor::IsBatteryPower() {