xref: /aosp_15_r20/external/cronet/base/power_monitor/power_monitor_device_source_win.cc (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 #include "base/power_monitor/power_monitor_device_source.h"
6 
7 #include <string>
8 
9 #include "base/logging.h"
10 #include "base/power_monitor/power_monitor.h"
11 #include "base/power_monitor/power_monitor_source.h"
12 #include "base/strings/string_util.h"
13 #include "base/task/current_thread.h"
14 #include "base/task/sequenced_task_runner.h"
15 #include "base/task/thread_pool.h"
16 #include "base/win/wrapped_window_proc.h"
17 
18 namespace base {
19 
ProcessPowerEventHelper(PowerMonitorSource::PowerEvent event)20 void ProcessPowerEventHelper(PowerMonitorSource::PowerEvent event) {
21   PowerMonitorSource::ProcessPowerEvent(event);
22 }
23 
24 namespace {
25 
26 constexpr wchar_t kWindowClassName[] = L"Base_PowerMessageWindow";
27 
ProcessWmPowerBroadcastMessage(WPARAM event_id)28 void ProcessWmPowerBroadcastMessage(WPARAM event_id) {
29   PowerMonitorSource::PowerEvent power_event;
30   switch (event_id) {
31     case PBT_APMPOWERSTATUSCHANGE:  // The power status changed.
32       power_event = PowerMonitorSource::POWER_STATE_EVENT;
33       break;
34     case PBT_APMRESUMEAUTOMATIC:  // Resume from suspend.
35       // We don't notify for PBT_APMRESUMESUSPEND
36       // because, if it occurs, it is always sent as a
37       // second event after PBT_APMRESUMEAUTOMATIC.
38       power_event = PowerMonitorSource::RESUME_EVENT;
39       break;
40     case PBT_APMSUSPEND:  // System has been suspended.
41       power_event = PowerMonitorSource::SUSPEND_EVENT;
42       break;
43     default:
44       return;
45 
46       // Other Power Events:
47       // PBT_APMBATTERYLOW - removed in Vista.
48       // PBT_APMOEMEVENT - removed in Vista.
49       // PBT_APMQUERYSUSPEND - removed in Vista.
50       // PBT_APMQUERYSUSPENDFAILED - removed in Vista.
51       // PBT_APMRESUMECRITICAL - removed in Vista.
52       // PBT_POWERSETTINGCHANGE - user changed the power settings.
53   }
54 
55   ProcessPowerEventHelper(power_event);
56 }
57 
58 }  // namespace
59 
PlatformInit()60 void PowerMonitorDeviceSource::PlatformInit() {
61   // Only for testing.
62   if (!CurrentUIThread::IsSet()) {
63     return;
64   }
65   speed_limit_observer_ =
66       std::make_unique<base::SequenceBound<SpeedLimitObserverWin>>(
67           base::ThreadPool::CreateSequencedTaskRunner({}),
68           BindRepeating(&PowerMonitorSource::ProcessSpeedLimitEvent));
69 }
70 
PlatformDestroy()71 void PowerMonitorDeviceSource::PlatformDestroy() {
72   // Because |speed_limit_observer_| is sequence bound, the actual destruction
73   // happens asynchronously on its task runner. Until this has completed it is
74   // still possible for PowerMonitorSource::ProcessSpeedLimitEvent to be called.
75   speed_limit_observer_.reset();
76 }
77 
78 // Function to query the system to see if it is currently running on
79 // battery power.  Returns true if running on battery.
IsOnBatteryPower()80 bool PowerMonitorDeviceSource::IsOnBatteryPower() {
81   SYSTEM_POWER_STATUS status;
82   if (!::GetSystemPowerStatus(&status)) {
83     DPLOG(ERROR) << "GetSystemPowerStatus failed";
84     return false;
85   }
86   return (status.ACLineStatus == 0);
87 }
88 
GetInitialSpeedLimit()89 int PowerMonitorDeviceSource::GetInitialSpeedLimit() {
90   // Returns the maximum value once at start. Subsequent actual values will be
91   // provided asynchronously via callbacks instead.
92   return PowerThermalObserver::kSpeedLimitMax;
93 }
94 
PowerMessageWindow()95 PowerMonitorDeviceSource::PowerMessageWindow::PowerMessageWindow() {
96   if (!CurrentUIThread::IsSet()) {
97     // Creating this window in (e.g.) a renderer inhibits shutdown on Windows.
98     // See http://crbug.com/230122. TODO(vandebo): http://crbug.com/236031
99     DLOG(ERROR)
100         << "Cannot create windows on non-UI thread, power monitor disabled!";
101     return;
102   }
103   WNDCLASSEX window_class;
104   base::win::InitializeWindowClass(
105       kWindowClassName,
106       &base::win::WrappedWindowProc<
107           PowerMonitorDeviceSource::PowerMessageWindow::WndProcThunk>,
108       0, 0, 0, nullptr, nullptr, nullptr, nullptr, nullptr, &window_class);
109   instance_ = window_class.hInstance;
110   ATOM clazz = ::RegisterClassEx(&window_class);
111   DCHECK(clazz);
112 
113   message_hwnd_ =
114       ::CreateWindowEx(WS_EX_NOACTIVATE, kWindowClassName, nullptr, WS_POPUP, 0,
115                        0, 0, 0, nullptr, nullptr, instance_, nullptr);
116   if (message_hwnd_) {
117     // On machines with modern standby calling RegisterSuspendResumeNotification
118     // is required in order to get the PBT_APMSUSPEND message.
119     power_notify_handle_ = ::RegisterSuspendResumeNotification(
120         message_hwnd_, DEVICE_NOTIFY_WINDOW_HANDLE);
121   }
122 }
123 
~PowerMessageWindow()124 PowerMonitorDeviceSource::PowerMessageWindow::~PowerMessageWindow() {
125   if (message_hwnd_) {
126     if (power_notify_handle_)
127       ::UnregisterSuspendResumeNotification(power_notify_handle_);
128 
129     ::DestroyWindow(message_hwnd_);
130     ::UnregisterClass(kWindowClassName, instance_);
131   }
132 }
133 
134 // static
WndProcThunk(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)135 LRESULT CALLBACK PowerMonitorDeviceSource::PowerMessageWindow::WndProcThunk(
136     HWND hwnd,
137     UINT message,
138     WPARAM wparam,
139     LPARAM lparam) {
140   switch (message) {
141     case WM_POWERBROADCAST:
142       ProcessWmPowerBroadcastMessage(wparam);
143       return TRUE;
144     default:
145       return ::DefWindowProc(hwnd, message, wparam, lparam);
146   }
147 }
148 
149 }  // namespace base
150