xref: /aosp_15_r20/external/cronet/base/power_monitor/power_monitor_device_source_mac.mm (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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, &notifier_);
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(&notifier_);
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