summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authorwillchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-05-18 07:29:56 +0000
committerwillchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-05-18 07:29:56 +0000
commite41d7ddd66de84c0d521358d1478d9da77384563 (patch)
tree796268f8f8b66753c41eebb8c95d8c9a53872760 /base
parent6e20962febbab9e523976d0cc792710bf6daf521 (diff)
downloadchromium_src-e41d7ddd66de84c0d521358d1478d9da77384563.zip
chromium_src-e41d7ddd66de84c0d521358d1478d9da77384563.tar.gz
chromium_src-e41d7ddd66de84c0d521358d1478d9da77384563.tar.bz2
Move SystemMonitor to base/.
I plan to use SystemMonitor in net/. Fix up the Mac implementation not to use Cocoa APIs since @interface is not allowed in base. BUG=none TEST=none Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=85732 Review URL: http://codereview.chromium.org/7015017 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@85737 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r--base/base.gyp2
-rw-r--r--base/base.gypi5
-rw-r--r--base/system_monitor/system_monitor.cc108
-rw-r--r--base/system_monitor/system_monitor.h142
-rw-r--r--base/system_monitor/system_monitor_mac.mm78
-rw-r--r--base/system_monitor/system_monitor_posix.cc14
-rw-r--r--base/system_monitor/system_monitor_unittest.cc91
-rw-r--r--base/system_monitor/system_monitor_win.cc50
8 files changed, 489 insertions, 1 deletions
diff --git a/base/base.gyp b/base/base.gyp
index 8514894..68974f5 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -186,6 +186,7 @@
'sys_info_unittest.cc',
'sys_string_conversions_mac_unittest.mm',
'sys_string_conversions_unittest.cc',
+ 'system_monitor/system_monitor_unittest.cc',
'task_queue_unittest.cc',
'task_unittest.cc',
'template_util_unittest.cc',
@@ -283,7 +284,6 @@
['exclude', '^win/'],
],
'sources!': [
- 'system_monitor_unittest.cc',
'time_win_unittest.cc',
'trace_event_win_unittest.cc',
'win_util_unittest.cc',
diff --git a/base/base.gypi b/base/base.gypi
index 56da313..25060bb 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -243,6 +243,11 @@
'synchronization/waitable_event_watcher_posix.cc',
'synchronization/waitable_event_watcher_win.cc',
'synchronization/waitable_event_win.cc',
+ 'system_monitor/system_monitor.cc',
+ 'system_monitor/system_monitor.h',
+ 'system_monitor/system_monitor_mac.mm',
+ 'system_monitor/system_monitor_posix.cc',
+ 'system_monitor/system_monitor_win.cc',
'sys_info.h',
'sys_info_chromeos.cc',
'sys_info_freebsd.cc',
diff --git a/base/system_monitor/system_monitor.cc b/base/system_monitor/system_monitor.cc
new file mode 100644
index 0000000..7b1349c
--- /dev/null
+++ b/base/system_monitor/system_monitor.cc
@@ -0,0 +1,108 @@
+// Copyright (c) 2011 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/logging.h"
+#include "base/message_loop.h"
+#include "base/time.h"
+
+namespace base {
+
+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)
+#if defined(OS_MACOSX)
+ PlatformInit();
+#endif
+}
+
+SystemMonitor::~SystemMonitor() {
+#if defined(OS_MACOSX)
+ PlatformDestroy();
+#endif
+ 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() {
+ VLOG(1) << "PowerStateChange: " << (BatteryPower() ? "On" : "Off")
+ << " battery";
+ observer_list_->Notify(&PowerObserver::OnPowerStateChange, BatteryPower());
+}
+
+void SystemMonitor::NotifySuspend() {
+ VLOG(1) << "Power Suspending";
+ observer_list_->Notify(&PowerObserver::OnSuspend);
+}
+
+void SystemMonitor::NotifyResume() {
+ VLOG(1) << "Power Resuming";
+ observer_list_->Notify(&PowerObserver::OnResume);
+}
+
+void SystemMonitor::BatteryCheck() {
+ ProcessPowerMessage(SystemMonitor::POWER_STATE_EVENT);
+}
+
+} // namespace base
diff --git a/base/system_monitor/system_monitor.h b/base/system_monitor/system_monitor.h
new file mode 100644
index 0000000..e552b26
--- /dev/null
+++ b/base/system_monitor/system_monitor.h
@@ -0,0 +1,142 @@
+// Copyright (c) 2011 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 BASE_SYSTEM_MONITOR_SYSTEM_MONITOR_H_
+#define BASE_SYSTEM_MONITOR_SYSTEM_MONITOR_H_
+#pragma once
+
+#include "base/basictypes.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)
+
+#if defined(OS_MACOSX)
+#include <IOKit/pwr_mgt/IOPMLib.h>
+#include <IOKit/IOMessage.h>
+#endif // OS_MACOSX
+
+namespace base {
+
+// 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:
+ // 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.
+ };
+
+ // 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_;
+ }
+
+ // 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() {}
+
+ protected:
+ virtual ~PowerObserver() {}
+ };
+
+ // 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:
+#if defined(OS_MACOSX)
+ void PlatformInit();
+ void PlatformDestroy();
+#endif
+
+ // 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
+
+#if defined(OS_MACOSX)
+ IONotificationPortRef notification_port_ref_;
+ io_object_t notifier_object_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(SystemMonitor);
+};
+
+} // namespace base
+
+#endif // BASE_SYSTEM_MONITOR_SYSTEM_MONITOR_H_
diff --git a/base/system_monitor/system_monitor_mac.mm b/base/system_monitor/system_monitor_mac.mm
new file mode 100644
index 0000000..8611613
--- /dev/null
+++ b/base/system_monitor/system_monitor_mac.mm
@@ -0,0 +1,78 @@
+// Copyright (c) 2011 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.
+
+// Implementation based on sample code from
+// http://developer.apple.com/library/mac/#qa/qa1340/_index.html.
+
+#include "base/system_monitor/system_monitor.h"
+
+#include <IOKit/pwr_mgt/IOPMLib.h>
+#include <IOKit/IOMessage.h>
+
+namespace base {
+
+namespace {
+
+io_connect_t g_system_power_io_port = 0;
+
+void SystemPowerEventCallback(void* system_monitor,
+ io_service_t service,
+ natural_t message_type,
+ void* message_argument) {
+ DCHECK(system_monitor);
+ SystemMonitor* sys_monitor = reinterpret_cast<SystemMonitor*>(system_monitor);
+ switch (message_type) {
+ case kIOMessageSystemWillSleep:
+ sys_monitor->ProcessPowerMessage(SystemMonitor::SUSPEND_EVENT);
+ IOAllowPowerChange(g_system_power_io_port,
+ reinterpret_cast<int>(message_argument));
+ break;
+
+ case kIOMessageSystemWillPowerOn:
+ sys_monitor->ProcessPowerMessage(SystemMonitor::RESUME_EVENT);
+ break;
+ }
+}
+
+} // namespace
+
+void SystemMonitor::PlatformInit() {
+ DCHECK_EQ(g_system_power_io_port, 0u);
+
+ // Notification port allocated by IORegisterForSystemPower.
+
+ g_system_power_io_port = IORegisterForSystemPower(
+ this, &notification_port_ref_, SystemPowerEventCallback,
+ &notifier_object_);
+ DCHECK_NE(g_system_power_io_port, 0u);
+
+ // Add the notification port to the application runloop
+ CFRunLoopAddSource(CFRunLoopGetCurrent(),
+ IONotificationPortGetRunLoopSource(notification_port_ref_),
+ kCFRunLoopCommonModes);
+}
+
+void SystemMonitor::PlatformDestroy() {
+ DCHECK_NE(g_system_power_io_port, 0u);
+
+ // Remove the sleep notification port from the application runloop
+ CFRunLoopRemoveSource(
+ CFRunLoopGetCurrent(),
+ IONotificationPortGetRunLoopSource(notification_port_ref_),
+ kCFRunLoopCommonModes);
+
+ // Deregister for system sleep notifications
+ IODeregisterForSystemPower(&notifier_object_);
+
+ // IORegisterForSystemPower implicitly opens the Root Power Domain IOService,
+ // so we close it here.
+ IOServiceClose(g_system_power_io_port);
+
+ g_system_power_io_port = 0;
+
+ // Destroy the notification port allocated by IORegisterForSystemPower.
+ IONotificationPortDestroy(notification_port_ref_);
+}
+
+} // namespace base
diff --git a/base/system_monitor/system_monitor_posix.cc b/base/system_monitor/system_monitor_posix.cc
new file mode 100644
index 0000000..6cf01bf
--- /dev/null
+++ b/base/system_monitor/system_monitor_posix.cc
@@ -0,0 +1,14 @@
+// Copyright (c) 2011 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"
+
+namespace base {
+
+bool SystemMonitor::IsBatteryPower() {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+} // namespace base
diff --git a/base/system_monitor/system_monitor_unittest.cc b/base/system_monitor/system_monitor_unittest.cc
new file mode 100644
index 0000000..9517247
--- /dev/null
+++ b/base/system_monitor/system_monitor_unittest.cc
@@ -0,0 +1,91 @@
+// Copyright (c) 2011 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 "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+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);
+}
+
+} // namespace base
diff --git a/base/system_monitor/system_monitor_win.cc b/base/system_monitor/system_monitor_win.cc
new file mode 100644
index 0000000..84f2b2e
--- /dev/null
+++ b/base/system_monitor/system_monitor_win.cc
@@ -0,0 +1,50 @@
+// Copyright (c) 2011 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"
+
+namespace base {
+
+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);
+}
+
+} // namespace base