diff options
author | rvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-18 21:23:08 +0000 |
---|---|---|
committer | rvargas@google.com <rvargas@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-18 21:23:08 +0000 |
commit | c8d0c146d5b213326980e360172394ca08f790ba (patch) | |
tree | 98da33c9246ff6f3043b3e85d0cbb1b2c548d873 /base | |
parent | 0e6ce626ab966908d1a626005a167235020b797a (diff) | |
download | chromium_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.h | 31 | ||||
-rw-r--r-- | base/system_monitor/system_monitor_android.cc | 18 | ||||
-rw-r--r-- | base/system_monitor/system_monitor_posix.cc | 18 | ||||
-rw-r--r-- | base/system_monitor/system_monitor_unittest.cc | 28 | ||||
-rw-r--r-- | base/system_monitor/system_monitor_win.cc | 148 |
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() { |