123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- // Copyright 2013 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/power_monitor/power_monitor_device_source.h"
- #include "base/mac/foundation_util.h"
- #include "base/mac/scoped_cftyperef.h"
- #include "base/power_monitor/power_monitor.h"
- #include "base/power_monitor/power_monitor_source.h"
- #include <IOKit/IOMessage.h>
- #include <IOKit/ps/IOPSKeys.h>
- #include <IOKit/ps/IOPowerSources.h>
- #include <IOKit/pwr_mgt/IOPMLib.h>
- namespace base {
- void ProcessPowerEventHelper(PowerMonitorSource::PowerEvent event) {
- PowerMonitorSource::ProcessPowerEvent(event);
- }
- bool PowerMonitorDeviceSource::IsOnBatteryPower() {
- base::ScopedCFTypeRef<CFTypeRef> info(IOPSCopyPowerSourcesInfo());
- if (!info)
- return false;
- base::ScopedCFTypeRef<CFArrayRef> power_sources_list(
- IOPSCopyPowerSourcesList(info));
- if (!power_sources_list)
- return false;
- bool found_battery = false;
- const CFIndex count = CFArrayGetCount(power_sources_list);
- for (CFIndex i = 0; i < count; ++i) {
- const CFDictionaryRef description = IOPSGetPowerSourceDescription(
- info, CFArrayGetValueAtIndex(power_sources_list, i));
- if (!description)
- continue;
- CFStringRef current_state = base::mac::GetValueFromDictionary<CFStringRef>(
- description, CFSTR(kIOPSPowerSourceStateKey));
- if (!current_state)
- continue;
- // We only report "on battery power" if no source is on AC power.
- if (CFStringCompare(current_state, CFSTR(kIOPSOffLineValue), 0) ==
- kCFCompareEqualTo) {
- continue;
- } else if (CFStringCompare(current_state, CFSTR(kIOPSACPowerValue), 0) ==
- kCFCompareEqualTo) {
- return false;
- }
- DCHECK_EQ(CFStringCompare(current_state, CFSTR(kIOPSBatteryPowerValue), 0),
- kCFCompareEqualTo)
- << "Power source state is not one of 3 documented values";
- found_battery = true;
- }
- // At this point, either there were no readable batteries found, in which case
- // this Mac is not on battery power, or all the readable batteries were on
- // battery power, in which case, count this as being on battery power.
- return found_battery;
- }
- PowerThermalObserver::DeviceThermalState
- PowerMonitorDeviceSource::GetCurrentThermalState() {
- return thermal_state_observer_->GetCurrentThermalState();
- }
- int PowerMonitorDeviceSource::GetInitialSpeedLimit() {
- return thermal_state_observer_->GetCurrentSpeedLimit();
- }
- namespace {
- void BatteryEventCallback(void*) {
- ProcessPowerEventHelper(PowerMonitorSource::POWER_STATE_EVENT);
- }
- } // namespace
- void PowerMonitorDeviceSource::PlatformInit() {
- power_manager_port_ = IORegisterForSystemPower(
- this,
- mac::ScopedIONotificationPortRef::Receiver(notification_port_).get(),
- &SystemPowerEventCallback, ¬ifier_);
- DCHECK_NE(power_manager_port_, IO_OBJECT_NULL);
- // Add the sleep/wake notification event source to the runloop.
- CFRunLoopAddSource(
- CFRunLoopGetCurrent(),
- IONotificationPortGetRunLoopSource(notification_port_.get()),
- kCFRunLoopCommonModes);
- // Create and add the power-source-change event source to the runloop.
- power_source_run_loop_source_.reset(
- IOPSNotificationCreateRunLoopSource(&BatteryEventCallback, nullptr));
- // Verify that the source was created. This may fail if the sandbox does not
- // permit the process to access the underlying system service. See
- // https://crbug.com/897557 for an example of such a configuration bug.
- DCHECK(power_source_run_loop_source_);
- CFRunLoopAddSource(CFRunLoopGetCurrent(), power_source_run_loop_source_,
- kCFRunLoopDefaultMode);
- thermal_state_observer_ = std::make_unique<ThermalStateObserverMac>(
- BindRepeating(&PowerMonitorSource::ProcessThermalEvent),
- BindRepeating(&PowerMonitorSource::ProcessSpeedLimitEvent));
- }
- void PowerMonitorDeviceSource::PlatformDestroy() {
- CFRunLoopRemoveSource(
- CFRunLoopGetCurrent(),
- IONotificationPortGetRunLoopSource(notification_port_.get()),
- kCFRunLoopCommonModes);
- CFRunLoopRemoveSource(CFRunLoopGetCurrent(),
- power_source_run_loop_source_.get(),
- kCFRunLoopDefaultMode);
- // Deregister for system power notifications.
- IODeregisterForSystemPower(¬ifier_);
- // Close the connection to the IOPMrootDomain that was opened in
- // PlatformInit().
- IOServiceClose(power_manager_port_);
- power_manager_port_ = IO_OBJECT_NULL;
- }
- void PowerMonitorDeviceSource::SystemPowerEventCallback(
- void* refcon,
- io_service_t service,
- natural_t message_type,
- void* message_argument) {
- auto* thiz = static_cast<PowerMonitorDeviceSource*>(refcon);
- switch (message_type) {
- // If this message is not handled the system may delay sleep for 30 seconds.
- case kIOMessageCanSystemSleep:
- IOAllowPowerChange(thiz->power_manager_port_,
- reinterpret_cast<intptr_t>(message_argument));
- break;
- case kIOMessageSystemWillSleep:
- ProcessPowerEventHelper(PowerMonitorSource::SUSPEND_EVENT);
- IOAllowPowerChange(thiz->power_manager_port_,
- reinterpret_cast<intptr_t>(message_argument));
- break;
- case kIOMessageSystemWillPowerOn:
- ProcessPowerEventHelper(PowerMonitorSource::RESUME_EVENT);
- break;
- }
- }
- } // namespace base
|