summaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
authorphajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-26 19:48:34 +0000
committerphajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-26 19:48:34 +0000
commit097ae5a93a863b604fd6dbd939bed0c2be1afed2 (patch)
tree61177362b1c1bd2d1b2438acc50ccb2c061b176e /app
parent902c971382790170852fe5b5d22d1b79adb31056 (diff)
downloadchromium_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.gyp8
-rw-r--r--app/hi_res_timer_manager.h29
-rw-r--r--app/hi_res_timer_manager_posix.cc19
-rw-r--r--app/hi_res_timer_manager_win.cc31
-rw-r--r--app/system_monitor.cc98
-rw-r--r--app/system_monitor.h118
-rw-r--r--app/system_monitor_posix.cc10
-rw-r--r--app/system_monitor_unittest.cc87
-rw-r--r--app/system_monitor_win.cc46
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);
+}