xref: /aosp_15_r20/external/cronet/base/message_loop/message_pump.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2010 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/message_loop/message_pump.h"
6 
7 #include "base/check.h"
8 #include "base/message_loop/message_pump_default.h"
9 #include "base/message_loop/message_pump_for_io.h"
10 #include "base/message_loop/message_pump_for_ui.h"
11 #include "base/notreached.h"
12 #include "base/task/task_features.h"
13 #include "base/threading/platform_thread.h"
14 #include "build/build_config.h"
15 
16 #if BUILDFLAG(IS_APPLE)
17 #include "base/message_loop/message_pump_apple.h"
18 #endif
19 
20 namespace base {
21 
22 namespace {
23 
24 constexpr uint64_t kAlignWakeUpsMask = 1;
25 constexpr uint64_t kLeewayOffset = 1;
26 
PackAlignWakeUpsAndLeeway(bool align_wake_ups,TimeDelta leeway)27 constexpr uint64_t PackAlignWakeUpsAndLeeway(bool align_wake_ups,
28                                              TimeDelta leeway) {
29   return (static_cast<uint64_t>(leeway.InMilliseconds()) << kLeewayOffset) |
30          (align_wake_ups ? kAlignWakeUpsMask : 0);
31 }
32 
33 // This stores the current state of |kAlignWakeUps| and leeway. The last bit
34 // represents if |kAlignWakeUps| is enabled, and the other bits represent the
35 // leeway value applied to delayed tasks in milliseconds. An atomic is used here
36 // because the value is queried from multiple threads.
37 std::atomic<uint64_t> g_align_wake_ups_and_leeway =
38     PackAlignWakeUpsAndLeeway(false, kDefaultLeeway);
39 #if BUILDFLAG(IS_WIN)
40 bool g_explicit_high_resolution_timer_win = true;
41 #endif  // BUILDFLAG(IS_WIN)
42 
43 MessagePump::MessagePumpFactory* message_pump_for_ui_factory_ = nullptr;
44 
45 }  // namespace
46 
47 MessagePump::MessagePump() = default;
48 
49 MessagePump::~MessagePump() = default;
50 
HandleNestedNativeLoopWithApplicationTasks(bool application_tasks_desired)51 bool MessagePump::HandleNestedNativeLoopWithApplicationTasks(
52     bool application_tasks_desired) {
53   return false;
54 }
55 
56 // static
OverrideMessagePumpForUIFactory(MessagePumpFactory * factory)57 void MessagePump::OverrideMessagePumpForUIFactory(MessagePumpFactory* factory) {
58   DCHECK(!message_pump_for_ui_factory_);
59   message_pump_for_ui_factory_ = factory;
60 }
61 
62 // static
IsMessagePumpForUIFactoryOveridden()63 bool MessagePump::IsMessagePumpForUIFactoryOveridden() {
64   return message_pump_for_ui_factory_ != nullptr;
65 }
66 
67 // static
Create(MessagePumpType type)68 std::unique_ptr<MessagePump> MessagePump::Create(MessagePumpType type) {
69   switch (type) {
70     case MessagePumpType::UI:
71       if (message_pump_for_ui_factory_)
72         return message_pump_for_ui_factory_();
73 #if BUILDFLAG(IS_APPLE)
74       return message_pump_apple::Create();
75 #elif BUILDFLAG(IS_NACL) || BUILDFLAG(IS_AIX)
76       // Currently NaCl and AIX don't have a UI MessagePump.
77       // TODO(abarth): Figure out if we need this.
78       NOTREACHED();
79       return nullptr;
80 #elif BUILDFLAG(IS_ANDROID)
81       {
82         auto message_pump = std::make_unique<MessagePumpAndroid>();
83         message_pump->set_is_type_ui(true);
84         return message_pump;
85       }
86 #else
87       return std::make_unique<MessagePumpForUI>();
88 #endif
89 
90     case MessagePumpType::IO:
91       return std::make_unique<MessagePumpForIO>();
92 
93 #if BUILDFLAG(IS_ANDROID)
94     case MessagePumpType::JAVA:
95       return std::make_unique<MessagePumpAndroid>();
96 #endif
97 
98 #if BUILDFLAG(IS_APPLE)
99     case MessagePumpType::NS_RUNLOOP:
100       return std::make_unique<MessagePumpNSRunLoop>();
101 #endif
102 
103     case MessagePumpType::CUSTOM:
104       NOTREACHED();
105       return nullptr;
106 
107     case MessagePumpType::DEFAULT:
108 #if BUILDFLAG(IS_IOS)
109       // On iOS, a native runloop is always required to pump system work.
110       return std::make_unique<MessagePumpCFRunLoop>();
111 #else
112       return std::make_unique<MessagePumpDefault>();
113 #endif
114   }
115 }
116 
117 // static
InitializeFeatures()118 void MessagePump::InitializeFeatures() {
119   ResetAlignWakeUpsState();
120 #if BUILDFLAG(IS_WIN)
121   g_explicit_high_resolution_timer_win =
122       FeatureList::IsEnabled(kExplicitHighResolutionTimerWin);
123   MessagePumpWin::InitializeFeatures();
124 #endif
125 }
126 
127 // static
OverrideAlignWakeUpsState(bool enabled,TimeDelta leeway)128 void MessagePump::OverrideAlignWakeUpsState(bool enabled, TimeDelta leeway) {
129   g_align_wake_ups_and_leeway.store(PackAlignWakeUpsAndLeeway(enabled, leeway),
130                                     std::memory_order_relaxed);
131 }
132 
133 // static
ResetAlignWakeUpsState()134 void MessagePump::ResetAlignWakeUpsState() {
135   OverrideAlignWakeUpsState(FeatureList::IsEnabled(kAlignWakeUps),
136                             kTaskLeewayParam.Get());
137 }
138 
139 // static
GetAlignWakeUpsEnabled()140 bool MessagePump::GetAlignWakeUpsEnabled() {
141   return g_align_wake_ups_and_leeway.load(std::memory_order_relaxed) &
142          kAlignWakeUpsMask;
143 }
144 
145 // static
GetLeewayIgnoringThreadOverride()146 TimeDelta MessagePump::GetLeewayIgnoringThreadOverride() {
147   return Milliseconds(
148       g_align_wake_ups_and_leeway.load(std::memory_order_relaxed) >>
149       kLeewayOffset);
150 }
151 
152 // static
GetLeewayForCurrentThread()153 TimeDelta MessagePump::GetLeewayForCurrentThread() {
154   // For some threads, there might be an override of the leeway, so check it
155   // first.
156   auto leeway_override = PlatformThread::GetThreadLeewayOverride();
157   if (leeway_override.has_value()) {
158     return leeway_override.value();
159   }
160   return GetLeewayIgnoringThreadOverride();
161 }
162 
AdjustDelayedRunTime(TimeTicks earliest_time,TimeTicks run_time,TimeTicks latest_time)163 TimeTicks MessagePump::AdjustDelayedRunTime(TimeTicks earliest_time,
164                                             TimeTicks run_time,
165                                             TimeTicks latest_time) {
166   // Windows relies on the low resolution timer rather than manual wake up
167   // alignment when the leeway is less than the OS default timer resolution.
168 #if BUILDFLAG(IS_WIN)
169   if (g_explicit_high_resolution_timer_win &&
170       GetLeewayForCurrentThread() <=
171           Milliseconds(Time::kMinLowResolutionThresholdMs)) {
172     return earliest_time;
173   }
174 #endif  // BUILDFLAG(IS_WIN)
175   if (GetAlignWakeUpsEnabled()) {
176     TimeTicks aligned_run_time = earliest_time.SnappedToNextTick(
177         TimeTicks(), GetLeewayForCurrentThread());
178     return std::min(aligned_run_time, latest_time);
179   }
180   return run_time;
181 }
182 
183 }  // namespace base
184