1// Copyright 2013 The Chromium Authors 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5// Implementation based on sample code from 6// http://developer.apple.com/library/mac/#qa/qa1340/_index.html. 7 8#include "base/power_monitor/power_monitor_device_source.h" 9 10#include "base/apple/foundation_util.h" 11#include "base/apple/scoped_cftyperef.h" 12#include "base/power_monitor/power_monitor.h" 13#include "base/power_monitor/power_monitor_source.h" 14 15#include <IOKit/IOMessage.h> 16#include <IOKit/ps/IOPSKeys.h> 17#include <IOKit/ps/IOPowerSources.h> 18#include <IOKit/pwr_mgt/IOPMLib.h> 19 20namespace base { 21 22PowerThermalObserver::DeviceThermalState 23PowerMonitorDeviceSource::GetCurrentThermalState() { 24 return thermal_state_observer_->GetCurrentThermalState(); 25} 26 27int PowerMonitorDeviceSource::GetInitialSpeedLimit() { 28 return thermal_state_observer_->GetCurrentSpeedLimit(); 29} 30 31void PowerMonitorDeviceSource::GetBatteryState() { 32 DCHECK(battery_level_provider_); 33 // base::Unretained is safe because the callback is immediately invoked 34 // inside `BatteryLevelProvider::GetBatteryState()`. 35 battery_level_provider_->GetBatteryState( 36 base::BindOnce(&PowerMonitorDeviceSource::OnBatteryStateReceived, 37 base::Unretained(this))); 38} 39 40void PowerMonitorDeviceSource::OnBatteryStateReceived( 41 const std::optional<BatteryLevelProvider::BatteryState>& battery_state) { 42 is_on_battery_ = 43 battery_state.has_value() && !battery_state->is_external_power_connected; 44 PowerMonitorSource::ProcessPowerEvent(PowerMonitorSource::POWER_STATE_EVENT); 45} 46 47void PowerMonitorDeviceSource::PlatformInit() { 48 power_manager_port_ = IORegisterForSystemPower( 49 this, 50 mac::ScopedIONotificationPortRef::Receiver(notification_port_).get(), 51 &SystemPowerEventCallback, ¬ifier_); 52 DCHECK_NE(power_manager_port_, IO_OBJECT_NULL); 53 54 // Add the sleep/wake notification event source to the runloop. 55 CFRunLoopAddSource( 56 CFRunLoopGetCurrent(), 57 IONotificationPortGetRunLoopSource(notification_port_.get()), 58 kCFRunLoopCommonModes); 59 60 battery_level_provider_ = BatteryLevelProvider::Create(); 61 // Get the initial state for `is_on_battery_` and register for all future 62 // power-source-change events. 63 GetBatteryState(); 64 // base::Unretained is safe because `this` owns `power_source_event_source_`, 65 // which exclusively owns the callback. 66 power_source_event_source_.Start(base::BindRepeating( 67 &PowerMonitorDeviceSource::GetBatteryState, base::Unretained(this))); 68 69 thermal_state_observer_ = std::make_unique<ThermalStateObserverMac>( 70 BindRepeating(&PowerMonitorSource::ProcessThermalEvent), 71 BindRepeating(&PowerMonitorSource::ProcessSpeedLimitEvent)); 72} 73 74void PowerMonitorDeviceSource::PlatformDestroy() { 75 CFRunLoopRemoveSource( 76 CFRunLoopGetCurrent(), 77 IONotificationPortGetRunLoopSource(notification_port_.get()), 78 kCFRunLoopCommonModes); 79 80 // Deregister for system power notifications. 81 IODeregisterForSystemPower(¬ifier_); 82 83 // Close the connection to the IOPMrootDomain that was opened in 84 // PlatformInit(). 85 IOServiceClose(power_manager_port_); 86 power_manager_port_ = IO_OBJECT_NULL; 87} 88 89bool PowerMonitorDeviceSource::IsOnBatteryPower() { 90 return is_on_battery_; 91} 92 93void PowerMonitorDeviceSource::SystemPowerEventCallback( 94 void* refcon, 95 io_service_t service, 96 natural_t message_type, 97 void* message_argument) { 98 auto* thiz = static_cast<PowerMonitorDeviceSource*>(refcon); 99 100 switch (message_type) { 101 // If this message is not handled the system may delay sleep for 30 seconds. 102 case kIOMessageCanSystemSleep: 103 IOAllowPowerChange(thiz->power_manager_port_, 104 reinterpret_cast<intptr_t>(message_argument)); 105 break; 106 case kIOMessageSystemWillSleep: 107 PowerMonitorSource::ProcessPowerEvent(PowerMonitorSource::SUSPEND_EVENT); 108 IOAllowPowerChange(thiz->power_manager_port_, 109 reinterpret_cast<intptr_t>(message_argument)); 110 break; 111 112 case kIOMessageSystemWillPowerOn: 113 PowerMonitorSource::ProcessPowerEvent(PowerMonitorSource::RESUME_EVENT); 114 break; 115 } 116} 117 118} // namespace base 119