diff options
author | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-26 19:48:34 +0000 |
---|---|---|
committer | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-26 19:48:34 +0000 |
commit | 097ae5a93a863b604fd6dbd939bed0c2be1afed2 (patch) | |
tree | 61177362b1c1bd2d1b2438acc50ccb2c061b176e /app | |
parent | 902c971382790170852fe5b5d22d1b79adb31056 (diff) | |
download | chromium_src-097ae5a93a863b604fd6dbd939bed0c2be1afed2.zip chromium_src-097ae5a93a863b604fd6dbd939bed0c2be1afed2.tar.gz chromium_src-097ae5a93a863b604fd6dbd939bed0c2be1afed2.tar.bz2 |
Make SystemMonitor not a Singleton and move it out of base
SystemMonitor makes an assumption that through its lifetime a MessageLoop exists and stays the same. It is difficult and error-prone to satisfy that when it is a Singleton. It has caused problems in the past.
Additionally, extract HighResoltionTimerManager out of time_win.cc, eliminating yet another Singleton.
TEST=none
BUG=none
Review URL: http://codereview.chromium.org/431008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@33214 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'app')
-rw-r--r-- | app/app.gyp | 8 | ||||
-rw-r--r-- | app/hi_res_timer_manager.h | 29 | ||||
-rw-r--r-- | app/hi_res_timer_manager_posix.cc | 19 | ||||
-rw-r--r-- | app/hi_res_timer_manager_win.cc | 31 | ||||
-rw-r--r-- | app/system_monitor.cc | 98 | ||||
-rw-r--r-- | app/system_monitor.h | 118 | ||||
-rw-r--r-- | app/system_monitor_posix.cc | 10 | ||||
-rw-r--r-- | app/system_monitor_unittest.cc | 87 | ||||
-rw-r--r-- | app/system_monitor_win.cc | 46 |
9 files changed, 446 insertions, 0 deletions
diff --git a/app/app.gyp b/app/app.gyp index 78f9978..4ddfb8a 100644 --- a/app/app.gyp +++ b/app/app.gyp @@ -105,6 +105,9 @@ 'gfx/text_elider.h', 'gtk_dnd_util.cc', 'gtk_dnd_util.h', + 'hi_res_timer_manager_posix.cc', + 'hi_res_timer_manager_win.cc', + 'hi_res_timer_manager.h', 'l10n_util.cc', 'l10n_util.h', 'l10n_util_mac.h', @@ -134,6 +137,10 @@ 'sql/statement.h', 'sql/transaction.cc', 'sql/transaction.h', + 'system_monitor.cc', + 'system_monitor.h', + 'system_monitor_posix.cc', + 'system_monitor_win.cc', 'table_model.cc', 'table_model.h', 'table_model_observer.h', @@ -244,6 +251,7 @@ 'l10n_util_unittest.cc', 'os_exchange_data_win_unittest.cc', 'run_all_unittests.cc', + 'system_monitor_unittest.cc', 'test_suite.h', 'sql/connection_unittest.cc', 'sql/statement_unittest.cc', diff --git a/app/hi_res_timer_manager.h b/app/hi_res_timer_manager.h new file mode 100644 index 0000000..17a0522 --- /dev/null +++ b/app/hi_res_timer_manager.h @@ -0,0 +1,29 @@ +// Copyright (c) 2009 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. + +#ifndef APP_HI_RES_TIMER_MANAGER_H_ +#define APP_HI_RES_TIMER_MANAGER_H_ + +#include "app/system_monitor.h" + +// Ensures that the Windows high resolution timer is only used +// when not running on battery power. +class HighResolutionTimerManager : public SystemMonitor::PowerObserver { + public: + HighResolutionTimerManager(); + virtual ~HighResolutionTimerManager(); + + // SystemMonitor::PowerObserver: + void OnPowerStateChange(bool on_battery_power); + + private: + // Enable or disable the faster multimedia timer. + void UseHiResClock(bool use); + + bool hi_res_clock_used_; + + DISALLOW_COPY_AND_ASSIGN(HighResolutionTimerManager); +}; + +#endif // APP_HI_RES_TIMER_MANAGER_H_ diff --git a/app/hi_res_timer_manager_posix.cc b/app/hi_res_timer_manager_posix.cc new file mode 100644 index 0000000..f0562fd --- /dev/null +++ b/app/hi_res_timer_manager_posix.cc @@ -0,0 +1,19 @@ +// Copyright (c) 2009 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 "app/hi_res_timer_manager.h" + +// On POSIX we don't need to do anything special with the system timer. + +HighResolutionTimerManager::HighResolutionTimerManager() { +} + +HighResolutionTimerManager::~HighResolutionTimerManager() { +} + +void HighResolutionTimerManager::OnPowerStateChange(bool on_battery_power) { +} + +void HighResolutionTimerManager::UseHiResClock(bool use) { +} diff --git a/app/hi_res_timer_manager_win.cc b/app/hi_res_timer_manager_win.cc new file mode 100644 index 0000000..b7cee1d --- /dev/null +++ b/app/hi_res_timer_manager_win.cc @@ -0,0 +1,31 @@ +// Copyright (c) 2009 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 "app/hi_res_timer_manager.h" + +#include "base/time.h" + +HighResolutionTimerManager::HighResolutionTimerManager() + : hi_res_clock_used_(false) { + SystemMonitor* system_monitor = SystemMonitor::Get(); + system_monitor->AddObserver(this); + UseHiResClock(!system_monitor->BatteryPower()); +} + +HighResolutionTimerManager::~HighResolutionTimerManager() { + SystemMonitor::Get()->RemoveObserver(this); + UseHiResClock(false); +} + +void HighResolutionTimerManager::OnPowerStateChange(bool on_battery_power) { + UseHiResClock(!on_battery_power); +} + +void HighResolutionTimerManager::UseHiResClock(bool use) { + if (use == hi_res_clock_used_) + return; + bool result = base::Time::UseHighResolutionTimer(use); + DCHECK(result); + hi_res_clock_used_ = use; +} diff --git a/app/system_monitor.cc b/app/system_monitor.cc new file mode 100644 index 0000000..b0e715a --- /dev/null +++ b/app/system_monitor.cc @@ -0,0 +1,98 @@ +// Copyright (c) 2009 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 "app/system_monitor.h" + +#include "base/logging.h" +#include "base/message_loop.h" +#include "base/time.h" + +static SystemMonitor* g_system_monitor = NULL; + +#if defined(ENABLE_BATTERY_MONITORING) +// The amount of time (in ms) to wait before running the initial +// battery check. +static int kDelayedBatteryCheckMs = 10 * 1000; +#endif // defined(ENABLE_BATTERY_MONITORING) + +SystemMonitor::SystemMonitor() + : observer_list_(new ObserverListThreadSafe<PowerObserver>()), + battery_in_use_(false), + suspended_(false) { + DCHECK(!g_system_monitor); + g_system_monitor = this; + + DCHECK(MessageLoop::current()); +#if defined(ENABLE_BATTERY_MONITORING) + delayed_battery_check_.Start( + base::TimeDelta::FromMilliseconds(kDelayedBatteryCheckMs), this, + &SystemMonitor::BatteryCheck); +#endif // defined(ENABLE_BATTERY_MONITORING) +} + +SystemMonitor::~SystemMonitor() { + DCHECK_EQ(this, g_system_monitor); + g_system_monitor = NULL; +} + +// static +SystemMonitor* SystemMonitor::Get() { + return g_system_monitor; +} + +void SystemMonitor::ProcessPowerMessage(PowerEvent event_id) { + // Suppress duplicate notifications. Some platforms may + // send multiple notifications of the same event. + switch (event_id) { + case POWER_STATE_EVENT: + { + bool on_battery = IsBatteryPower(); + if (on_battery != battery_in_use_) { + battery_in_use_ = on_battery; + NotifyPowerStateChange(); + } + } + break; + case RESUME_EVENT: + if (suspended_) { + suspended_ = false; + NotifyResume(); + } + break; + case SUSPEND_EVENT: + if (!suspended_) { + suspended_ = true; + NotifySuspend(); + } + break; + } +} + +void SystemMonitor::AddObserver(PowerObserver* obs) { + observer_list_->AddObserver(obs); +} + +void SystemMonitor::RemoveObserver(PowerObserver* obs) { + observer_list_->RemoveObserver(obs); +} + +void SystemMonitor::NotifyPowerStateChange() { + LOG(INFO) << L"PowerStateChange: " + << (BatteryPower() ? L"On" : L"Off") << L" battery"; + observer_list_->Notify(&PowerObserver::OnPowerStateChange, BatteryPower()); +} + +void SystemMonitor::NotifySuspend() { + LOG(INFO) << L"Power Suspending"; + observer_list_->Notify(&PowerObserver::OnSuspend); +} + +void SystemMonitor::NotifyResume() { + LOG(INFO) << L"Power Resuming"; + observer_list_->Notify(&PowerObserver::OnResume); +} + +void SystemMonitor::BatteryCheck() { + ProcessPowerMessage(SystemMonitor::POWER_STATE_EVENT); +} diff --git a/app/system_monitor.h b/app/system_monitor.h new file mode 100644 index 0000000..abafe4f --- /dev/null +++ b/app/system_monitor.h @@ -0,0 +1,118 @@ +// Copyright (c) 2009 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. + +#ifndef APP_SYSTEM_MONITOR_H_ +#define APP_SYSTEM_MONITOR_H_ + +#include "build/build_config.h" + +// Windows HiRes timers drain the battery faster so we need to know the battery +// status. This isn't true for other platforms. +#if defined(OS_WIN) +#define ENABLE_BATTERY_MONITORING 1 +#else +#undef ENABLE_BATTERY_MONITORING +#endif // !OS_WIN + +#include "base/observer_list_threadsafe.h" +#if defined(ENABLE_BATTERY_MONITORING) +#include "base/timer.h" +#endif // defined(ENABLE_BATTERY_MONITORING) + +// Class for monitoring various system-related subsystems +// such as power management, network status, etc. +// TODO(mbelshe): Add support beyond just power management. +class SystemMonitor { + public: + // Create SystemMonitor. Only one SystemMonitor instance per application + // is allowed. + SystemMonitor(); + ~SystemMonitor(); + + // Get the application-wide SystemMonitor (if not present, returns NULL). + static SystemMonitor* Get(); + + // + // Power-related APIs + // + + // Is the computer currently on battery power. + // Can be called on any thread. + bool BatteryPower() const { + // Using a lock here is not necessary for just a bool. + return battery_in_use_; + } + + // Normalized list of power events. + enum PowerEvent { + POWER_STATE_EVENT, // The Power status of the system has changed. + SUSPEND_EVENT, // The system is being suspended. + RESUME_EVENT // The system is being resumed. + }; + + // Callbacks will be called on the thread which creates the SystemMonitor. + // During the callback, Add/RemoveObserver will block until the callbacks + // are finished. Observers should implement quick callback functions; if + // lengthy operations are needed, the observer should take care to invoke + // the operation on an appropriate thread. + class PowerObserver { + public: + // Notification of a change in power status of the computer, such + // as from switching between battery and A/C power. + virtual void OnPowerStateChange(bool on_battery_power) {} + + // Notification that the system is suspending. + virtual void OnSuspend() {} + + // Notification that the system is resuming. + virtual void OnResume() {} + }; + + // Add a new observer. + // Can be called from any thread. + // Must not be called from within a notification callback. + void AddObserver(PowerObserver* obs); + + // Remove an existing observer. + // Can be called from any thread. + // Must not be called from within a notification callback. + void RemoveObserver(PowerObserver* obs); + +#if defined(OS_WIN) + // Windows-specific handling of a WM_POWERBROADCAST message. + // Embedders of this API should hook their top-level window + // message loop and forward WM_POWERBROADCAST through this call. + void ProcessWmPowerBroadcastMessage(int event_id); +#endif + + // Cross-platform handling of a power event. + void ProcessPowerMessage(PowerEvent event_id); + + private: + // Platform-specific method to check whether the system is currently + // running on battery power. Returns true if running on batteries, + // false otherwise. + bool IsBatteryPower(); + + // Checks the battery status and notifies observers if the battery + // status has changed. + void BatteryCheck(); + + // Functions to trigger notifications. + void NotifyPowerStateChange(); + void NotifySuspend(); + void NotifyResume(); + + scoped_refptr<ObserverListThreadSafe<PowerObserver> > observer_list_; + bool battery_in_use_; + bool suspended_; + +#if defined(ENABLE_BATTERY_MONITORING) + base::OneShotTimer<SystemMonitor> delayed_battery_check_; +#endif + + DISALLOW_COPY_AND_ASSIGN(SystemMonitor); +}; + +#endif // APP_SYSTEM_MONITOR_H_ diff --git a/app/system_monitor_posix.cc b/app/system_monitor_posix.cc new file mode 100644 index 0000000..5ac7a12 --- /dev/null +++ b/app/system_monitor_posix.cc @@ -0,0 +1,10 @@ +// Copyright (c) 2009 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 "app/system_monitor.h" + +bool SystemMonitor::IsBatteryPower() { + NOTIMPLEMENTED(); + return false; +} diff --git a/app/system_monitor_unittest.cc b/app/system_monitor_unittest.cc new file mode 100644 index 0000000..5b107aa --- /dev/null +++ b/app/system_monitor_unittest.cc @@ -0,0 +1,87 @@ +// Copyright (c) 2009 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 "app/system_monitor.h" +#include "testing/gtest/include/gtest/gtest.h" + +class PowerTest : public SystemMonitor::PowerObserver { + public: + PowerTest() + : battery_(false), + power_state_changes_(0), + suspends_(0), + resumes_(0) { + } + + // PowerObserver callbacks. + void OnPowerStateChange(bool on_battery_power) { + power_state_changes_++; + } + + void OnSuspend() { + suspends_++; + } + + void OnResume() { + resumes_++; + } + + // Test status counts. + bool battery() { return battery_; } + int power_state_changes() { return power_state_changes_; } + int suspends() { return suspends_; } + int resumes() { return resumes_; } + + private: + bool battery_; // Do we currently think we're on battery power. + int power_state_changes_; // Count of OnPowerStateChange notifications. + int suspends_; // Count of OnSuspend notifications. + int resumes_; // Count of OnResume notifications. +}; + +TEST(SystemMonitor, PowerNotifications) { + const int kObservers = 5; + + // Initialize a message loop for this to run on. + MessageLoop loop; + // Initialize time() since it registers as a SystemMonitor observer. + base::Time now = base::Time::Now(); + + SystemMonitor system_monitor; + PowerTest test[kObservers]; + for (int index = 0; index < kObservers; ++index) + system_monitor.AddObserver(&test[index]); + + // Send a bunch of power changes. Since the battery power hasn't + // actually changed, we shouldn't get notifications. + for (int index = 0; index < 5; index++) { + system_monitor.ProcessPowerMessage(SystemMonitor::POWER_STATE_EVENT); + EXPECT_EQ(test[0].power_state_changes(), 0); + } + + // Sending resume when not suspended should have no effect. + system_monitor.ProcessPowerMessage(SystemMonitor::RESUME_EVENT); + loop.RunAllPending(); + EXPECT_EQ(test[0].resumes(), 0); + + // Pretend we suspended. + system_monitor.ProcessPowerMessage(SystemMonitor::SUSPEND_EVENT); + loop.RunAllPending(); + EXPECT_EQ(test[0].suspends(), 1); + + // Send a second suspend notification. This should be suppressed. + system_monitor.ProcessPowerMessage(SystemMonitor::SUSPEND_EVENT); + loop.RunAllPending(); + EXPECT_EQ(test[0].suspends(), 1); + + // Pretend we were awakened. + system_monitor.ProcessPowerMessage(SystemMonitor::RESUME_EVENT); + loop.RunAllPending(); + EXPECT_EQ(test[0].resumes(), 1); + + // Send a duplicate resume notification. This should be suppressed. + system_monitor.ProcessPowerMessage(SystemMonitor::RESUME_EVENT); + loop.RunAllPending(); + EXPECT_EQ(test[0].resumes(), 1); +} diff --git a/app/system_monitor_win.cc b/app/system_monitor_win.cc new file mode 100644 index 0000000..c9347dc --- /dev/null +++ b/app/system_monitor_win.cc @@ -0,0 +1,46 @@ +// Copyright (c) 2009 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 "app/system_monitor.h" + +void SystemMonitor::ProcessWmPowerBroadcastMessage(int event_id) { + PowerEvent power_event; + switch (event_id) { + case PBT_APMPOWERSTATUSCHANGE: // The power status changed. + power_event = POWER_STATE_EVENT; + break; + case PBT_APMRESUMEAUTOMATIC: // Resume from suspend. + //case PBT_APMRESUMESUSPEND: // User-initiated resume from suspend. + // We don't notify for this latter event + // because if it occurs it is always sent as a + // second event after PBT_APMRESUMEAUTOMATIC. + power_event = RESUME_EVENT; + break; + case PBT_APMSUSPEND: // System has been suspended. + power_event = SUSPEND_EVENT; + break; + default: + return; + + // Other Power Events: + // PBT_APMBATTERYLOW - removed in Vista. + // PBT_APMOEMEVENT - removed in Vista. + // PBT_APMQUERYSUSPEND - removed in Vista. + // PBT_APMQUERYSUSPENDFAILED - removed in Vista. + // PBT_APMRESUMECRITICAL - removed in Vista. + // PBT_POWERSETTINGCHANGE - user changed the power settings. + } + ProcessPowerMessage(power_event); +} + +// Function to query the system to see if it is currently running on +// battery power. Returns true if running on battery. +bool SystemMonitor::IsBatteryPower() { + SYSTEM_POWER_STATUS status; + if (!GetSystemPowerStatus(&status)) { + LOG(ERROR) << "GetSystemPowerStatus failed: " << GetLastError(); + return false; + } + return (status.ACLineStatus == 0); +} |