1 // Copyright 2014 The Chromium Authors. All rights reserved.
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 "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
6 
7 #include <algorithm>
8 #include <utility>
9 
10 #include "base/bind.h"
11 #include "base/check_op.h"
12 #include "base/feature_list.h"
13 #include "base/metrics/field_trial_params.h"
14 #include "base/metrics/histogram.h"
15 #include "base/metrics/histogram_functions.h"
16 #include "base/metrics/histogram_macros.h"
17 #include "base/notreached.h"
18 #include "base/numerics/safe_conversions.h"
19 #include "base/optional.h"
20 #include "base/strings/string_number_conversions.h"
21 #include "base/task/common/scoped_defer_task_posting.h"
22 #include "base/task/common/task_annotator.h"
23 #include "base/threading/thread_task_runner_handle.h"
24 #include "base/trace_event/common/trace_event_common.h"
25 #include "base/trace_event/trace_event.h"
26 #include "base/trace_event/traced_value.h"
27 #include "build/build_config.h"
28 #include "components/viz/common/frame_sinks/begin_frame_args.h"
29 #include "services/metrics/public/cpp/ukm_builders.h"
30 #include "third_party/blink/public/common/input/web_input_event_attribution.h"
31 #include "third_party/blink/public/common/input/web_mouse_wheel_event.h"
32 #include "third_party/blink/public/common/input/web_touch_event.h"
33 #include "third_party/blink/public/common/page/launching_process_state.h"
34 #include "third_party/blink/public/platform/scheduler/web_agent_group_scheduler.h"
35 #include "third_party/blink/public/platform/scheduler/web_renderer_process_type.h"
36 #include "third_party/blink/renderer/platform/bindings/parkable_string_manager.h"
37 #include "third_party/blink/renderer/platform/instrumentation/resource_coordinator/renderer_resource_coordinator.h"
38 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
39 #include "third_party/blink/renderer/platform/scheduler/common/features.h"
40 #include "third_party/blink/renderer/platform/scheduler/common/process_state.h"
41 #include "third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h"
42 #include "third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.h"
43 #include "third_party/blink/renderer/platform/scheduler/main_thread/agent_scheduling_strategy.h"
44 #include "third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain.h"
45 #include "third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h"
46 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread.h"
47 #include "third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h"
48 #include "third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.h"
49 #include "third_party/blink/renderer/platform/scheduler/main_thread/widget_scheduler.h"
50 #include "third_party/blink/renderer/platform/scheduler/public/event_loop.h"
51 #include "third_party/blink/renderer/platform/wtf/functional.h"
52 #include "third_party/perfetto/protos/perfetto/trace/track_event/chrome_renderer_scheduler_state.pbzero.h"
53 #include "third_party/perfetto/protos/perfetto/trace/track_event/track_event.pbzero.h"
54 #include "v8/include/v8.h"
55 
56 namespace blink {
57 namespace scheduler {
58 
59 using base::sequence_manager::TaskQueue;
60 using base::sequence_manager::TaskTimeObserver;
61 using base::sequence_manager::TimeDomain;
62 
63 namespace {
64 const int kShortIdlePeriodDurationSampleCount = 10;
65 const double kShortIdlePeriodDurationPercentile = 50;
66 // Amount of idle time left in a frame (as a ratio of the vsync interval) above
67 // which main thread compositing can be considered fast.
68 const double kFastCompositingIdleTimeThreshold = .2;
69 const int64_t kSecondsPerMinute = 60;
70 
71 // Name of the finch study that enables using resource fetch priorities to
72 // schedule tasks on Blink.
73 constexpr const char kResourceFetchPriorityExperiment[] =
74     "ResourceFetchPriorityExperiment";
75 
RAILModeToV8RAILMode(RAILMode rail_mode)76 v8::RAILMode RAILModeToV8RAILMode(RAILMode rail_mode) {
77   switch (rail_mode) {
78     case RAILMode::kResponse:
79       return v8::RAILMode::PERFORMANCE_RESPONSE;
80     case RAILMode::kAnimation:
81       return v8::RAILMode::PERFORMANCE_ANIMATION;
82     case RAILMode::kIdle:
83       return v8::RAILMode::PERFORMANCE_IDLE;
84     case RAILMode::kLoad:
85       return v8::RAILMode::PERFORMANCE_LOAD;
86     default:
87       NOTREACHED();
88   }
89 }
90 
AddRAILModeToProto(perfetto::protos::pbzero::TrackEvent * event,RAILMode mode)91 void AddRAILModeToProto(perfetto::protos::pbzero::TrackEvent* event,
92                         RAILMode mode) {
93   perfetto::protos::pbzero::ChromeRAILMode proto_mode;
94   switch (mode) {
95     case RAILMode::kResponse:
96       proto_mode = perfetto::protos::pbzero::ChromeRAILMode::RAIL_MODE_RESPONSE;
97       break;
98     case RAILMode::kAnimation:
99       proto_mode =
100           perfetto::protos::pbzero::ChromeRAILMode::RAIL_MODE_ANIMATION;
101       break;
102     case RAILMode::kIdle:
103       proto_mode = perfetto::protos::pbzero::ChromeRAILMode::RAIL_MODE_IDLE;
104       break;
105     case RAILMode::kLoad:
106       proto_mode = perfetto::protos::pbzero::ChromeRAILMode::RAIL_MODE_LOAD;
107       break;
108     default:
109       proto_mode = perfetto::protos::pbzero::ChromeRAILMode::RAIL_MODE_NONE;
110       break;
111   }
112   event->set_chrome_renderer_scheduler_state()->set_rail_mode(proto_mode);
113 }
114 
BackgroundStateToString(bool is_backgrounded)115 const char* BackgroundStateToString(bool is_backgrounded) {
116   if (is_backgrounded) {
117     return "renderer_backgrounded";
118   } else {
119     return "renderer_foregrounded";
120   }
121 }
122 
HiddenStateToString(bool is_hidden)123 const char* HiddenStateToString(bool is_hidden) {
124   if (is_hidden) {
125     return "hidden";
126   } else {
127     return "visible";
128   }
129 }
130 
AudioPlayingStateToString(bool is_audio_playing)131 const char* AudioPlayingStateToString(bool is_audio_playing) {
132   if (is_audio_playing) {
133     return "playing";
134   } else {
135     return "silent";
136   }
137 }
138 
RendererProcessTypeToString(WebRendererProcessType process_type)139 const char* RendererProcessTypeToString(WebRendererProcessType process_type) {
140   switch (process_type) {
141     case WebRendererProcessType::kRenderer:
142       return "normal";
143     case WebRendererProcessType::kExtensionRenderer:
144       return "extension";
145   }
146   NOTREACHED();
147   return "";  // MSVC needs that.
148 }
149 
OptionalTaskDescriptionToString(base::Optional<MainThreadSchedulerImpl::TaskDescriptionForTracing> desc)150 const char* OptionalTaskDescriptionToString(
151     base::Optional<MainThreadSchedulerImpl::TaskDescriptionForTracing> desc) {
152   if (!desc)
153     return nullptr;
154   if (desc->task_type != TaskType::kDeprecatedNone)
155     return TaskTypeNames::TaskTypeToString(desc->task_type);
156   if (!desc->queue_type)
157     return "detached_tq";
158   return MainThreadTaskQueue::NameForQueueType(desc->queue_type.value());
159 }
160 
OptionalTaskPriorityToString(base::Optional<TaskQueue::QueuePriority> priority)161 const char* OptionalTaskPriorityToString(
162     base::Optional<TaskQueue::QueuePriority> priority) {
163   if (!priority)
164     return nullptr;
165   return TaskQueue::PriorityToString(priority.value());
166 }
167 
StringToTaskQueuePriority(const std::string & priority)168 TaskQueue::QueuePriority StringToTaskQueuePriority(
169     const std::string& priority) {
170   if (priority == "CONTROL") {
171     return TaskQueue::QueuePriority::kControlPriority;
172   } else if (priority == "HIGHEST") {
173     return TaskQueue::QueuePriority::kHighestPriority;
174   } else if (priority == "HIGH") {
175     return TaskQueue::QueuePriority::kHighPriority;
176   } else if (priority == "NORMAL") {
177     return TaskQueue::QueuePriority::kNormalPriority;
178   } else if (priority == "LOW") {
179     return TaskQueue::QueuePriority::kLowPriority;
180   } else if (priority == "BEST_EFFORT") {
181     return TaskQueue::QueuePriority::kBestEffortPriority;
182   } else {
183     NOTREACHED();
184     return TaskQueue::QueuePriority::kQueuePriorityCount;
185   }
186 }
187 
IsBlockingEvent(const blink::WebInputEvent & web_input_event)188 bool IsBlockingEvent(const blink::WebInputEvent& web_input_event) {
189   blink::WebInputEvent::Type type = web_input_event.GetType();
190   DCHECK(type == blink::WebInputEvent::Type::kTouchStart ||
191          type == blink::WebInputEvent::Type::kMouseWheel);
192 
193   if (type == blink::WebInputEvent::Type::kTouchStart) {
194     const WebTouchEvent& touch_event =
195         static_cast<const WebTouchEvent&>(web_input_event);
196     return touch_event.dispatch_type ==
197            blink::WebInputEvent::DispatchType::kBlocking;
198   }
199 
200   const WebMouseWheelEvent& mouse_event =
201       static_cast<const WebMouseWheelEvent&>(web_input_event);
202   return mouse_event.dispatch_type ==
203          blink::WebInputEvent::DispatchType::kBlocking;
204 }
205 
206 MainThreadSchedulerImpl* g_main_thread_scheduler = nullptr;
207 
208 }  // namespace
209 
MainThreadSchedulerImpl(std::unique_ptr<base::sequence_manager::SequenceManager> sequence_manager,base::Optional<base::Time> initial_virtual_time)210 MainThreadSchedulerImpl::MainThreadSchedulerImpl(
211     std::unique_ptr<base::sequence_manager::SequenceManager> sequence_manager,
212     base::Optional<base::Time> initial_virtual_time)
213     : sequence_manager_(std::move(sequence_manager)),
214       helper_(sequence_manager_.get(), this),
215       idle_helper_queue_(helper_.NewTaskQueue(
216           MainThreadTaskQueue::QueueCreationParams(
217               MainThreadTaskQueue::QueueType::kIdle)
218               .SetPrioritisationType(MainThreadTaskQueue::QueueTraits::
219                                          PrioritisationType::kBestEffort))),
220       idle_helper_(&helper_,
221                    this,
222                    "MainThreadSchedulerIdlePeriod",
223                    base::TimeDelta(),
224                    idle_helper_queue_->GetTaskQueue()),
225       render_widget_scheduler_signals_(this),
226       find_in_page_budget_pool_controller_(
227           new FindInPageBudgetPoolController(this)),
228       control_task_queue_(helper_.ControlMainThreadTaskQueue()),
229       compositor_task_queue_(helper_.NewTaskQueue(
230           MainThreadTaskQueue::QueueCreationParams(
231               MainThreadTaskQueue::QueueType::kCompositor)
232               .SetShouldMonitorQuiescence(true)
233               .SetPrioritisationType(MainThreadTaskQueue::QueueTraits::
234                                          PrioritisationType::kCompositor))),
235       back_forward_cache_ipc_tracking_task_queue_(helper_.NewTaskQueue(
236           MainThreadTaskQueue::QueueCreationParams(
237               MainThreadTaskQueue::QueueType::kIPCTrackingForCachedPages)
238               .SetShouldNotifyObservers(false))),
239       compositor_task_queue_enabled_voter_(
240           compositor_task_queue_->GetTaskQueue()->CreateQueueEnabledVoter()),
241       memory_purge_task_queue_(helper_.NewTaskQueue(
242           MainThreadTaskQueue::QueueCreationParams(
243               MainThreadTaskQueue::QueueType::kIdle)
244               .SetPrioritisationType(MainThreadTaskQueue::QueueTraits::
245                                          PrioritisationType::kBestEffort))),
246       memory_purge_manager_(memory_purge_task_queue_->CreateTaskRunner(
247           TaskType::kMainThreadTaskQueueMemoryPurge)),
248       non_waking_time_domain_(tick_clock()),
249       delayed_update_policy_runner_(
250           base::BindRepeating(&MainThreadSchedulerImpl::UpdatePolicy,
251                               base::Unretained(this)),
252           helper_.ControlMainThreadTaskQueue()->CreateTaskRunner(
253               TaskType::kMainThreadTaskQueueControl)),
254       main_thread_only_(this,
255                         compositor_task_queue_,
256                         helper_.GetClock(),
257                         helper_.NowTicks()),
258       any_thread_(this),
259       policy_may_need_update_(&any_thread_lock_),
260       notify_agent_strategy_task_posted_(&any_thread_lock_) {
261   // Compositor task queue and default task queue should be managed by
262   // WebThreadScheduler. Control task queue should not.
263   task_runners_.emplace(helper_.DefaultMainThreadTaskQueue(), nullptr);
264   task_runners_.emplace(
265       compositor_task_queue_,
266       compositor_task_queue_->GetTaskQueue()->CreateQueueEnabledVoter());
267 
268   back_forward_cache_ipc_tracking_task_runner_ =
269       back_forward_cache_ipc_tracking_task_queue_->CreateTaskRunner(
270           TaskType::kMainThreadTaskQueueIPCTracking);
271 
272   RegisterTimeDomain(&non_waking_time_domain_);
273 
274   v8_task_queue_ = NewTaskQueue(MainThreadTaskQueue::QueueCreationParams(
275       MainThreadTaskQueue::QueueType::kV8));
276   non_waking_task_queue_ =
277       NewTaskQueue(MainThreadTaskQueue::QueueCreationParams(
278                        MainThreadTaskQueue::QueueType::kNonWaking)
279                        .SetTimeDomain(&non_waking_time_domain_));
280 
281   v8_task_runner_ =
282       v8_task_queue_->CreateTaskRunner(TaskType::kMainThreadTaskQueueV8);
283   compositor_task_runner_ = compositor_task_queue_->CreateTaskRunner(
284       TaskType::kMainThreadTaskQueueCompositor);
285   control_task_runner_ = helper_.ControlMainThreadTaskQueue()->CreateTaskRunner(
286       TaskType::kMainThreadTaskQueueControl);
287   non_waking_task_runner_ = non_waking_task_queue_->CreateTaskRunner(
288       TaskType::kMainThreadTaskQueueNonWaking);
289 
290   // TaskQueueThrottler requires some task runners, then initialize
291   // TaskQueueThrottler after task queues/runners are initialized.
292   task_queue_throttler_.reset(
293       new TaskQueueThrottler(this, &tracing_controller_));
294   update_policy_closure_ = base::BindRepeating(
295       &MainThreadSchedulerImpl::UpdatePolicy, weak_factory_.GetWeakPtr());
296   end_renderer_hidden_idle_period_closure_.Reset(base::BindRepeating(
297       &MainThreadSchedulerImpl::EndIdlePeriod, weak_factory_.GetWeakPtr()));
298   notify_agent_strategy_on_input_event_closure_ = base::BindRepeating(
299       &MainThreadSchedulerImpl::NotifyAgentSchedulerOnInputEvent,
300       weak_factory_.GetWeakPtr());
301   agent_strategy_delay_callback_ =
302       base::BindRepeating(&MainThreadSchedulerImpl::OnAgentStrategyDelayPassed,
303                           weak_factory_.GetWeakPtr());
304 
305   TRACE_EVENT_OBJECT_CREATED_WITH_ID(
306       TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "MainThreadScheduler",
307       this);
308 
309   helper_.SetObserver(this);
310 
311   // Register a tracing state observer unless we're running in a test without a
312   // task runner. Note that it's safe to remove a non-existent observer.
313   if (base::ThreadTaskRunnerHandle::IsSet()) {
314     base::trace_event::TraceLog::GetInstance()->AddAsyncEnabledStateObserver(
315         weak_factory_.GetWeakPtr());
316   }
317 
318   internal::ProcessState::Get()->is_process_backgrounded =
319       main_thread_only().renderer_backgrounded;
320 
321   if (initial_virtual_time) {
322     main_thread_only().initial_virtual_time = *initial_virtual_time;
323     // The real uptime of the machine is irrelevant if we're using virtual time
324     // we choose an arbitrary initial offset.
325     main_thread_only().initial_virtual_time_ticks =
326         base::TimeTicks() + base::TimeDelta::FromSeconds(10);
327     EnableVirtualTime(BaseTimeOverridePolicy::OVERRIDE);
328     SetVirtualTimePolicy(VirtualTimePolicy::kPause);
329   }
330 
331   main_thread_only()
332       .compositor_priority_experiments.OnMainThreadSchedulerInitialized();
333 
334   main_thread_only().current_policy.find_in_page_priority() =
335       find_in_page_budget_pool_controller_->CurrentTaskPriority();
336 
337   g_main_thread_scheduler = this;
338 
339   // Explicitly set the priority of this queue since it is not managed by
340   // the main thread scheduler.
341   memory_purge_task_queue_->GetTaskQueue()->SetQueuePriority(
342       ComputePriority(memory_purge_task_queue_.get()));
343 }
344 
~MainThreadSchedulerImpl()345 MainThreadSchedulerImpl::~MainThreadSchedulerImpl() {
346   TRACE_EVENT_OBJECT_DELETED_WITH_ID(
347       TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "MainThreadScheduler",
348       this);
349 
350   for (auto& pair : task_runners_) {
351     pair.first->ShutdownTaskQueue();
352   }
353 
354   UnregisterTimeDomain(&non_waking_time_domain_);
355 
356   if (virtual_time_domain_)
357     UnregisterTimeDomain(virtual_time_domain_.get());
358 
359   if (virtual_time_control_task_queue_)
360     virtual_time_control_task_queue_->ShutdownTaskQueue();
361 
362   base::trace_event::TraceLog::GetInstance()->RemoveAsyncEnabledStateObserver(
363       this);
364 
365   // Ensure the renderer scheduler was shut down explicitly, because otherwise
366   // we could end up having stale pointers to the Blink heap which has been
367   // terminated by this point.
368   DCHECK(was_shutdown_);
369 
370   g_main_thread_scheduler = nullptr;
371 }
372 
373 // static
MainThreadScheduler()374 WebThreadScheduler* WebThreadScheduler::MainThreadScheduler() {
375   return g_main_thread_scheduler;
376 }
377 
MainThreadOnly(MainThreadSchedulerImpl * main_thread_scheduler_impl,const scoped_refptr<MainThreadTaskQueue> & compositor_task_runner,const base::TickClock * time_source,base::TimeTicks now)378 MainThreadSchedulerImpl::MainThreadOnly::MainThreadOnly(
379     MainThreadSchedulerImpl* main_thread_scheduler_impl,
380     const scoped_refptr<MainThreadTaskQueue>& compositor_task_runner,
381     const base::TickClock* time_source,
382     base::TimeTicks now)
383     : idle_time_estimator(compositor_task_runner,
384                           time_source,
385                           kShortIdlePeriodDurationSampleCount,
386                           kShortIdlePeriodDurationPercentile),
387       current_use_case(UseCase::kNone,
388                        "Scheduler.UseCase",
389                        &main_thread_scheduler_impl->tracing_controller_,
390                        UseCaseToString),
391       longest_jank_free_task_duration(
392           base::TimeDelta(),
393           "Scheduler.LongestJankFreeTaskDuration",
394           &main_thread_scheduler_impl->tracing_controller_,
395           TimeDeltaToMilliseconds),
396       renderer_pause_count(0,
397                            "Scheduler.PauseCount",
398                            &main_thread_scheduler_impl->tracing_controller_),
399       rail_mode_for_tracing(current_policy.rail_mode(),
400                             "Scheduler.RAILMode",
401                             &main_thread_scheduler_impl->tracing_controller_,
402                             &AddRAILModeToProto),
403       renderer_hidden(false,
404                       "RendererVisibility",
405                       &main_thread_scheduler_impl->tracing_controller_,
406                       HiddenStateToString),
407       renderer_backgrounded(kLaunchingProcessIsBackgrounded,
408                             "RendererPriority",
409                             &main_thread_scheduler_impl->tracing_controller_,
410                             BackgroundStateToString),
411       keep_active_fetch_or_worker(
412           false,
413           "Scheduler.KeepRendererActive",
414           &main_thread_scheduler_impl->tracing_controller_,
415           YesNoStateToString),
416       blocking_input_expected_soon(
417           false,
418           "Scheduler.BlockingInputExpectedSoon",
419           &main_thread_scheduler_impl->tracing_controller_,
420           YesNoStateToString),
421       have_reported_blocking_intervention_in_current_policy(
422           false,
423           "Scheduler.HasReportedBlockingInterventionInCurrentPolicy",
424           &main_thread_scheduler_impl->tracing_controller_,
425           YesNoStateToString),
426       have_reported_blocking_intervention_since_navigation(
427           false,
428           "Scheduler.HasReportedBlockingInterventionSinceNavigation",
429           &main_thread_scheduler_impl->tracing_controller_,
430           YesNoStateToString),
431       has_visible_render_widget_with_touch_handler(
432           false,
433           "Scheduler.HasVisibleRenderWidgetWithTouchHandler",
434           &main_thread_scheduler_impl->tracing_controller_,
435           YesNoStateToString),
436       in_idle_period_for_testing(
437           false,
438           "Scheduler.InIdlePeriod",
439           &main_thread_scheduler_impl->tracing_controller_,
440           YesNoStateToString),
441       use_virtual_time(false,
442                        "Scheduler.UseVirtualTime",
443                        &main_thread_scheduler_impl->tracing_controller_,
444                        YesNoStateToString),
445       is_audio_playing(false,
446                        "RendererAudioState",
447                        &main_thread_scheduler_impl->tracing_controller_,
448                        AudioPlayingStateToString),
449       compositor_will_send_main_frame_not_expected(
450           false,
451           "Scheduler.CompositorWillSendMainFrameNotExpected",
452           &main_thread_scheduler_impl->tracing_controller_,
453           YesNoStateToString),
454       has_navigated(false,
455                     "Scheduler.HasNavigated",
456                     &main_thread_scheduler_impl->tracing_controller_,
457                     YesNoStateToString),
458       pause_timers_for_webview(false,
459                                "Scheduler.PauseTimersForWebview",
460                                &main_thread_scheduler_impl->tracing_controller_,
461                                YesNoStateToString),
462       background_status_changed_at(now),
463       metrics_helper(
464           main_thread_scheduler_impl,
465           main_thread_scheduler_impl->helper_.HasCPUTimingForEachTask(),
466           now,
467           renderer_backgrounded),
468       process_type(WebRendererProcessType::kRenderer,
469                    "RendererProcessType",
470                    &main_thread_scheduler_impl->tracing_controller_,
471                    RendererProcessTypeToString),
472       task_description_for_tracing(
473           base::nullopt,
474           "Scheduler.MainThreadTask",
475           &main_thread_scheduler_impl->tracing_controller_,
476           OptionalTaskDescriptionToString),
477       task_priority_for_tracing(
478           base::nullopt,
479           "Scheduler.TaskPriority",
480           &main_thread_scheduler_impl->tracing_controller_,
481           OptionalTaskPriorityToString),
482       virtual_time_policy(VirtualTimePolicy::kAdvance),
483       virtual_time_pause_count(0),
484       max_virtual_time_task_starvation_count(0),
485       virtual_time_stopped(false),
486       nested_runloop(false),
487       prioritize_compositing_after_input(
488           false,
489           "Scheduler.PrioritizeCompositingAfterInput",
490           &main_thread_scheduler_impl->tracing_controller_,
491           YesNoStateToString),
492       compositor_priority_experiments(main_thread_scheduler_impl),
493       main_thread_compositing_is_fast(false),
494       compositor_priority(TaskQueue::QueuePriority::kNormalPriority,
495                           "Scheduler.CompositorPriority",
496                           &main_thread_scheduler_impl->tracing_controller_,
497                           TaskQueue::PriorityToString) {}
498 
499 MainThreadSchedulerImpl::MainThreadOnly::~MainThreadOnly() = default;
500 
AnyThread(MainThreadSchedulerImpl * main_thread_scheduler_impl)501 MainThreadSchedulerImpl::AnyThread::AnyThread(
502     MainThreadSchedulerImpl* main_thread_scheduler_impl)
503     : awaiting_touch_start_response(
504           false,
505           "Scheduler.AwaitingTouchstartResponse",
506           &main_thread_scheduler_impl->tracing_controller_,
507           YesNoStateToString),
508       in_idle_period(false,
509                      "Scheduler.InIdlePeriod",
510                      &main_thread_scheduler_impl->tracing_controller_,
511                      YesNoStateToString),
512       begin_main_frame_on_critical_path(
513           false,
514           "Scheduler.BeginMainFrameOnCriticalPath",
515           &main_thread_scheduler_impl->tracing_controller_,
516           YesNoStateToString),
517       last_gesture_was_compositor_driven(
518           false,
519           "Scheduler.LastGestureWasCompositorDriven",
520           &main_thread_scheduler_impl->tracing_controller_,
521           YesNoStateToString),
522       default_gesture_prevented(
523           true,
524           "Scheduler.DefaultGesturePrevented",
525           &main_thread_scheduler_impl->tracing_controller_,
526           YesNoStateToString),
527       have_seen_a_blocking_gesture(
528           false,
529           "Scheduler.HaveSeenBlockingGesture",
530           &main_thread_scheduler_impl->tracing_controller_,
531           YesNoStateToString),
532       waiting_for_any_main_frame_contentful_paint(
533           false,
534           "Scheduler.WaitingForMainFrameContentfulPaint",
535           &main_thread_scheduler_impl->tracing_controller_,
536           YesNoStateToString),
537       waiting_for_any_main_frame_meaningful_paint(
538           false,
539           "Scheduler.WaitingForMeaningfulPaint",
540           &main_thread_scheduler_impl->tracing_controller_,
541           YesNoStateToString),
542       have_seen_input_since_navigation(
543           false,
544           "Scheduler.HaveSeenInputSinceNavigation",
545           &main_thread_scheduler_impl->tracing_controller_,
546           YesNoStateToString),
547       begin_main_frame_scheduled_count(
548           0,
549           "Scheduler.BeginMainFrameScheduledCount",
550           &main_thread_scheduler_impl->tracing_controller_) {}
551 
SchedulingSettings()552 MainThreadSchedulerImpl::SchedulingSettings::SchedulingSettings() {
553   low_priority_background_page =
554       base::FeatureList::IsEnabled(kLowPriorityForBackgroundPages);
555   best_effort_background_page =
556       base::FeatureList::IsEnabled(kBestEffortPriorityForBackgroundPages);
557 
558   low_priority_hidden_frame =
559       base::FeatureList::IsEnabled(kLowPriorityForHiddenFrame);
560   low_priority_subframe = base::FeatureList::IsEnabled(kLowPriorityForSubFrame);
561   low_priority_throttleable =
562       base::FeatureList::IsEnabled(kLowPriorityForThrottleableTask);
563   low_priority_subframe_throttleable =
564       base::FeatureList::IsEnabled(kLowPriorityForSubFrameThrottleableTask);
565   use_frame_priorities_only_during_loading =
566       base::FeatureList::IsEnabled(kFrameExperimentOnlyWhenLoading);
567 
568   low_priority_ad_frame = base::FeatureList::IsEnabled(kLowPriorityForAdFrame);
569   best_effort_ad_frame =
570       base::FeatureList::IsEnabled(kBestEffortPriorityForAdFrame);
571   use_adframe_priorities_only_during_loading =
572       base::FeatureList::IsEnabled(kAdFrameExperimentOnlyWhenLoading);
573 
574   low_priority_cross_origin =
575       base::FeatureList::IsEnabled(kLowPriorityForCrossOrigin);
576   low_priority_cross_origin_only_during_loading =
577       base::FeatureList::IsEnabled(kLowPriorityForCrossOriginOnlyWhenLoading);
578 
579   use_resource_fetch_priority =
580       base::FeatureList::IsEnabled(kUseResourceFetchPriority);
581   use_resource_priorities_only_during_loading =
582       base::FeatureList::IsEnabled(kUseResourceFetchPriorityOnlyWhenLoading);
583 
584   prioritize_compositing_and_loading_during_early_loading =
585       base::FeatureList::IsEnabled(
586           kPrioritizeCompositingAndLoadingDuringEarlyLoading);
587 
588   prioritize_compositing_after_input =
589       base::FeatureList::IsEnabled(kPrioritizeCompositingAfterInput);
590 
591   if (use_resource_fetch_priority ||
592       use_resource_priorities_only_during_loading) {
593     base::FieldTrialParams params;
594     base::GetFieldTrialParams(kResourceFetchPriorityExperiment, &params);
595     for (size_t net_priority = 0;
596          net_priority < net::RequestPrioritySize::NUM_PRIORITIES;
597          net_priority++) {
598       net_to_blink_priority[net_priority] =
599           TaskQueue::QueuePriority::kNormalPriority;
600       auto iter = params.find(net::RequestPriorityToString(
601           static_cast<net::RequestPriority>(net_priority)));
602       if (iter != params.end()) {
603         net_to_blink_priority[net_priority] =
604             StringToTaskQueuePriority(iter->second);
605       }
606     }
607   }
608 }
609 
610 MainThreadSchedulerImpl::AnyThread::~AnyThread() = default;
611 
CompositorThreadOnly()612 MainThreadSchedulerImpl::CompositorThreadOnly::CompositorThreadOnly()
613     : last_input_type(blink::WebInputEvent::Type::kUndefined) {}
614 
615 MainThreadSchedulerImpl::CompositorThreadOnly::~CompositorThreadOnly() =
616     default;
617 
RendererPauseHandleImpl(MainThreadSchedulerImpl * scheduler)618 MainThreadSchedulerImpl::RendererPauseHandleImpl::RendererPauseHandleImpl(
619     MainThreadSchedulerImpl* scheduler)
620     : scheduler_(scheduler) {
621   scheduler_->PauseRendererImpl();
622 }
623 
~RendererPauseHandleImpl()624 MainThreadSchedulerImpl::RendererPauseHandleImpl::~RendererPauseHandleImpl() {
625   scheduler_->ResumeRendererImpl();
626 }
627 
ShutdownAllQueues()628 void MainThreadSchedulerImpl::ShutdownAllQueues() {
629   while (!task_runners_.empty()) {
630     scoped_refptr<MainThreadTaskQueue> queue = task_runners_.begin()->first;
631     queue->ShutdownTaskQueue();
632   }
633 
634   if (virtual_time_control_task_queue_)
635     virtual_time_control_task_queue_->ShutdownTaskQueue();
636 }
637 
IsAnyMainFrameWaitingForFirstMeaningfulPaint() const638 bool MainThreadSchedulerImpl::IsAnyMainFrameWaitingForFirstMeaningfulPaint()
639     const {
640   return std::any_of(
641       main_thread_only().page_schedulers.begin(),
642       main_thread_only().page_schedulers.end(),
643       std::mem_fn(&PageSchedulerImpl::IsWaitingForMainFrameMeaningfulPaint));
644 }
645 
IsAnyMainFrameWaitingForFirstContentfulPaint() const646 bool MainThreadSchedulerImpl::IsAnyMainFrameWaitingForFirstContentfulPaint()
647     const {
648   return std::any_of(
649       main_thread_only().page_schedulers.begin(),
650       main_thread_only().page_schedulers.end(),
651       std::mem_fn(&PageSchedulerImpl::IsWaitingForMainFrameContentfulPaint));
652 }
653 
Shutdown()654 void MainThreadSchedulerImpl::Shutdown() {
655   if (was_shutdown_)
656     return;
657 
658   base::TimeTicks now = tick_clock()->NowTicks();
659   main_thread_only().metrics_helper.OnRendererShutdown(now);
660   main_thread_only()
661       .compositor_priority_experiments.OnMainThreadSchedulerShutdown();
662 
663   ShutdownAllQueues();
664   task_queue_throttler_.reset();
665 
666   // Shut down |helper_| first, so that the ForceUpdatePolicy() call
667   // from |idle_helper_| early-outs and doesn't do anything.
668   helper_.Shutdown();
669   idle_helper_.Shutdown();
670   sequence_manager_.reset();
671   main_thread_only().rail_mode_observers.Clear();
672   was_shutdown_ = true;
673 }
674 
CreateMainThread()675 std::unique_ptr<Thread> MainThreadSchedulerImpl::CreateMainThread() {
676   return std::make_unique<MainThread>(this);
677 }
678 
679 std::unique_ptr<WebWidgetScheduler>
CreateWidgetScheduler()680 MainThreadSchedulerImpl::CreateWidgetScheduler() {
681   return std::make_unique<WidgetScheduler>(this);
682 }
683 
684 scoped_refptr<base::SingleThreadTaskRunner>
ControlTaskRunner()685 MainThreadSchedulerImpl::ControlTaskRunner() {
686   return control_task_runner_;
687 }
688 
689 scoped_refptr<base::SingleThreadTaskRunner>
DefaultTaskRunner()690 MainThreadSchedulerImpl::DefaultTaskRunner() {
691   return helper_.DefaultTaskRunner();
692 }
693 
694 scoped_refptr<SingleThreadIdleTaskRunner>
IdleTaskRunner()695 MainThreadSchedulerImpl::IdleTaskRunner() {
696   return idle_helper_.IdleTaskRunner();
697 }
698 
699 scoped_refptr<base::SingleThreadTaskRunner>
DeprecatedDefaultTaskRunner()700 MainThreadSchedulerImpl::DeprecatedDefaultTaskRunner() {
701   return helper_.DeprecatedDefaultTaskRunner();
702 }
703 
704 scoped_refptr<base::SingleThreadTaskRunner>
VirtualTimeControlTaskRunner()705 MainThreadSchedulerImpl::VirtualTimeControlTaskRunner() {
706   return virtual_time_control_task_queue_->GetTaskRunnerWithDefaultTaskType();
707 }
708 
709 scoped_refptr<MainThreadTaskQueue>
CompositorTaskQueue()710 MainThreadSchedulerImpl::CompositorTaskQueue() {
711   helper_.CheckOnValidThread();
712   return compositor_task_queue_;
713 }
714 
V8TaskQueue()715 scoped_refptr<MainThreadTaskQueue> MainThreadSchedulerImpl::V8TaskQueue() {
716   helper_.CheckOnValidThread();
717   return v8_task_queue_;
718 }
719 
ControlTaskQueue()720 scoped_refptr<MainThreadTaskQueue> MainThreadSchedulerImpl::ControlTaskQueue() {
721   return helper_.ControlMainThreadTaskQueue();
722 }
723 
DefaultTaskQueue()724 scoped_refptr<MainThreadTaskQueue> MainThreadSchedulerImpl::DefaultTaskQueue() {
725   return helper_.DefaultMainThreadTaskQueue();
726 }
727 
728 scoped_refptr<MainThreadTaskQueue>
VirtualTimeControlTaskQueue()729 MainThreadSchedulerImpl::VirtualTimeControlTaskQueue() {
730   helper_.CheckOnValidThread();
731   return virtual_time_control_task_queue_;
732 }
733 
NewTaskQueue(const MainThreadTaskQueue::QueueCreationParams & params)734 scoped_refptr<MainThreadTaskQueue> MainThreadSchedulerImpl::NewTaskQueue(
735     const MainThreadTaskQueue::QueueCreationParams& params) {
736   helper_.CheckOnValidThread();
737   scoped_refptr<MainThreadTaskQueue> task_queue(helper_.NewTaskQueue(params));
738 
739   std::unique_ptr<TaskQueue::QueueEnabledVoter> voter;
740   if (params.queue_traits.can_be_deferred ||
741       params.queue_traits.can_be_paused || params.queue_traits.can_be_frozen) {
742     voter = task_queue->GetTaskQueue()->CreateQueueEnabledVoter();
743   }
744 
745   auto insert_result = task_runners_.emplace(task_queue, std::move(voter));
746 
747   UpdateTaskQueueState(task_queue.get(), insert_result.first->second.get(),
748                        Policy(), main_thread_only().current_policy,
749                        /*should_update_priority=*/true);
750 
751   // If this is a timer queue, and virtual time is enabled and paused, it should
752   // be suspended by adding a fence to prevent immediate tasks from running when
753   // they're not supposed to.
754   if (main_thread_only().virtual_time_stopped &&
755       main_thread_only().use_virtual_time &&
756       !task_queue->CanRunWhenVirtualTimePaused()) {
757     task_queue->GetTaskQueue()->InsertFence(
758         TaskQueue::InsertFencePosition::kNow);
759   }
760 
761   return task_queue;
762 }
763 
IsIpcTrackingEnabledForAllPages()764 bool MainThreadSchedulerImpl::IsIpcTrackingEnabledForAllPages() {
765   for (auto* scheduler : main_thread_only().page_schedulers) {
766     if (!(scheduler->IsInBackForwardCache() &&
767           scheduler->has_ipc_detection_enabled())) {
768       return false;
769     }
770   }
771   return true;
772 }
773 
UpdateIpcTracking()774 void MainThreadSchedulerImpl::UpdateIpcTracking() {
775   bool should_track = IsIpcTrackingEnabledForAllPages();
776   if (should_track == has_ipc_callback_set_)
777     return;
778 
779   has_ipc_callback_set_ = should_track;
780   if (has_ipc_callback_set_) {
781     SetOnIPCTaskPostedWhileInBackForwardCacheIfNeeded();
782   } else {
783     DetachOnIPCTaskPostedWhileInBackForwardCacheHandler();
784   }
785 }
786 
787 void MainThreadSchedulerImpl::
SetOnIPCTaskPostedWhileInBackForwardCacheIfNeeded()788     SetOnIPCTaskPostedWhileInBackForwardCacheIfNeeded() {
789   has_ipc_callback_set_ = true;
790   helper_.DefaultMainThreadTaskQueue()->SetOnIPCTaskPosted(base::BindRepeating(
791       [](scoped_refptr<base::SingleThreadTaskRunner> task_runner,
792          base::WeakPtr<MainThreadSchedulerImpl> main_thread_scheduler,
793          const base::sequence_manager::Task& task) {
794         // Only log IPC tasks. IPC tasks are only logged currently as IPC
795         // hash can be mapped back to a function name, and IPC tasks may
796         // potentially post sensitive information.
797         if (!task.ipc_hash && !task.ipc_interface_name) {
798           return;
799         }
800         base::ScopedDeferTaskPosting::PostOrDefer(
801             task_runner, FROM_HERE,
802             base::BindOnce(&MainThreadSchedulerImpl::
803                                OnIPCTaskPostedWhileInAllPagesBackForwardCache,
804                            main_thread_scheduler, task.ipc_hash,
805                            task.ipc_interface_name),
806             base::TimeDelta());
807       },
808       back_forward_cache_ipc_tracking_task_runner_, GetWeakPtr()));
809 }
810 
OnIPCTaskPostedWhileInAllPagesBackForwardCache(uint32_t ipc_hash,const char * ipc_interface_name)811 void MainThreadSchedulerImpl::OnIPCTaskPostedWhileInAllPagesBackForwardCache(
812     uint32_t ipc_hash,
813     const char* ipc_interface_name) {
814   // As this is a multi-threaded environment, we need to check that all page
815   // schedulers are in the cache before logging. There may be instances where
816   // the scheduler has been unfrozen prior to the IPC tracking handler being
817   // reset.
818   if (!IsIpcTrackingEnabledForAllPages()) {
819     return;
820   }
821 
822   // IPC tasks may have an IPC interface name in addition to, or instead of an
823   // IPC hash. IPC hash is known from the mojo Accept method. When IPC hash is
824   // 0, then the IPC hash must be calculated form the IPC interface name
825   // instead.
826   if (!ipc_hash) {
827     // base::HashMetricName produces a uint64; however, the MD5 hash calculation
828     // for an IPC interface name is always calculated as uint32; the IPC hash on
829     // a task is also a uint32. The calculation here is meant to mimic the
830     // calculation used in base::MD5Hash32Constexpr.
831     ipc_hash = static_cast<uint32_t>(
832         base::TaskAnnotator::ScopedSetIpcHash::MD5HashMetricName(
833             ipc_interface_name));
834   }
835 
836   base::UmaHistogramSparse(
837       "BackForwardCache.Experimental.UnexpectedIPCMessagePostedToCachedFrame."
838       "MethodHash",
839       static_cast<int32_t>(ipc_hash));
840 }
841 
842 void MainThreadSchedulerImpl::
DetachOnIPCTaskPostedWhileInBackForwardCacheHandler()843     DetachOnIPCTaskPostedWhileInBackForwardCacheHandler() {
844   has_ipc_callback_set_ = false;
845   helper_.DefaultMainThreadTaskQueue()
846       ->DetachOnIPCTaskPostedWhileInBackForwardCache();
847 }
848 
849 // TODO(sreejakshetty): Cleanup NewLoadingTaskQueue.
NewLoadingTaskQueue(MainThreadTaskQueue::QueueType queue_type,FrameSchedulerImpl * frame_scheduler)850 scoped_refptr<MainThreadTaskQueue> MainThreadSchedulerImpl::NewLoadingTaskQueue(
851     MainThreadTaskQueue::QueueType queue_type,
852     FrameSchedulerImpl* frame_scheduler) {
853   DCHECK(queue_type == MainThreadTaskQueue::QueueType::kFrameLoading ||
854          queue_type == MainThreadTaskQueue::QueueType::kFrameLoadingControl);
855   return NewTaskQueue(MainThreadTaskQueue::QueueCreationParams(queue_type)
856                           .SetCanBePaused(true)
857                           .SetCanBeFrozen(true)
858                           .SetCanBeDeferred(true)
859                           .SetFrameScheduler(frame_scheduler));
860 }
861 
862 scoped_refptr<MainThreadTaskQueue>
NewThrottleableTaskQueueForTest(FrameSchedulerImpl * frame_scheduler)863 MainThreadSchedulerImpl::NewThrottleableTaskQueueForTest(
864     FrameSchedulerImpl* frame_scheduler) {
865   return NewTaskQueue(MainThreadTaskQueue::QueueCreationParams(
866                           MainThreadTaskQueue::QueueType::kFrameThrottleable)
867                           .SetCanBePaused(true)
868                           .SetCanBeFrozen(true)
869                           .SetCanBeDeferred(true)
870                           .SetCanBeThrottled(true)
871                           .SetFrameScheduler(frame_scheduler)
872                           .SetCanRunWhenVirtualTimePaused(false));
873 }
874 
875 scoped_refptr<base::sequence_manager::TaskQueue>
NewTaskQueueForTest()876 MainThreadSchedulerImpl::NewTaskQueueForTest() {
877   return sequence_manager_->CreateTaskQueue(
878       base::sequence_manager::TaskQueue::Spec("test"));
879 }
880 
881 std::unique_ptr<WebRenderWidgetSchedulingState>
NewRenderWidgetSchedulingState()882 MainThreadSchedulerImpl::NewRenderWidgetSchedulingState() {
883   return render_widget_scheduler_signals_.NewRenderWidgetSchedulingState();
884 }
885 
OnShutdownTaskQueue(const scoped_refptr<MainThreadTaskQueue> & task_queue)886 void MainThreadSchedulerImpl::OnShutdownTaskQueue(
887     const scoped_refptr<MainThreadTaskQueue>& task_queue) {
888   if (was_shutdown_)
889     return;
890 
891   if (task_queue_throttler_)
892     task_queue_throttler_->ShutdownTaskQueue(task_queue->GetTaskQueue());
893 
894   task_queue.get()->DetachOnIPCTaskPostedWhileInBackForwardCache();
895   task_runners_.erase(task_queue.get());
896 }
897 
CanExceedIdleDeadlineIfRequired() const898 bool MainThreadSchedulerImpl::CanExceedIdleDeadlineIfRequired() const {
899   return idle_helper_.CanExceedIdleDeadlineIfRequired();
900 }
901 
AddTaskObserver(base::TaskObserver * task_observer)902 void MainThreadSchedulerImpl::AddTaskObserver(
903     base::TaskObserver* task_observer) {
904   helper_.AddTaskObserver(task_observer);
905 }
906 
RemoveTaskObserver(base::TaskObserver * task_observer)907 void MainThreadSchedulerImpl::RemoveTaskObserver(
908     base::TaskObserver* task_observer) {
909   helper_.RemoveTaskObserver(task_observer);
910 }
911 
WillBeginFrame(const viz::BeginFrameArgs & args)912 void MainThreadSchedulerImpl::WillBeginFrame(const viz::BeginFrameArgs& args) {
913   // TODO(crbug/1068426): Figure out when and if |UpdatePolicy| should be called
914   //  and, if needed, remove the call to it from
915   //  |SetPrioritizeCompositingAfterInput|.
916   TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
917                "MainThreadSchedulerImpl::WillBeginFrame", "args",
918                args.AsValue());
919   helper_.CheckOnValidThread();
920   if (helper_.IsShutdown())
921     return;
922 
923   EndIdlePeriod();
924   main_thread_only().estimated_next_frame_begin =
925       args.frame_time + args.interval;
926   main_thread_only().compositor_frame_interval = args.interval;
927   {
928     base::AutoLock lock(any_thread_lock_);
929     any_thread().begin_main_frame_on_critical_path = args.on_critical_path;
930   }
931   SetPrioritizeCompositingAfterInput(false);
932   main_thread_only().compositor_priority_experiments.OnWillBeginMainFrame();
933 }
934 
DidCommitFrameToCompositor()935 void MainThreadSchedulerImpl::DidCommitFrameToCompositor() {
936   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
937                "MainThreadSchedulerImpl::DidCommitFrameToCompositor");
938   helper_.CheckOnValidThread();
939   if (helper_.IsShutdown())
940     return;
941 
942   base::TimeTicks now(helper_.NowTicks());
943   if (now < main_thread_only().estimated_next_frame_begin) {
944     // TODO(rmcilroy): Consider reducing the idle period based on the runtime of
945     // the next pending delayed tasks (as currently done in for long idle times)
946     idle_helper_.StartIdlePeriod(
947         IdleHelper::IdlePeriodState::kInShortIdlePeriod, now,
948         main_thread_only().estimated_next_frame_begin);
949   }
950 
951   main_thread_only().idle_time_estimator.DidCommitFrameToCompositor();
952 }
953 
BeginFrameNotExpectedSoon()954 void MainThreadSchedulerImpl::BeginFrameNotExpectedSoon() {
955   // TODO(crbug/1068426): Should this call |UpdatePolicy|?
956   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
957                "MainThreadSchedulerImpl::BeginFrameNotExpectedSoon");
958   helper_.CheckOnValidThread();
959   if (helper_.IsShutdown())
960     return;
961 
962   idle_helper_.EnableLongIdlePeriod();
963   {
964     base::AutoLock lock(any_thread_lock_);
965     any_thread().begin_main_frame_on_critical_path = false;
966   }
967 }
968 
BeginMainFrameNotExpectedUntil(base::TimeTicks time)969 void MainThreadSchedulerImpl::BeginMainFrameNotExpectedUntil(
970     base::TimeTicks time) {
971   helper_.CheckOnValidThread();
972   if (helper_.IsShutdown())
973     return;
974 
975   base::TimeTicks now(helper_.NowTicks());
976   TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
977                "MainThreadSchedulerImpl::BeginMainFrameNotExpectedUntil",
978                "time_remaining", (time - now).InMillisecondsF());
979 
980   if (now < time) {
981     // End any previous idle period.
982     EndIdlePeriod();
983 
984     // TODO(rmcilroy): Consider reducing the idle period based on the runtime of
985     // the next pending delayed tasks (as currently done in for long idle times)
986     idle_helper_.StartIdlePeriod(
987         IdleHelper::IdlePeriodState::kInShortIdlePeriod, now, time);
988   }
989 }
990 
SetAllRenderWidgetsHidden(bool hidden)991 void MainThreadSchedulerImpl::SetAllRenderWidgetsHidden(bool hidden) {
992   TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
993                "MainThreadSchedulerImpl::SetAllRenderWidgetsHidden", "hidden",
994                hidden);
995 
996   helper_.CheckOnValidThread();
997 
998   if (helper_.IsShutdown() || main_thread_only().renderer_hidden == hidden)
999     return;
1000 
1001   end_renderer_hidden_idle_period_closure_.Cancel();
1002 
1003   if (hidden) {
1004     idle_helper_.EnableLongIdlePeriod();
1005 
1006     // Ensure that we stop running idle tasks after a few seconds of being
1007     // hidden.
1008     base::TimeDelta end_idle_when_hidden_delay =
1009         base::TimeDelta::FromMilliseconds(kEndIdleWhenHiddenDelayMillis);
1010     control_task_queue_->GetTaskRunnerWithDefaultTaskType()->PostDelayedTask(
1011         FROM_HERE, end_renderer_hidden_idle_period_closure_.GetCallback(),
1012         end_idle_when_hidden_delay);
1013     main_thread_only().renderer_hidden = true;
1014   } else {
1015     main_thread_only().renderer_hidden = false;
1016     EndIdlePeriod();
1017   }
1018 
1019   // TODO(alexclarke): Should we update policy here?
1020   CreateTraceEventObjectSnapshot();
1021 }
1022 
SetHasVisibleRenderWidgetWithTouchHandler(bool has_visible_render_widget_with_touch_handler)1023 void MainThreadSchedulerImpl::SetHasVisibleRenderWidgetWithTouchHandler(
1024     bool has_visible_render_widget_with_touch_handler) {
1025   helper_.CheckOnValidThread();
1026   if (has_visible_render_widget_with_touch_handler ==
1027       main_thread_only().has_visible_render_widget_with_touch_handler)
1028     return;
1029 
1030   main_thread_only().has_visible_render_widget_with_touch_handler =
1031       has_visible_render_widget_with_touch_handler;
1032 
1033   base::AutoLock lock(any_thread_lock_);
1034   UpdatePolicyLocked(UpdateType::kForceUpdate);
1035 }
1036 
SetRendererHidden(bool hidden)1037 void MainThreadSchedulerImpl::SetRendererHidden(bool hidden) {
1038   if (hidden) {
1039     TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
1040                  "MainThreadSchedulerImpl::OnRendererHidden");
1041     main_thread_only().renderer_hidden_metadata.emplace(
1042         "MainThreadSchedulerImpl.RendererHidden", /* is_hidden */ 1);
1043   } else {
1044     TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
1045                  "MainThreadSchedulerImpl::OnRendererVisible");
1046     main_thread_only().renderer_hidden_metadata.reset();
1047   }
1048   helper_.CheckOnValidThread();
1049   main_thread_only().renderer_hidden = hidden;
1050 }
1051 
SetRendererBackgrounded(bool backgrounded)1052 void MainThreadSchedulerImpl::SetRendererBackgrounded(bool backgrounded) {
1053   helper_.CheckOnValidThread();
1054 
1055   // Increasing timer slack helps the OS to coalesce timers efficiently.
1056   base::TimerSlack timer_slack = base::TIMER_SLACK_NONE;
1057   if (backgrounded)
1058     timer_slack = base::TIMER_SLACK_MAXIMUM;
1059   helper_.SetTimerSlack(timer_slack);
1060 
1061   if (helper_.IsShutdown() ||
1062       main_thread_only().renderer_backgrounded == backgrounded)
1063     return;
1064   if (backgrounded) {
1065     TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
1066                  "MainThreadSchedulerImpl::OnRendererBackgrounded");
1067   } else {
1068     TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
1069                  "MainThreadSchedulerImpl::OnRendererForegrounded");
1070   }
1071 
1072   main_thread_only().renderer_backgrounded = backgrounded;
1073   internal::ProcessState::Get()->is_process_backgrounded = backgrounded;
1074 
1075   main_thread_only().background_status_changed_at = tick_clock()->NowTicks();
1076 
1077   UpdatePolicy();
1078 
1079   base::TimeTicks now = tick_clock()->NowTicks();
1080   if (backgrounded) {
1081     main_thread_only().metrics_helper.OnRendererBackgrounded(now);
1082   } else {
1083     main_thread_only().metrics_helper.OnRendererForegrounded(now);
1084   }
1085 
1086   ParkableStringManager::Instance().SetRendererBackgrounded(backgrounded);
1087   memory_purge_manager_.SetRendererBackgrounded(backgrounded);
1088 }
1089 
SetSchedulerKeepActive(bool keep_active)1090 void MainThreadSchedulerImpl::SetSchedulerKeepActive(bool keep_active) {
1091   main_thread_only().keep_active_fetch_or_worker = keep_active;
1092   for (PageSchedulerImpl* page_scheduler : main_thread_only().page_schedulers) {
1093     page_scheduler->SetKeepActive(keep_active);
1094   }
1095 }
1096 
OnMainFrameRequestedForInput()1097 void MainThreadSchedulerImpl::OnMainFrameRequestedForInput() {
1098   SetPrioritizeCompositingAfterInput(
1099       scheduling_settings().prioritize_compositing_after_input);
1100 }
1101 
SchedulerKeepActive()1102 bool MainThreadSchedulerImpl::SchedulerKeepActive() {
1103   return main_thread_only().keep_active_fetch_or_worker;
1104 }
1105 
1106 #if defined(OS_ANDROID)
PauseTimersForAndroidWebView()1107 void MainThreadSchedulerImpl::PauseTimersForAndroidWebView() {
1108   main_thread_only().pause_timers_for_webview = true;
1109   UpdatePolicy();
1110 }
1111 
ResumeTimersForAndroidWebView()1112 void MainThreadSchedulerImpl::ResumeTimersForAndroidWebView() {
1113   main_thread_only().pause_timers_for_webview = false;
1114   UpdatePolicy();
1115 }
1116 #endif
1117 
OnAudioStateChanged()1118 void MainThreadSchedulerImpl::OnAudioStateChanged() {
1119   bool is_audio_playing = false;
1120   for (PageSchedulerImpl* page_scheduler : main_thread_only().page_schedulers) {
1121     is_audio_playing = is_audio_playing || page_scheduler->IsAudioPlaying();
1122   }
1123 
1124   if (is_audio_playing == main_thread_only().is_audio_playing)
1125     return;
1126 
1127   main_thread_only().is_audio_playing = is_audio_playing;
1128 }
1129 
1130 std::unique_ptr<ThreadScheduler::RendererPauseHandle>
PauseRenderer()1131 MainThreadSchedulerImpl::PauseRenderer() {
1132   return std::make_unique<RendererPauseHandleImpl>(this);
1133 }
1134 
PauseRendererImpl()1135 void MainThreadSchedulerImpl::PauseRendererImpl() {
1136   helper_.CheckOnValidThread();
1137   if (helper_.IsShutdown())
1138     return;
1139 
1140   ++main_thread_only().renderer_pause_count;
1141   UpdatePolicy();
1142 }
1143 
ResumeRendererImpl()1144 void MainThreadSchedulerImpl::ResumeRendererImpl() {
1145   helper_.CheckOnValidThread();
1146   if (helper_.IsShutdown())
1147     return;
1148   --main_thread_only().renderer_pause_count;
1149   DCHECK_GE(main_thread_only().renderer_pause_count.value(), 0);
1150   UpdatePolicy();
1151 }
1152 
EndIdlePeriod()1153 void MainThreadSchedulerImpl::EndIdlePeriod() {
1154   if (main_thread_only().in_idle_period_for_testing)
1155     return;
1156   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
1157                "MainThreadSchedulerImpl::EndIdlePeriod");
1158   helper_.CheckOnValidThread();
1159   idle_helper_.EndIdlePeriod();
1160 }
1161 
EndIdlePeriodForTesting(base::OnceClosure callback,base::TimeTicks time_remaining)1162 void MainThreadSchedulerImpl::EndIdlePeriodForTesting(
1163     base::OnceClosure callback,
1164     base::TimeTicks time_remaining) {
1165   main_thread_only().in_idle_period_for_testing = false;
1166   EndIdlePeriod();
1167   std::move(callback).Run();
1168 }
1169 
PolicyNeedsUpdateForTesting()1170 bool MainThreadSchedulerImpl::PolicyNeedsUpdateForTesting() {
1171   return policy_may_need_update_.IsSet();
1172 }
1173 
SetHaveSeenABlockingGestureForTesting(bool status)1174 void MainThreadSchedulerImpl::SetHaveSeenABlockingGestureForTesting(
1175     bool status) {
1176   base::AutoLock lock(any_thread_lock_);
1177   any_thread().have_seen_a_blocking_gesture = status;
1178 }
1179 
PerformMicrotaskCheckpoint()1180 void MainThreadSchedulerImpl::PerformMicrotaskCheckpoint() {
1181   if (isolate())
1182     EventLoop::PerformIsolateGlobalMicrotasksCheckpoint(isolate());
1183 }
1184 
1185 // static
ShouldPrioritizeInputEvent(const blink::WebInputEvent & web_input_event)1186 bool MainThreadSchedulerImpl::ShouldPrioritizeInputEvent(
1187     const blink::WebInputEvent& web_input_event) {
1188   // We regard MouseMove events with the left mouse button down as a signal
1189   // that the user is doing something requiring a smooth frame rate.
1190   if ((web_input_event.GetType() == blink::WebInputEvent::Type::kMouseDown ||
1191        web_input_event.GetType() == blink::WebInputEvent::Type::kMouseMove) &&
1192       (web_input_event.GetModifiers() &
1193        blink::WebInputEvent::kLeftButtonDown)) {
1194     return true;
1195   }
1196   // Ignore all other mouse events because they probably don't signal user
1197   // interaction needing a smooth framerate. NOTE isMouseEventType returns false
1198   // for mouse wheel events, hence we regard them as user input.
1199   // Ignore keyboard events because it doesn't really make sense to enter
1200   // compositor priority for them.
1201   if (blink::WebInputEvent::IsMouseEventType(web_input_event.GetType()) ||
1202       blink::WebInputEvent::IsKeyboardEventType(web_input_event.GetType())) {
1203     return false;
1204   }
1205   return true;
1206 }
1207 
DidHandleInputEventOnCompositorThread(const blink::WebInputEvent & web_input_event,InputEventState event_state)1208 void MainThreadSchedulerImpl::DidHandleInputEventOnCompositorThread(
1209     const blink::WebInputEvent& web_input_event,
1210     InputEventState event_state) {
1211   TRACE_EVENT0(
1212       TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
1213       "MainThreadSchedulerImpl::DidHandleInputEventOnCompositorThread");
1214   if (!ShouldPrioritizeInputEvent(web_input_event))
1215     return;
1216 
1217   UpdateForInputEventOnCompositorThread(web_input_event, event_state);
1218 }
1219 
DidAnimateForInputOnCompositorThread()1220 void MainThreadSchedulerImpl::DidAnimateForInputOnCompositorThread() {
1221   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
1222                "MainThreadSchedulerImpl::DidAnimateForInputOnCompositorThread");
1223   base::AutoLock lock(any_thread_lock_);
1224   any_thread().fling_compositor_escalation_deadline =
1225       helper_.NowTicks() +
1226       base::TimeDelta::FromMilliseconds(kFlingEscalationLimitMillis);
1227 }
1228 
DidScheduleBeginMainFrame()1229 void MainThreadSchedulerImpl::DidScheduleBeginMainFrame() {
1230   base::AutoLock lock(any_thread_lock_);
1231   any_thread().begin_main_frame_scheduled_count += 1;
1232 }
1233 
DidRunBeginMainFrame()1234 void MainThreadSchedulerImpl::DidRunBeginMainFrame() {
1235   base::AutoLock lock(any_thread_lock_);
1236   any_thread().begin_main_frame_scheduled_count -= 1;
1237 }
1238 
UpdateForInputEventOnCompositorThread(const blink::WebInputEvent & web_input_event,InputEventState input_event_state)1239 void MainThreadSchedulerImpl::UpdateForInputEventOnCompositorThread(
1240     const blink::WebInputEvent& web_input_event,
1241     InputEventState input_event_state) {
1242   base::AutoLock lock(any_thread_lock_);
1243   base::TimeTicks now = helper_.NowTicks();
1244 
1245   blink::WebInputEvent::Type type = web_input_event.GetType();
1246 
1247   // TODO(alexclarke): Move WebInputEventTraits where we can access it from here
1248   // and record the name rather than the integer representation.
1249   TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
1250                "MainThreadSchedulerImpl::UpdateForInputEventOnCompositorThread",
1251                "type", static_cast<int>(type), "input_event_state",
1252                InputEventStateToString(input_event_state));
1253 
1254   base::TimeDelta unused_policy_duration;
1255   UseCase previous_use_case =
1256       ComputeCurrentUseCase(now, &unused_policy_duration);
1257   bool was_awaiting_touch_start_response =
1258       any_thread().awaiting_touch_start_response;
1259 
1260   any_thread().user_model.DidStartProcessingInputEvent(type, now);
1261   any_thread().have_seen_input_since_navigation = true;
1262 
1263   if (input_event_state == InputEventState::EVENT_CONSUMED_BY_COMPOSITOR)
1264     any_thread().user_model.DidFinishProcessingInputEvent(now);
1265 
1266   switch (type) {
1267     case blink::WebInputEvent::Type::kTouchStart:
1268       any_thread().awaiting_touch_start_response = true;
1269       // This is just a fail-safe to reset the state of
1270       // |last_gesture_was_compositor_driven| to the default. We don't know
1271       // yet where the gesture will run.
1272       any_thread().last_gesture_was_compositor_driven = false;
1273       // Assume the default gesture is prevented until we see evidence
1274       // otherwise.
1275       any_thread().default_gesture_prevented = true;
1276 
1277       if (IsBlockingEvent(web_input_event))
1278         any_thread().have_seen_a_blocking_gesture = true;
1279       break;
1280     case blink::WebInputEvent::Type::kTouchMove:
1281       // Observation of consecutive touchmoves is a strong signal that the
1282       // page is consuming the touch sequence, in which case touchstart
1283       // response prioritization is no longer necessary. Otherwise, the
1284       // initial touchmove should preserve the touchstart response pending
1285       // state.
1286       if (any_thread().awaiting_touch_start_response &&
1287           GetCompositorThreadOnly().last_input_type ==
1288               blink::WebInputEvent::Type::kTouchMove) {
1289         any_thread().awaiting_touch_start_response = false;
1290       }
1291       break;
1292 
1293     case blink::WebInputEvent::Type::kGesturePinchUpdate:
1294     case blink::WebInputEvent::Type::kGestureScrollUpdate:
1295       // If we see events for an established gesture, we can lock it to the
1296       // appropriate thread as the gesture can no longer be cancelled.
1297       any_thread().last_gesture_was_compositor_driven =
1298           input_event_state == InputEventState::EVENT_CONSUMED_BY_COMPOSITOR;
1299       any_thread().awaiting_touch_start_response = false;
1300       any_thread().default_gesture_prevented = false;
1301       break;
1302 
1303     case blink::WebInputEvent::Type::kGestureFlingCancel:
1304       any_thread().fling_compositor_escalation_deadline = base::TimeTicks();
1305       break;
1306 
1307     case blink::WebInputEvent::Type::kGestureTapDown:
1308     case blink::WebInputEvent::Type::kGestureShowPress:
1309     case blink::WebInputEvent::Type::kGestureScrollEnd:
1310       // With no observable effect, these meta events do not indicate a
1311       // meaningful touchstart response and should not impact task priority.
1312       break;
1313 
1314     case blink::WebInputEvent::Type::kMouseDown:
1315       // Reset tracking state at the start of a new mouse drag gesture.
1316       any_thread().last_gesture_was_compositor_driven = false;
1317       any_thread().default_gesture_prevented = true;
1318       break;
1319 
1320     case blink::WebInputEvent::Type::kMouseMove:
1321       // Consider mouse movement with the left button held down (see
1322       // ShouldPrioritizeInputEvent) similarly to a touch gesture.
1323       any_thread().last_gesture_was_compositor_driven =
1324           input_event_state == InputEventState::EVENT_CONSUMED_BY_COMPOSITOR;
1325       any_thread().awaiting_touch_start_response = false;
1326       break;
1327 
1328     case blink::WebInputEvent::Type::kMouseWheel:
1329       any_thread().last_gesture_was_compositor_driven =
1330           input_event_state == InputEventState::EVENT_CONSUMED_BY_COMPOSITOR;
1331       any_thread().awaiting_touch_start_response = false;
1332       // If the event was sent to the main thread, assume the default gesture is
1333       // prevented until we see evidence otherwise.
1334       any_thread().default_gesture_prevented =
1335           !any_thread().last_gesture_was_compositor_driven;
1336       if (IsBlockingEvent(web_input_event))
1337         any_thread().have_seen_a_blocking_gesture = true;
1338       break;
1339     case blink::WebInputEvent::Type::kUndefined:
1340       break;
1341 
1342     default:
1343       any_thread().awaiting_touch_start_response = false;
1344       break;
1345   }
1346 
1347   // Make sure the per-agent scheduling strategy is notified that there was an
1348   // input event.
1349   if (type != WebInputEvent::Type::kMouseMove &&
1350       !notify_agent_strategy_task_posted_.IsSet() &&
1351       agent_scheduling_strategy_->ShouldNotifyOnInputEvent()) {
1352     notify_agent_strategy_task_posted_.SetWhileLocked(true);
1353     control_task_queue_->GetTaskRunnerWithDefaultTaskType()->PostTask(
1354         FROM_HERE, notify_agent_strategy_on_input_event_closure_);
1355   }
1356 
1357   // Avoid unnecessary policy updates if the use case did not change.
1358   UseCase use_case = ComputeCurrentUseCase(now, &unused_policy_duration);
1359 
1360   if (use_case != previous_use_case ||
1361       was_awaiting_touch_start_response !=
1362           any_thread().awaiting_touch_start_response) {
1363     EnsureUrgentPolicyUpdatePostedOnMainThread(FROM_HERE);
1364   }
1365   GetCompositorThreadOnly().last_input_type = type;
1366 }
1367 
NotifyAgentSchedulerOnInputEvent()1368 void MainThreadSchedulerImpl::NotifyAgentSchedulerOnInputEvent() {
1369   helper_.CheckOnValidThread();
1370 
1371   if (agent_scheduling_strategy_->OnInputEvent() ==
1372           AgentSchedulingStrategy::ShouldUpdatePolicy::kYes &&
1373       !policy_may_need_update_.IsSet()) {
1374     OnAgentStrategyUpdated();
1375   }
1376 
1377   base::AutoLock lock(any_thread_lock_);
1378   notify_agent_strategy_task_posted_.SetWhileLocked(false);
1379 }
1380 
WillPostInputEventToMainThread(WebInputEvent::Type web_input_event_type,const WebInputEventAttribution & web_input_event_attribution)1381 void MainThreadSchedulerImpl::WillPostInputEventToMainThread(
1382     WebInputEvent::Type web_input_event_type,
1383     const WebInputEventAttribution& web_input_event_attribution) {
1384   base::AutoLock lock(any_thread_lock_);
1385   any_thread().pending_input_monitor.OnEnqueue(web_input_event_type,
1386                                                web_input_event_attribution);
1387 }
1388 
WillHandleInputEventOnMainThread(WebInputEvent::Type web_input_event_type,const WebInputEventAttribution & web_input_event_attribution)1389 void MainThreadSchedulerImpl::WillHandleInputEventOnMainThread(
1390     WebInputEvent::Type web_input_event_type,
1391     const WebInputEventAttribution& web_input_event_attribution) {
1392   helper_.CheckOnValidThread();
1393 
1394   base::AutoLock lock(any_thread_lock_);
1395   any_thread().pending_input_monitor.OnDequeue(web_input_event_type,
1396                                                web_input_event_attribution);
1397 }
1398 
DidHandleInputEventOnMainThread(const WebInputEvent & web_input_event,WebInputEventResult result)1399 void MainThreadSchedulerImpl::DidHandleInputEventOnMainThread(
1400     const WebInputEvent& web_input_event,
1401     WebInputEventResult result) {
1402   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
1403                "MainThreadSchedulerImpl::DidHandleInputEventOnMainThread");
1404   helper_.CheckOnValidThread();
1405   if (ShouldPrioritizeInputEvent(web_input_event)) {
1406     base::AutoLock lock(any_thread_lock_);
1407     any_thread().user_model.DidFinishProcessingInputEvent(helper_.NowTicks());
1408 
1409     // If we were waiting for a touchstart response and the main thread has
1410     // prevented the default gesture, consider the gesture established. This
1411     // ensures single-event gestures such as button presses are promptly
1412     // detected.
1413     if (any_thread().awaiting_touch_start_response &&
1414         result == WebInputEventResult::kHandledApplication) {
1415       any_thread().awaiting_touch_start_response = false;
1416       any_thread().default_gesture_prevented = true;
1417       UpdatePolicyLocked(UpdateType::kMayEarlyOutIfPolicyUnchanged);
1418     }
1419   }
1420 }
1421 
IsHighPriorityWorkAnticipated()1422 bool MainThreadSchedulerImpl::IsHighPriorityWorkAnticipated() {
1423   helper_.CheckOnValidThread();
1424   if (helper_.IsShutdown())
1425     return false;
1426 
1427   MaybeUpdatePolicy();
1428   // The touchstart, synchronized gesture and main-thread gesture use cases
1429   // indicate a strong likelihood of high-priority work in the near future.
1430   UseCase use_case = main_thread_only().current_use_case;
1431   return main_thread_only().blocking_input_expected_soon ||
1432          use_case == UseCase::kTouchstart ||
1433          use_case == UseCase::kMainThreadGesture ||
1434          use_case == UseCase::kMainThreadCustomInputHandling ||
1435          use_case == UseCase::kSynchronizedGesture;
1436 }
1437 
ShouldYieldForHighPriorityWork()1438 bool MainThreadSchedulerImpl::ShouldYieldForHighPriorityWork() {
1439   helper_.CheckOnValidThread();
1440   if (helper_.IsShutdown())
1441     return false;
1442 
1443   MaybeUpdatePolicy();
1444   // We only yield if there's a urgent task to be run now, or we are expecting
1445   // one soon (touch start).
1446   // Note: even though the control queue has the highest priority we don't yield
1447   // for it since these tasks are not user-provided work and they are only
1448   // intended to run before the next task, not interrupt the tasks.
1449   switch (main_thread_only().current_use_case) {
1450     case UseCase::kCompositorGesture:
1451     case UseCase::kNone:
1452       return main_thread_only().blocking_input_expected_soon;
1453 
1454     case UseCase::kMainThreadGesture:
1455     case UseCase::kMainThreadCustomInputHandling:
1456     case UseCase::kSynchronizedGesture:
1457       return compositor_task_queue_->GetTaskQueue()
1458                  ->HasTaskToRunImmediately() ||
1459              main_thread_only().blocking_input_expected_soon;
1460 
1461     case UseCase::kTouchstart:
1462       return true;
1463 
1464     case UseCase::kEarlyLoading:
1465     case UseCase::kLoading:
1466       return false;
1467 
1468     default:
1469       NOTREACHED();
1470       return false;
1471   }
1472 }
1473 
CurrentIdleTaskDeadlineForTesting() const1474 base::TimeTicks MainThreadSchedulerImpl::CurrentIdleTaskDeadlineForTesting()
1475     const {
1476   return idle_helper_.CurrentIdleTaskDeadline();
1477 }
1478 
RunIdleTasksForTesting(base::OnceClosure callback)1479 void MainThreadSchedulerImpl::RunIdleTasksForTesting(
1480     base::OnceClosure callback) {
1481   main_thread_only().in_idle_period_for_testing = true;
1482   IdleTaskRunner()->PostIdleTask(
1483       FROM_HERE,
1484       base::BindOnce(&MainThreadSchedulerImpl::EndIdlePeriodForTesting,
1485                      weak_factory_.GetWeakPtr(), std::move(callback)));
1486   idle_helper_.EnableLongIdlePeriod();
1487 }
1488 
MaybeUpdatePolicy()1489 void MainThreadSchedulerImpl::MaybeUpdatePolicy() {
1490   helper_.CheckOnValidThread();
1491   if (policy_may_need_update_.IsSet()) {
1492     UpdatePolicy();
1493   }
1494 }
1495 
EnsureUrgentPolicyUpdatePostedOnMainThread(const base::Location & from_here)1496 void MainThreadSchedulerImpl::EnsureUrgentPolicyUpdatePostedOnMainThread(
1497     const base::Location& from_here) {
1498   // TODO(scheduler-dev): Check that this method isn't called from the main
1499   // thread.
1500   any_thread_lock_.AssertAcquired();
1501   if (!policy_may_need_update_.IsSet()) {
1502     policy_may_need_update_.SetWhileLocked(true);
1503     control_task_queue_->GetTaskRunnerWithDefaultTaskType()->PostTask(
1504         from_here, update_policy_closure_);
1505   }
1506 }
1507 
UpdatePolicy()1508 void MainThreadSchedulerImpl::UpdatePolicy() {
1509   base::AutoLock lock(any_thread_lock_);
1510   UpdatePolicyLocked(UpdateType::kMayEarlyOutIfPolicyUnchanged);
1511 }
1512 
ForceUpdatePolicy()1513 void MainThreadSchedulerImpl::ForceUpdatePolicy() {
1514   base::AutoLock lock(any_thread_lock_);
1515   UpdatePolicyLocked(UpdateType::kForceUpdate);
1516 }
1517 
UpdatePolicyLocked(UpdateType update_type)1518 void MainThreadSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) {
1519   helper_.CheckOnValidThread();
1520   any_thread_lock_.AssertAcquired();
1521   if (helper_.IsShutdown())
1522     return;
1523 
1524   base::TimeTicks now = helper_.NowTicks();
1525   policy_may_need_update_.SetWhileLocked(false);
1526 
1527   base::TimeDelta expected_use_case_duration;
1528   main_thread_only().current_use_case =
1529       ComputeCurrentUseCase(now, &expected_use_case_duration);
1530 
1531   base::TimeDelta gesture_expected_flag_valid_for_duration;
1532 
1533   main_thread_only().blocking_input_expected_soon = false;
1534   if (any_thread().have_seen_a_blocking_gesture) {
1535     main_thread_only().blocking_input_expected_soon =
1536         any_thread().user_model.IsGestureExpectedSoon(
1537             now, &gesture_expected_flag_valid_for_duration);
1538   }
1539 
1540   base::TimeDelta longest_jank_free_task_duration =
1541       EstimateLongestJankFreeTaskDuration();
1542   main_thread_only().longest_jank_free_task_duration =
1543       longest_jank_free_task_duration;
1544 
1545   // The |new_policy_duration| is the minimum of |expected_use_case_duration|
1546   // and |gesture_expected_flag_valid_for_duration| unless one is zero in
1547   // which case we choose the other.
1548   base::TimeDelta new_policy_duration = expected_use_case_duration;
1549   if (new_policy_duration.is_zero() ||
1550       (gesture_expected_flag_valid_for_duration > base::TimeDelta() &&
1551        new_policy_duration > gesture_expected_flag_valid_for_duration)) {
1552     new_policy_duration = gesture_expected_flag_valid_for_duration;
1553   }
1554 
1555   if (new_policy_duration > base::TimeDelta()) {
1556     main_thread_only().current_policy_expiration_time =
1557         now + new_policy_duration;
1558     delayed_update_policy_runner_.SetDeadline(FROM_HERE, new_policy_duration,
1559                                               now);
1560   } else {
1561     main_thread_only().current_policy_expiration_time = base::TimeTicks();
1562   }
1563 
1564   // Avoid prioritizing main thread compositing (e.g., rAF) if it is extremely
1565   // slow, because that can cause starvation in other task sources.
1566   main_thread_only().main_thread_compositing_is_fast =
1567       main_thread_only().idle_time_estimator.GetExpectedIdleDuration(
1568           main_thread_only().compositor_frame_interval) >
1569       main_thread_only().compositor_frame_interval *
1570           kFastCompositingIdleTimeThreshold;
1571 
1572   Policy new_policy;
1573   new_policy.rail_mode() = RAILMode::kAnimation;
1574   new_policy.use_case() = main_thread_only().current_use_case;
1575 
1576   switch (new_policy.use_case()) {
1577     case UseCase::kCompositorGesture:
1578       if (main_thread_only().blocking_input_expected_soon)
1579         new_policy.rail_mode() = RAILMode::kResponse;
1580       break;
1581 
1582     case UseCase::kSynchronizedGesture:
1583       if (main_thread_only().blocking_input_expected_soon)
1584         new_policy.rail_mode() = RAILMode::kResponse;
1585       break;
1586 
1587     case UseCase::kMainThreadCustomInputHandling:
1588       break;
1589 
1590     case UseCase::kMainThreadGesture:
1591       if (main_thread_only().blocking_input_expected_soon)
1592         new_policy.rail_mode() = RAILMode::kResponse;
1593       break;
1594 
1595     case UseCase::kTouchstart:
1596       new_policy.rail_mode() = RAILMode::kResponse;
1597       new_policy.should_defer_task_queues() = true;
1598       break;
1599 
1600     case UseCase::kNone:
1601       // It's only safe to block tasks if we are expecting a compositor
1602       // driven gesture.
1603       if (main_thread_only().blocking_input_expected_soon &&
1604           any_thread().last_gesture_was_compositor_driven) {
1605         new_policy.rail_mode() = RAILMode::kResponse;
1606       }
1607       break;
1608 
1609     case UseCase::kEarlyLoading:
1610       new_policy.rail_mode() = RAILMode::kLoad;
1611       break;
1612 
1613     case UseCase::kLoading:
1614       new_policy.rail_mode() = RAILMode::kLoad;
1615       // TODO(skyostil): Experiment with throttling rendering frame rate.
1616       break;
1617 
1618     default:
1619       NOTREACHED();
1620   }
1621 
1622   // TODO(skyostil): Add an idle state for foreground tabs too.
1623   if (main_thread_only().renderer_hidden)
1624     new_policy.rail_mode() = RAILMode::kIdle;
1625 
1626   if (main_thread_only().renderer_pause_count != 0) {
1627     new_policy.should_pause_task_queues() = true;
1628   }
1629 
1630   if (main_thread_only().pause_timers_for_webview) {
1631     new_policy.should_pause_task_queues_for_android_webview() = true;
1632   }
1633 
1634   if (main_thread_only().use_virtual_time) {
1635     new_policy.use_virtual_time() = true;
1636   }
1637 
1638   if (scheduling_settings_
1639           .prioritize_compositing_and_loading_during_early_loading &&
1640       current_use_case() == UseCase::kEarlyLoading) {
1641     new_policy.should_prioritize_loading_with_compositing() = true;
1642   }
1643 
1644   new_policy.should_disable_throttling() = main_thread_only().use_virtual_time;
1645 
1646   new_policy.find_in_page_priority() =
1647       find_in_page_budget_pool_controller_->CurrentTaskPriority();
1648 
1649   new_policy.should_freeze_compositor_task_queue() = AllPagesFrozen();
1650 
1651   // Tracing is done before the early out check, because it's quite possible we
1652   // will otherwise miss this information in traces.
1653   CreateTraceEventObjectSnapshotLocked();
1654 
1655   // TODO(alexclarke): Can we get rid of force update now?
1656   // talp: Can't get rid of this, as per-agent scheduling happens on top of the
1657   //  policy, based on agent states.
1658   if (update_type == UpdateType::kMayEarlyOutIfPolicyUnchanged &&
1659       new_policy == main_thread_only().current_policy) {
1660     return;
1661   }
1662 
1663   main_thread_only().rail_mode_for_tracing = new_policy.rail_mode();
1664   if (new_policy.rail_mode() != main_thread_only().current_policy.rail_mode()) {
1665     if (isolate()) {
1666       isolate()->SetRAILMode(RAILModeToV8RAILMode(new_policy.rail_mode()));
1667     }
1668     for (auto& observer : main_thread_only().rail_mode_observers) {
1669       observer.OnRAILModeChanged(new_policy.rail_mode());
1670     }
1671   }
1672 
1673   if (new_policy.should_disable_throttling() !=
1674       main_thread_only().current_policy.should_disable_throttling()) {
1675     if (new_policy.should_disable_throttling()) {
1676       task_queue_throttler()->DisableThrottling();
1677     } else {
1678       task_queue_throttler()->EnableThrottling();
1679     }
1680   }
1681 
1682   Policy old_policy = main_thread_only().current_policy;
1683   main_thread_only().current_policy = new_policy;
1684 
1685   UpdateCompositorTaskQueuePriority();
1686 
1687   UpdateStateForAllTaskQueues(old_policy);
1688 }
1689 
OnAgentStrategyUpdated()1690 void MainThreadSchedulerImpl::OnAgentStrategyUpdated() {
1691   UpdateStateForAllTaskQueues(base::nullopt);
1692 }
1693 
UpdateStateForAllTaskQueues(base::Optional<Policy> previous_policy)1694 void MainThreadSchedulerImpl::UpdateStateForAllTaskQueues(
1695     base::Optional<Policy> previous_policy) {
1696   helper_.CheckOnValidThread();
1697 
1698   const Policy& current_policy = main_thread_only().current_policy;
1699   const Policy& old_policy =
1700       previous_policy.value_or(main_thread_only().current_policy);
1701 
1702   bool should_update_priorities =
1703       !previous_policy.has_value() ||
1704       ShouldUpdateTaskQueuePriorities(previous_policy.value());
1705   for (const auto& pair : task_runners_) {
1706     UpdateTaskQueueState(pair.first.get(), pair.second.get(), old_policy,
1707                          current_policy, should_update_priorities);
1708   }
1709   compositor_task_queue_enabled_voter_->SetVoteToEnable(
1710       !current_policy.should_freeze_compositor_task_queue());
1711 }
1712 
UpdateTaskQueueState(MainThreadTaskQueue * task_queue,TaskQueue::QueueEnabledVoter * task_queue_enabled_voter,const Policy & old_policy,const Policy & new_policy,bool should_update_priority) const1713 void MainThreadSchedulerImpl::UpdateTaskQueueState(
1714     MainThreadTaskQueue* task_queue,
1715     TaskQueue::QueueEnabledVoter* task_queue_enabled_voter,
1716     const Policy& old_policy,
1717     const Policy& new_policy,
1718     bool should_update_priority) const {
1719   if (should_update_priority)
1720     task_queue->GetTaskQueue()->SetQueuePriority(ComputePriority(task_queue));
1721 
1722   if (task_queue_enabled_voter) {
1723     bool is_enabled_for_agent =
1724         agent_scheduling_strategy_->QueueEnabledState(*task_queue)
1725             .value_or(true);
1726     task_queue_enabled_voter->SetVoteToEnable(
1727         is_enabled_for_agent && new_policy.IsQueueEnabled(task_queue));
1728   }
1729 
1730   // Make sure if there's no voter that the task queue is enabled.
1731   DCHECK(task_queue_enabled_voter || old_policy.IsQueueEnabled(task_queue));
1732 
1733   TimeDomainType old_time_domain_type = old_policy.GetTimeDomainType();
1734   TimeDomainType new_time_domain_type = new_policy.GetTimeDomainType();
1735 
1736   if (old_time_domain_type != new_time_domain_type) {
1737     if (new_time_domain_type == TimeDomainType::kVirtual) {
1738       DCHECK(virtual_time_domain_);
1739       task_queue->GetTaskQueue()->SetTimeDomain(virtual_time_domain_.get());
1740     } else {
1741       task_queue->GetTaskQueue()->SetTimeDomain(real_time_domain());
1742     }
1743   }
1744 }
1745 
ComputeCurrentUseCase(base::TimeTicks now,base::TimeDelta * expected_use_case_duration) const1746 UseCase MainThreadSchedulerImpl::ComputeCurrentUseCase(
1747     base::TimeTicks now,
1748     base::TimeDelta* expected_use_case_duration) const {
1749   any_thread_lock_.AssertAcquired();
1750   // Special case for flings. This is needed because we don't get notification
1751   // of a fling ending (although we do for cancellation).
1752   if (any_thread().fling_compositor_escalation_deadline > now &&
1753       !any_thread().awaiting_touch_start_response) {
1754     *expected_use_case_duration =
1755         any_thread().fling_compositor_escalation_deadline - now;
1756     return UseCase::kCompositorGesture;
1757   }
1758   // Above all else we want to be responsive to user input.
1759   *expected_use_case_duration =
1760       any_thread().user_model.TimeLeftInUserGesture(now);
1761   if (*expected_use_case_duration > base::TimeDelta()) {
1762     // Has a gesture been fully established?
1763     if (any_thread().awaiting_touch_start_response) {
1764       // No, so arrange for compositor tasks to be run at the highest priority.
1765       return UseCase::kTouchstart;
1766     }
1767 
1768     // Yes a gesture has been established.  Based on how the gesture is handled
1769     // we need to choose between one of four use cases:
1770     // 1. kCompositorGesture where the gesture is processed only on the
1771     //    compositor thread.
1772     // 2. MAIN_THREAD_GESTURE where the gesture is processed only on the main
1773     //    thread.
1774     // 3. MAIN_THREAD_CUSTOM_INPUT_HANDLING where the main thread processes a
1775     //    stream of input events and has prevented a default gesture from being
1776     //    started.
1777     // 4. SYNCHRONIZED_GESTURE where the gesture is processed on both threads.
1778     if (any_thread().last_gesture_was_compositor_driven) {
1779       if (any_thread().begin_main_frame_on_critical_path) {
1780         return UseCase::kSynchronizedGesture;
1781       } else {
1782         return UseCase::kCompositorGesture;
1783       }
1784     }
1785     if (any_thread().default_gesture_prevented) {
1786       return UseCase::kMainThreadCustomInputHandling;
1787     } else {
1788       return UseCase::kMainThreadGesture;
1789     }
1790   }
1791 
1792   // Occasionally the meaningful paint fails to be detected, so as a fallback we
1793   // treat the presence of input as an indirect signal that there is meaningful
1794   // content on the page.
1795   if (!any_thread().have_seen_input_since_navigation) {
1796     if (any_thread().waiting_for_any_main_frame_contentful_paint)
1797       return UseCase::kEarlyLoading;
1798 
1799     if (any_thread().waiting_for_any_main_frame_meaningful_paint)
1800       return UseCase::kLoading;
1801   }
1802   return UseCase::kNone;
1803 }
1804 
EstimateLongestJankFreeTaskDuration() const1805 base::TimeDelta MainThreadSchedulerImpl::EstimateLongestJankFreeTaskDuration()
1806     const {
1807   switch (main_thread_only().current_use_case) {
1808     case UseCase::kTouchstart:
1809     case UseCase::kCompositorGesture:
1810     case UseCase::kEarlyLoading:
1811     case UseCase::kLoading:
1812     case UseCase::kNone:
1813       return base::TimeDelta::FromMilliseconds(kRailsResponseTimeMillis);
1814 
1815     case UseCase::kMainThreadCustomInputHandling:
1816     case UseCase::kMainThreadGesture:
1817     case UseCase::kSynchronizedGesture:
1818       return main_thread_only().idle_time_estimator.GetExpectedIdleDuration(
1819           main_thread_only().compositor_frame_interval);
1820 
1821     default:
1822       NOTREACHED();
1823       return base::TimeDelta::FromMilliseconds(kRailsResponseTimeMillis);
1824   }
1825 }
1826 
CanEnterLongIdlePeriod(base::TimeTicks now,base::TimeDelta * next_long_idle_period_delay_out)1827 bool MainThreadSchedulerImpl::CanEnterLongIdlePeriod(
1828     base::TimeTicks now,
1829     base::TimeDelta* next_long_idle_period_delay_out) {
1830   helper_.CheckOnValidThread();
1831 
1832   MaybeUpdatePolicy();
1833   if (main_thread_only().current_use_case == UseCase::kTouchstart) {
1834     // Don't start a long idle task in touch start priority, try again when
1835     // the policy is scheduled to end.
1836     *next_long_idle_period_delay_out =
1837         std::max(base::TimeDelta(),
1838                  main_thread_only().current_policy_expiration_time - now);
1839     return false;
1840   }
1841   return true;
1842 }
1843 
1844 MainThreadSchedulerHelper*
GetSchedulerHelperForTesting()1845 MainThreadSchedulerImpl::GetSchedulerHelperForTesting() {
1846   return &helper_;
1847 }
1848 
GetIdleTimeEstimatorForTesting()1849 IdleTimeEstimator* MainThreadSchedulerImpl::GetIdleTimeEstimatorForTesting() {
1850   return &main_thread_only().idle_time_estimator;
1851 }
1852 
EnableVirtualTime()1853 base::TimeTicks MainThreadSchedulerImpl::EnableVirtualTime() {
1854   return EnableVirtualTime(main_thread_only().initial_virtual_time.is_null()
1855                                ? BaseTimeOverridePolicy::DO_NOT_OVERRIDE
1856                                : BaseTimeOverridePolicy::OVERRIDE);
1857 }
1858 
EnableVirtualTime(BaseTimeOverridePolicy policy)1859 base::TimeTicks MainThreadSchedulerImpl::EnableVirtualTime(
1860     BaseTimeOverridePolicy policy) {
1861   if (main_thread_only().use_virtual_time)
1862     return main_thread_only().initial_virtual_time_ticks;
1863   main_thread_only().use_virtual_time = true;
1864   DCHECK(!virtual_time_domain_);
1865   if (main_thread_only().initial_virtual_time.is_null())
1866     main_thread_only().initial_virtual_time = base::Time::Now();
1867   if (main_thread_only().initial_virtual_time_ticks.is_null())
1868     main_thread_only().initial_virtual_time_ticks = tick_clock()->NowTicks();
1869   virtual_time_domain_.reset(new AutoAdvancingVirtualTimeDomain(
1870       main_thread_only().initial_virtual_time +
1871           main_thread_only().initial_virtual_time_offset,
1872       main_thread_only().initial_virtual_time_ticks +
1873           main_thread_only().initial_virtual_time_offset,
1874       &helper_, policy));
1875   RegisterTimeDomain(virtual_time_domain_.get());
1876 
1877   DCHECK(!virtual_time_control_task_queue_);
1878   virtual_time_control_task_queue_ =
1879       helper_.NewTaskQueue(MainThreadTaskQueue::QueueCreationParams(
1880           MainThreadTaskQueue::QueueType::kControl));
1881   virtual_time_control_task_queue_->GetTaskQueue()->SetQueuePriority(
1882       TaskQueue::kControlPriority);
1883   virtual_time_control_task_queue_->GetTaskQueue()->SetTimeDomain(
1884       virtual_time_domain_.get());
1885 
1886   main_thread_only().use_virtual_time = true;
1887   ForceUpdatePolicy();
1888 
1889   virtual_time_domain_->SetCanAdvanceVirtualTime(
1890       !main_thread_only().virtual_time_stopped);
1891 
1892   if (main_thread_only().virtual_time_stopped)
1893     VirtualTimePaused();
1894   return main_thread_only().initial_virtual_time_ticks;
1895 }
1896 
IsVirtualTimeEnabled() const1897 bool MainThreadSchedulerImpl::IsVirtualTimeEnabled() const {
1898   return main_thread_only().use_virtual_time;
1899 }
1900 
DisableVirtualTimeForTesting()1901 void MainThreadSchedulerImpl::DisableVirtualTimeForTesting() {
1902   if (!main_thread_only().use_virtual_time)
1903     return;
1904   // Reset virtual time and all tasks queues back to their initial state.
1905   main_thread_only().use_virtual_time = false;
1906 
1907   if (main_thread_only().virtual_time_stopped) {
1908     main_thread_only().virtual_time_stopped = false;
1909     VirtualTimeResumed();
1910   }
1911 
1912   ForceUpdatePolicy();
1913 
1914   virtual_time_control_task_queue_->ShutdownTaskQueue();
1915   virtual_time_control_task_queue_ = nullptr;
1916   UnregisterTimeDomain(virtual_time_domain_.get());
1917   virtual_time_domain_.reset();
1918   virtual_time_control_task_queue_ = nullptr;
1919   ApplyVirtualTimePolicy();
1920 
1921   main_thread_only().initial_virtual_time = base::Time();
1922   main_thread_only().initial_virtual_time_ticks = base::TimeTicks();
1923 
1924   // Reset the MetricsHelper because it gets confused by time going backwards.
1925   base::TimeTicks now = tick_clock()->NowTicks();
1926   main_thread_only().metrics_helper.ResetForTest(now);
1927 }
1928 
SetVirtualTimeStopped(bool virtual_time_stopped)1929 void MainThreadSchedulerImpl::SetVirtualTimeStopped(bool virtual_time_stopped) {
1930   if (main_thread_only().virtual_time_stopped == virtual_time_stopped)
1931     return;
1932   main_thread_only().virtual_time_stopped = virtual_time_stopped;
1933 
1934   if (!main_thread_only().use_virtual_time)
1935     return;
1936 
1937   virtual_time_domain_->SetCanAdvanceVirtualTime(!virtual_time_stopped);
1938 
1939   if (virtual_time_stopped) {
1940     VirtualTimePaused();
1941   } else {
1942     VirtualTimeResumed();
1943   }
1944 }
1945 
VirtualTimePaused()1946 void MainThreadSchedulerImpl::VirtualTimePaused() {
1947   for (const auto& pair : task_runners_) {
1948     if (pair.first->CanRunWhenVirtualTimePaused())
1949       continue;
1950     DCHECK(!task_queue_throttler_->IsThrottled(pair.first->GetTaskQueue()));
1951     pair.first->GetTaskQueue()->InsertFence(
1952         TaskQueue::InsertFencePosition::kNow);
1953   }
1954 }
1955 
VirtualTimeResumed()1956 void MainThreadSchedulerImpl::VirtualTimeResumed() {
1957   for (const auto& pair : task_runners_) {
1958     if (pair.first->CanRunWhenVirtualTimePaused())
1959       continue;
1960     DCHECK(!task_queue_throttler_->IsThrottled(pair.first->GetTaskQueue()));
1961     DCHECK(pair.first->GetTaskQueue()->HasActiveFence());
1962     pair.first->GetTaskQueue()->RemoveFence();
1963   }
1964 }
1965 
VirtualTimeAllowedToAdvance() const1966 bool MainThreadSchedulerImpl::VirtualTimeAllowedToAdvance() const {
1967   return !main_thread_only().virtual_time_stopped;
1968 }
1969 
IncrementVirtualTimePauseCount()1970 base::TimeTicks MainThreadSchedulerImpl::IncrementVirtualTimePauseCount() {
1971   main_thread_only().virtual_time_pause_count++;
1972   ApplyVirtualTimePolicy();
1973 
1974   if (virtual_time_domain_)
1975     return virtual_time_domain_->Now();
1976   return tick_clock()->NowTicks();
1977 }
1978 
DecrementVirtualTimePauseCount()1979 void MainThreadSchedulerImpl::DecrementVirtualTimePauseCount() {
1980   main_thread_only().virtual_time_pause_count--;
1981   DCHECK_GE(main_thread_only().virtual_time_pause_count, 0);
1982   ApplyVirtualTimePolicy();
1983 }
1984 
MaybeAdvanceVirtualTime(base::TimeTicks new_virtual_time)1985 void MainThreadSchedulerImpl::MaybeAdvanceVirtualTime(
1986     base::TimeTicks new_virtual_time) {
1987   if (virtual_time_domain_)
1988     virtual_time_domain_->MaybeAdvanceVirtualTime(new_virtual_time);
1989 }
1990 
SetVirtualTimePolicy(VirtualTimePolicy policy)1991 void MainThreadSchedulerImpl::SetVirtualTimePolicy(VirtualTimePolicy policy) {
1992   main_thread_only().virtual_time_policy = policy;
1993   ApplyVirtualTimePolicy();
1994 }
1995 
SetInitialVirtualTime(base::Time time)1996 void MainThreadSchedulerImpl::SetInitialVirtualTime(base::Time time) {
1997   main_thread_only().initial_virtual_time = time;
1998 }
1999 
SetInitialVirtualTimeOffset(base::TimeDelta offset)2000 void MainThreadSchedulerImpl::SetInitialVirtualTimeOffset(
2001     base::TimeDelta offset) {
2002   main_thread_only().initial_virtual_time_offset = offset;
2003 }
2004 
ApplyVirtualTimePolicy()2005 void MainThreadSchedulerImpl::ApplyVirtualTimePolicy() {
2006   switch (main_thread_only().virtual_time_policy) {
2007     case VirtualTimePolicy::kAdvance:
2008       if (virtual_time_domain_) {
2009         virtual_time_domain_->SetMaxVirtualTimeTaskStarvationCount(
2010             main_thread_only().nested_runloop
2011                 ? 0
2012                 : main_thread_only().max_virtual_time_task_starvation_count);
2013         virtual_time_domain_->SetVirtualTimeFence(base::TimeTicks());
2014       }
2015       SetVirtualTimeStopped(false);
2016       break;
2017     case VirtualTimePolicy::kPause:
2018       if (virtual_time_domain_) {
2019         virtual_time_domain_->SetMaxVirtualTimeTaskStarvationCount(0);
2020         virtual_time_domain_->SetVirtualTimeFence(virtual_time_domain_->Now());
2021       }
2022       SetVirtualTimeStopped(true);
2023       break;
2024     case VirtualTimePolicy::kDeterministicLoading:
2025       if (virtual_time_domain_) {
2026         virtual_time_domain_->SetMaxVirtualTimeTaskStarvationCount(
2027             main_thread_only().nested_runloop
2028                 ? 0
2029                 : main_thread_only().max_virtual_time_task_starvation_count);
2030       }
2031 
2032       // We pause virtual time while the run loop is nested because that implies
2033       // something modal is happening such as the DevTools debugger pausing the
2034       // system. We also pause while the renderer is waiting for various
2035       // asynchronous things e.g. resource load or navigation.
2036       SetVirtualTimeStopped(main_thread_only().virtual_time_pause_count != 0 ||
2037                             main_thread_only().nested_runloop);
2038       break;
2039   }
2040 }
2041 
SetMaxVirtualTimeTaskStarvationCount(int max_task_starvation_count)2042 void MainThreadSchedulerImpl::SetMaxVirtualTimeTaskStarvationCount(
2043     int max_task_starvation_count) {
2044   main_thread_only().max_virtual_time_task_starvation_count =
2045       max_task_starvation_count;
2046   ApplyVirtualTimePolicy();
2047 }
2048 
2049 std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
AsValue(base::TimeTicks optional_now) const2050 MainThreadSchedulerImpl::AsValue(base::TimeTicks optional_now) const {
2051   base::AutoLock lock(any_thread_lock_);
2052   return AsValueLocked(optional_now);
2053 }
2054 
CreateTraceEventObjectSnapshot() const2055 void MainThreadSchedulerImpl::CreateTraceEventObjectSnapshot() const {
2056   TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
2057       TRACE_DISABLED_BY_DEFAULT("renderer.scheduler.debug"),
2058       "MainThreadScheduler", this, AsValue(helper_.NowTicks()));
2059 }
2060 
CreateTraceEventObjectSnapshotLocked() const2061 void MainThreadSchedulerImpl::CreateTraceEventObjectSnapshotLocked() const {
2062   TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
2063       TRACE_DISABLED_BY_DEFAULT("renderer.scheduler.debug"),
2064       "MainThreadScheduler", this, AsValueLocked(helper_.NowTicks()));
2065 }
2066 
2067 std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
AsValueLocked(base::TimeTicks optional_now) const2068 MainThreadSchedulerImpl::AsValueLocked(base::TimeTicks optional_now) const {
2069   auto state = std::make_unique<base::trace_event::TracedValue>();
2070   AsValueIntoLocked(state.get(), optional_now);
2071   return std::move(state);
2072 }
2073 
ToString() const2074 std::string MainThreadSchedulerImpl::ToString() const {
2075   base::AutoLock lock(any_thread_lock_);
2076   base::trace_event::TracedValueJSON value;
2077   AsValueIntoLocked(&value, base::TimeTicks());
2078   return value.ToJSON();
2079 }
2080 
AsValueIntoLocked(base::trace_event::TracedValue * state,base::TimeTicks optional_now) const2081 void MainThreadSchedulerImpl::AsValueIntoLocked(
2082     base::trace_event::TracedValue* state,
2083     base::TimeTicks optional_now) const {
2084   helper_.CheckOnValidThread();
2085   any_thread_lock_.AssertAcquired();
2086 
2087   if (optional_now.is_null())
2088     optional_now = helper_.NowTicks();
2089   state->SetBoolean(
2090       "has_visible_render_widget_with_touch_handler",
2091       main_thread_only().has_visible_render_widget_with_touch_handler);
2092   state->SetString("current_use_case",
2093                    UseCaseToString(main_thread_only().current_use_case));
2094   state->SetBoolean(
2095       "compositor_will_send_main_frame_not_expected",
2096       main_thread_only().compositor_will_send_main_frame_not_expected);
2097   state->SetBoolean("blocking_input_expected_soon",
2098                     main_thread_only().blocking_input_expected_soon);
2099   state->SetString("idle_period_state",
2100                    IdleHelper::IdlePeriodStateToString(
2101                        idle_helper_.SchedulerIdlePeriodState()));
2102   state->SetBoolean("renderer_hidden", main_thread_only().renderer_hidden);
2103   state->SetBoolean("waiting_for_any_main_frame_contentful_paint",
2104                     any_thread().waiting_for_any_main_frame_contentful_paint);
2105   state->SetBoolean("waiting_for_any_main_frame_meaningful_paint",
2106                     any_thread().waiting_for_any_main_frame_meaningful_paint);
2107   state->SetBoolean("have_seen_input_since_navigation",
2108                     any_thread().have_seen_input_since_navigation);
2109   state->SetBoolean(
2110       "have_reported_blocking_intervention_in_current_policy",
2111       main_thread_only().have_reported_blocking_intervention_in_current_policy);
2112   state->SetBoolean(
2113       "have_reported_blocking_intervention_since_navigation",
2114       main_thread_only().have_reported_blocking_intervention_since_navigation);
2115   state->SetBoolean("renderer_backgrounded",
2116                     main_thread_only().renderer_backgrounded);
2117   state->SetBoolean("keep_active_fetch_or_worker",
2118                     main_thread_only().keep_active_fetch_or_worker);
2119   state->SetDouble("now", (optional_now - base::TimeTicks()).InMillisecondsF());
2120   state->SetDouble(
2121       "fling_compositor_escalation_deadline",
2122       (any_thread().fling_compositor_escalation_deadline - base::TimeTicks())
2123           .InMillisecondsF());
2124   state->SetDouble("last_idle_period_end_time",
2125                    (any_thread().last_idle_period_end_time - base::TimeTicks())
2126                        .InMillisecondsF());
2127   state->SetBoolean("awaiting_touch_start_response",
2128                     any_thread().awaiting_touch_start_response);
2129   state->SetBoolean("begin_main_frame_on_critical_path",
2130                     any_thread().begin_main_frame_on_critical_path);
2131   state->SetBoolean("last_gesture_was_compositor_driven",
2132                     any_thread().last_gesture_was_compositor_driven);
2133   state->SetBoolean("default_gesture_prevented",
2134                     any_thread().default_gesture_prevented);
2135   state->SetBoolean("is_audio_playing", main_thread_only().is_audio_playing);
2136   state->SetBoolean("virtual_time_stopped",
2137                     main_thread_only().virtual_time_stopped);
2138   state->SetDouble("virtual_time_pause_count",
2139                    main_thread_only().virtual_time_pause_count);
2140   state->SetString(
2141       "virtual_time_policy",
2142       VirtualTimePolicyToString(main_thread_only().virtual_time_policy));
2143   state->SetBoolean("virtual_time", main_thread_only().use_virtual_time);
2144 
2145   {
2146     auto dictionary_scope = state->BeginDictionaryScoped("page_schedulers");
2147     for (PageSchedulerImpl* page_scheduler :
2148          main_thread_only().page_schedulers) {
2149       auto inner_dictionary = state->BeginDictionaryScopedWithCopiedName(
2150           PointerToString(page_scheduler));
2151       page_scheduler->AsValueInto(state);
2152     }
2153   }
2154 
2155   {
2156     auto dictionary_scope = state->BeginDictionaryScoped("policy");
2157     main_thread_only().current_policy.AsValueInto(state);
2158   }
2159 
2160   // TODO(skyostil): Can we somehow trace how accurate these estimates were?
2161   state->SetDouble(
2162       "longest_jank_free_task_duration",
2163       main_thread_only().longest_jank_free_task_duration->InMillisecondsF());
2164   state->SetDouble(
2165       "compositor_frame_interval",
2166       main_thread_only().compositor_frame_interval.InMillisecondsF());
2167   state->SetDouble(
2168       "estimated_next_frame_begin",
2169       (main_thread_only().estimated_next_frame_begin - base::TimeTicks())
2170           .InMillisecondsF());
2171   state->SetBoolean("in_idle_period", any_thread().in_idle_period);
2172 
2173   any_thread().user_model.AsValueInto(state);
2174   render_widget_scheduler_signals_.AsValueInto(state);
2175 
2176   {
2177     auto dictionary_scope =
2178         state->BeginDictionaryScoped("task_queue_throttler");
2179     task_queue_throttler_->AsValueInto(state, optional_now);
2180   }
2181 }
2182 
IsQueueEnabled(MainThreadTaskQueue * task_queue) const2183 bool MainThreadSchedulerImpl::Policy::IsQueueEnabled(
2184     MainThreadTaskQueue* task_queue) const {
2185   if (should_pause_task_queues() && task_queue->CanBePaused())
2186     return false;
2187   if (should_defer_task_queues() && task_queue->CanBeDeferred())
2188     return false;
2189   if (should_pause_task_queues_for_android_webview() &&
2190       task_queue->CanBePausedForAndroidWebview())
2191     return false;
2192   return true;
2193 }
2194 
2195 MainThreadSchedulerImpl::TimeDomainType
GetTimeDomainType() const2196 MainThreadSchedulerImpl::Policy::GetTimeDomainType() const {
2197   if (use_virtual_time())
2198     return TimeDomainType::kVirtual;
2199   return TimeDomainType::kReal;
2200 }
2201 
AsValueInto(base::trace_event::TracedValue * state) const2202 void MainThreadSchedulerImpl::Policy::AsValueInto(
2203     base::trace_event::TracedValue* state) const {
2204   state->SetString("rail_mode", RAILModeToString(rail_mode()));
2205   state->SetString("use_case", UseCaseToString(use_case()));
2206 
2207   state->SetBoolean("should_disable_throttling", should_disable_throttling());
2208   state->SetBoolean("should_defer_task_queues", should_defer_task_queues());
2209   state->SetBoolean("should_pause_task_queues", should_pause_task_queues());
2210   state->SetBoolean("should_pause_task_queues_for_android_webview",
2211                     should_pause_task_queues_for_android_webview());
2212   state->SetBoolean("use_virtual_time", use_virtual_time());
2213 }
2214 
OnIdlePeriodStarted()2215 void MainThreadSchedulerImpl::OnIdlePeriodStarted() {
2216   base::AutoLock lock(any_thread_lock_);
2217   any_thread().in_idle_period = true;
2218   UpdatePolicyLocked(UpdateType::kMayEarlyOutIfPolicyUnchanged);
2219 }
2220 
OnIdlePeriodEnded()2221 void MainThreadSchedulerImpl::OnIdlePeriodEnded() {
2222   base::AutoLock lock(any_thread_lock_);
2223   any_thread().last_idle_period_end_time = helper_.NowTicks();
2224   any_thread().in_idle_period = false;
2225   UpdatePolicyLocked(UpdateType::kMayEarlyOutIfPolicyUnchanged);
2226 }
2227 
OnPendingTasksChanged(bool has_tasks)2228 void MainThreadSchedulerImpl::OnPendingTasksChanged(bool has_tasks) {
2229   if (has_tasks ==
2230       main_thread_only().compositor_will_send_main_frame_not_expected.get())
2231     return;
2232 
2233   // Dispatch RequestBeginMainFrameNotExpectedSoon notifications asynchronously.
2234   // This is needed because idle task can be posted (and OnPendingTasksChanged
2235   // called) at any moment, including in the middle of allocating an object,
2236   // when state is not consistent. Posting a task to dispatch notifications
2237   // minimizes the amount of code that runs and sees an inconsistent state .
2238   control_task_queue_->GetTaskRunnerWithDefaultTaskType()->PostTask(
2239       FROM_HERE,
2240       base::BindOnce(
2241           &MainThreadSchedulerImpl::DispatchRequestBeginMainFrameNotExpected,
2242           weak_factory_.GetWeakPtr(), has_tasks));
2243 }
2244 
DispatchRequestBeginMainFrameNotExpected(bool has_tasks)2245 void MainThreadSchedulerImpl::DispatchRequestBeginMainFrameNotExpected(
2246     bool has_tasks) {
2247   if (has_tasks ==
2248       main_thread_only().compositor_will_send_main_frame_not_expected.get())
2249     return;
2250 
2251   TRACE_EVENT1(
2252       TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
2253       "MainThreadSchedulerImpl::DispatchRequestBeginMainFrameNotExpected",
2254       "has_tasks", has_tasks);
2255   bool success = false;
2256   for (PageSchedulerImpl* page_scheduler : main_thread_only().page_schedulers) {
2257     success |= page_scheduler->RequestBeginMainFrameNotExpected(has_tasks);
2258   }
2259   main_thread_only().compositor_will_send_main_frame_not_expected =
2260       success && has_tasks;
2261 }
2262 
DidStartProvisionalLoad(bool is_main_frame)2263 void MainThreadSchedulerImpl::DidStartProvisionalLoad(bool is_main_frame) {
2264   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
2265                "MainThreadSchedulerImpl::DidStartProvisionalLoad");
2266   if (is_main_frame) {
2267     base::AutoLock lock(any_thread_lock_);
2268     ResetForNavigationLocked();
2269   }
2270 }
2271 
DidCommitProvisionalLoad(bool is_web_history_inert_commit,bool is_reload,bool is_main_frame)2272 void MainThreadSchedulerImpl::DidCommitProvisionalLoad(
2273     bool is_web_history_inert_commit,
2274     bool is_reload,
2275     bool is_main_frame) {
2276   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
2277                "MainThreadSchedulerImpl::DidCommitProvisionalLoad");
2278   main_thread_only().has_navigated = true;
2279 
2280   // If this either isn't a history inert commit or it's a reload then we must
2281   // reset the task cost estimators.
2282   if (is_main_frame && (!is_web_history_inert_commit || is_reload)) {
2283     base::AutoLock lock(any_thread_lock_);
2284     ResetForNavigationLocked();
2285   }
2286 }
2287 
OnMainFramePaint()2288 void MainThreadSchedulerImpl::OnMainFramePaint() {
2289   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
2290                "MainThreadSchedulerImpl::OnMainFramePaint");
2291   base::AutoLock lock(any_thread_lock_);
2292   any_thread().waiting_for_any_main_frame_contentful_paint =
2293       IsAnyMainFrameWaitingForFirstContentfulPaint();
2294   any_thread().waiting_for_any_main_frame_meaningful_paint =
2295       IsAnyMainFrameWaitingForFirstMeaningfulPaint();
2296   UpdatePolicyLocked(UpdateType::kMayEarlyOutIfPolicyUnchanged);
2297 }
2298 
OnMainFrameLoad(const FrameSchedulerImpl & frame_scheduler)2299 void MainThreadSchedulerImpl::OnMainFrameLoad(
2300     const FrameSchedulerImpl& frame_scheduler) {
2301   helper_.CheckOnValidThread();
2302   if (agent_scheduling_strategy_->OnMainFrameLoad(frame_scheduler) ==
2303       AgentSchedulingStrategy::ShouldUpdatePolicy::kYes) {
2304     OnAgentStrategyUpdated();
2305   };
2306 }
2307 
OnSetTimer(const FrameSchedulerImpl & frame_scheduler,base::TimeDelta delay)2308 void MainThreadSchedulerImpl::OnSetTimer(
2309     const FrameSchedulerImpl& frame_scheduler,
2310     base::TimeDelta delay) {
2311   helper_.CheckOnValidThread();
2312   control_task_runner_->PostDelayedTask(
2313       FROM_HERE,
2314       base::BindOnce(agent_strategy_delay_callback_,
2315                      frame_scheduler.GetWeakPtr()),
2316       delay);
2317 }
2318 
OnAgentStrategyDelayPassed(base::WeakPtr<const FrameSchedulerImpl> frame_scheduler)2319 void MainThreadSchedulerImpl::OnAgentStrategyDelayPassed(
2320     base::WeakPtr<const FrameSchedulerImpl> frame_scheduler) {
2321   helper_.CheckOnValidThread();
2322   if (frame_scheduler &&
2323       agent_scheduling_strategy_->OnDelayPassed(*frame_scheduler) ==
2324           AgentSchedulingStrategy::ShouldUpdatePolicy::kYes) {
2325     OnAgentStrategyUpdated();
2326   }
2327 }
2328 
ResetForNavigationLocked()2329 void MainThreadSchedulerImpl::ResetForNavigationLocked() {
2330   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
2331                "MainThreadSchedulerImpl::ResetForNavigationLocked");
2332   helper_.CheckOnValidThread();
2333   any_thread_lock_.AssertAcquired();
2334   any_thread().user_model.Reset(helper_.NowTicks());
2335   any_thread().have_seen_a_blocking_gesture = false;
2336   any_thread().waiting_for_any_main_frame_contentful_paint =
2337       IsAnyMainFrameWaitingForFirstContentfulPaint();
2338   any_thread().waiting_for_any_main_frame_meaningful_paint =
2339       IsAnyMainFrameWaitingForFirstMeaningfulPaint();
2340   any_thread().have_seen_input_since_navigation = false;
2341   main_thread_only().idle_time_estimator.Clear();
2342   main_thread_only().have_reported_blocking_intervention_since_navigation =
2343       false;
2344   for (PageSchedulerImpl* page_scheduler : main_thread_only().page_schedulers) {
2345     page_scheduler->OnNavigation();
2346   }
2347   UpdatePolicyLocked(UpdateType::kMayEarlyOutIfPolicyUnchanged);
2348 
2349   UMA_HISTOGRAM_COUNTS_100("RendererScheduler.WebViewsPerScheduler",
2350                            base::saturated_cast<base::HistogramBase::Sample>(
2351                                main_thread_only().page_schedulers.size()));
2352 
2353   size_t frame_count = 0;
2354   for (PageSchedulerImpl* page_scheduler : main_thread_only().page_schedulers) {
2355     frame_count += page_scheduler->FrameCount();
2356   }
2357   UMA_HISTOGRAM_COUNTS_100(
2358       "RendererScheduler.WebFramesPerScheduler",
2359       base::saturated_cast<base::HistogramBase::Sample>(frame_count));
2360 }
2361 
SetTopLevelBlameContext(base::trace_event::BlameContext * blame_context)2362 void MainThreadSchedulerImpl::SetTopLevelBlameContext(
2363     base::trace_event::BlameContext* blame_context) {
2364   // Any task that runs in the default task runners belongs to the context of
2365   // all frames (as opposed to a particular frame). Note that the task itself
2366   // may still enter a more specific blame context if necessary.
2367   //
2368   // Per-frame task runners (loading, timers, etc.) are configured with a more
2369   // specific blame context by FrameSchedulerImpl.
2370   //
2371   // TODO(altimin): automatically enter top-level for all task queues associated
2372   // with renderer scheduler which do not have a corresponding frame.
2373   control_task_queue_->GetTaskQueue()->SetBlameContext(blame_context);
2374   DefaultTaskQueue()->GetTaskQueue()->SetBlameContext(blame_context);
2375   compositor_task_queue_->GetTaskQueue()->SetBlameContext(blame_context);
2376   idle_helper_.IdleTaskRunner()->SetBlameContext(blame_context);
2377   v8_task_queue_->GetTaskQueue()->SetBlameContext(blame_context);
2378 }
2379 
AddRAILModeObserver(RAILModeObserver * observer)2380 void MainThreadSchedulerImpl::AddRAILModeObserver(RAILModeObserver* observer) {
2381   main_thread_only().rail_mode_observers.AddObserver(observer);
2382   observer->OnRAILModeChanged(main_thread_only().current_policy.rail_mode());
2383 }
2384 
RemoveRAILModeObserver(RAILModeObserver const * observer)2385 void MainThreadSchedulerImpl::RemoveRAILModeObserver(
2386     RAILModeObserver const* observer) {
2387   main_thread_only().rail_mode_observers.RemoveObserver(observer);
2388 }
2389 
SetRendererProcessType(WebRendererProcessType type)2390 void MainThreadSchedulerImpl::SetRendererProcessType(
2391     WebRendererProcessType type) {
2392   main_thread_only().process_type = type;
2393 }
2394 
2395 Vector<WebInputEventAttribution>
GetPendingUserInputInfo(bool include_continuous) const2396 MainThreadSchedulerImpl::GetPendingUserInputInfo(
2397     bool include_continuous) const {
2398   base::AutoLock lock(any_thread_lock_);
2399   return any_thread().pending_input_monitor.Info(include_continuous);
2400 }
2401 
IsBeginMainFrameScheduled() const2402 bool MainThreadSchedulerImpl::IsBeginMainFrameScheduled() const {
2403   base::AutoLock lock(any_thread_lock_);
2404   return any_thread().begin_main_frame_scheduled_count.value() > 0;
2405 }
2406 
RunIdleTask(Thread::IdleTask task,base::TimeTicks deadline)2407 void MainThreadSchedulerImpl::RunIdleTask(Thread::IdleTask task,
2408                                           base::TimeTicks deadline) {
2409   std::move(task).Run(deadline);
2410 }
2411 
PostIdleTask(const base::Location & location,Thread::IdleTask task)2412 void MainThreadSchedulerImpl::PostIdleTask(const base::Location& location,
2413                                            Thread::IdleTask task) {
2414   IdleTaskRunner()->PostIdleTask(
2415       location,
2416       base::BindOnce(&MainThreadSchedulerImpl::RunIdleTask, std::move(task)));
2417 }
2418 
PostDelayedIdleTask(const base::Location & location,base::TimeDelta delay,Thread::IdleTask task)2419 void MainThreadSchedulerImpl::PostDelayedIdleTask(
2420     const base::Location& location,
2421     base::TimeDelta delay,
2422     Thread::IdleTask task) {
2423   IdleTaskRunner()->PostDelayedIdleTask(
2424       location, delay,
2425       base::BindOnce(&MainThreadSchedulerImpl::RunIdleTask, std::move(task)));
2426 }
2427 
PostNonNestableIdleTask(const base::Location & location,Thread::IdleTask task)2428 void MainThreadSchedulerImpl::PostNonNestableIdleTask(
2429     const base::Location& location,
2430     Thread::IdleTask task) {
2431   IdleTaskRunner()->PostNonNestableIdleTask(
2432       location,
2433       base::BindOnce(&MainThreadSchedulerImpl::RunIdleTask, std::move(task)));
2434 }
2435 
2436 scoped_refptr<base::SingleThreadTaskRunner>
V8TaskRunner()2437 MainThreadSchedulerImpl::V8TaskRunner() {
2438   return v8_task_runner_;
2439 }
2440 
2441 scoped_refptr<base::SingleThreadTaskRunner>
CompositorTaskRunner()2442 MainThreadSchedulerImpl::CompositorTaskRunner() {
2443   return compositor_task_runner_;
2444 }
2445 
2446 scoped_refptr<base::SingleThreadTaskRunner>
NonWakingTaskRunner()2447 MainThreadSchedulerImpl::NonWakingTaskRunner() {
2448   return non_waking_task_runner_;
2449 }
2450 
2451 std::unique_ptr<WebAgentGroupScheduler>
CreateAgentGroupScheduler()2452 MainThreadSchedulerImpl::CreateAgentGroupScheduler() {
2453   auto agent_group_scheduler = std::make_unique<AgentGroupSchedulerImpl>(*this);
2454   AddAgentGroupScheduler(agent_group_scheduler.get());
2455   return agent_group_scheduler;
2456 }
2457 
RemoveAgentGroupScheduler(AgentGroupSchedulerImpl * agent_group_scheduler)2458 void MainThreadSchedulerImpl::RemoveAgentGroupScheduler(
2459     AgentGroupSchedulerImpl* agent_group_scheduler) {
2460   DCHECK(agent_group_schedulers_.Contains(agent_group_scheduler));
2461   agent_group_schedulers_.erase(agent_group_scheduler);
2462 }
2463 
2464 WebAgentGroupScheduler*
GetCurrentAgentGroupScheduler()2465 MainThreadSchedulerImpl::GetCurrentAgentGroupScheduler() {
2466   helper_.CheckOnValidThread();
2467   return current_agent_group_scheduler_;
2468 }
2469 
SetCurrentAgentGroupScheduler(WebAgentGroupScheduler * agent_group_scheduler)2470 void MainThreadSchedulerImpl::SetCurrentAgentGroupScheduler(
2471     WebAgentGroupScheduler* agent_group_scheduler) {
2472   helper_.CheckOnValidThread();
2473   if (current_agent_group_scheduler_) {
2474     TRACE_EVENT_NESTABLE_ASYNC_END1(
2475         TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
2476         "scheduler.agent_scope", current_agent_group_scheduler_,
2477         "agent_group_scheduler", current_agent_group_scheduler_);
2478   } else {
2479     TRACE_EVENT_NESTABLE_ASYNC_END0(
2480         TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
2481         "scheduler.thread_scope", this);
2482   }
2483   current_agent_group_scheduler_ = agent_group_scheduler;
2484   if (current_agent_group_scheduler_) {
2485     TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
2486         TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
2487         "scheduler.agent_scope", current_agent_group_scheduler_,
2488         "agent_group_scheduler", current_agent_group_scheduler_);
2489   } else {
2490     TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
2491         TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
2492         "scheduler.thread_scope", this);
2493   }
2494 }
2495 
2496 std::unique_ptr<ThreadScheduler::RendererPauseHandle>
PauseScheduler()2497 MainThreadSchedulerImpl::PauseScheduler() {
2498   return PauseRenderer();
2499 }
2500 
MonotonicallyIncreasingVirtualTime()2501 base::TimeTicks MainThreadSchedulerImpl::MonotonicallyIncreasingVirtualTime() {
2502   return GetActiveTimeDomain()->Now();
2503 }
2504 
2505 WebThreadScheduler*
GetWebMainThreadSchedulerForTest()2506 MainThreadSchedulerImpl::GetWebMainThreadSchedulerForTest() {
2507   return this;
2508 }
2509 
RegisterTimeDomain(TimeDomain * time_domain)2510 void MainThreadSchedulerImpl::RegisterTimeDomain(TimeDomain* time_domain) {
2511   helper_.RegisterTimeDomain(time_domain);
2512 }
2513 
UnregisterTimeDomain(TimeDomain * time_domain)2514 void MainThreadSchedulerImpl::UnregisterTimeDomain(TimeDomain* time_domain) {
2515   helper_.UnregisterTimeDomain(time_domain);
2516 }
2517 
GetTickClock()2518 const base::TickClock* MainThreadSchedulerImpl::GetTickClock() {
2519   return tick_clock();
2520 }
2521 
tick_clock() const2522 const base::TickClock* MainThreadSchedulerImpl::tick_clock() const {
2523   return helper_.GetClock();
2524 }
2525 
AddAgentGroupScheduler(AgentGroupSchedulerImpl * agent_group_scheduler)2526 void MainThreadSchedulerImpl::AddAgentGroupScheduler(
2527     AgentGroupSchedulerImpl* agent_group_scheduler) {
2528   bool is_new_entry =
2529       agent_group_schedulers_.insert(agent_group_scheduler).is_new_entry;
2530   DCHECK(is_new_entry);
2531 }
2532 
AddPageScheduler(PageSchedulerImpl * page_scheduler)2533 void MainThreadSchedulerImpl::AddPageScheduler(
2534     PageSchedulerImpl* page_scheduler) {
2535   main_thread_only().page_schedulers.insert(page_scheduler);
2536   DetachOnIPCTaskPostedWhileInBackForwardCacheHandler();
2537   if (page_scheduler->IsOrdinary()) {
2538     memory_purge_manager_.OnPageCreated(
2539         page_scheduler->GetPageLifecycleState());
2540   }
2541 
2542   base::AutoLock lock(any_thread_lock_);
2543   any_thread().waiting_for_any_main_frame_contentful_paint =
2544       IsAnyMainFrameWaitingForFirstContentfulPaint();
2545   any_thread().waiting_for_any_main_frame_meaningful_paint =
2546       IsAnyMainFrameWaitingForFirstMeaningfulPaint();
2547   UpdatePolicyLocked(UpdateType::kMayEarlyOutIfPolicyUnchanged);
2548 }
2549 
RemovePageScheduler(PageSchedulerImpl * page_scheduler)2550 void MainThreadSchedulerImpl::RemovePageScheduler(
2551     PageSchedulerImpl* page_scheduler) {
2552   DCHECK(main_thread_only().page_schedulers.find(page_scheduler) !=
2553          main_thread_only().page_schedulers.end());
2554   main_thread_only().page_schedulers.erase(page_scheduler);
2555   if (page_scheduler->IsOrdinary()) {
2556     memory_purge_manager_.OnPageDestroyed(
2557         page_scheduler->GetPageLifecycleState());
2558   }
2559 
2560   if (IsIpcTrackingEnabledForAllPages()) {
2561     SetOnIPCTaskPostedWhileInBackForwardCacheIfNeeded();
2562   }
2563 
2564   base::AutoLock lock(any_thread_lock_);
2565   any_thread().waiting_for_any_main_frame_contentful_paint =
2566       IsAnyMainFrameWaitingForFirstContentfulPaint();
2567   any_thread().waiting_for_any_main_frame_meaningful_paint =
2568       IsAnyMainFrameWaitingForFirstMeaningfulPaint();
2569   UpdatePolicyLocked(UpdateType::kMayEarlyOutIfPolicyUnchanged);
2570 }
2571 
OnFrameAdded(const FrameSchedulerImpl & frame_scheduler)2572 void MainThreadSchedulerImpl::OnFrameAdded(
2573     const FrameSchedulerImpl& frame_scheduler) {
2574   if (agent_scheduling_strategy_->OnFrameAdded(frame_scheduler) ==
2575       AgentSchedulingStrategy::ShouldUpdatePolicy::kYes) {
2576     OnAgentStrategyUpdated();
2577   }
2578 }
2579 
OnFrameRemoved(const FrameSchedulerImpl & frame_scheduler)2580 void MainThreadSchedulerImpl::OnFrameRemoved(
2581     const FrameSchedulerImpl& frame_scheduler) {
2582   if (agent_scheduling_strategy_->OnFrameRemoved(frame_scheduler) ==
2583       AgentSchedulingStrategy::ShouldUpdatePolicy::kYes) {
2584     OnAgentStrategyUpdated();
2585   }
2586 }
2587 
OnPageFrozen()2588 void MainThreadSchedulerImpl::OnPageFrozen() {
2589   memory_purge_manager_.OnPageFrozen();
2590   UpdatePolicy();
2591 }
2592 
OnPageResumed()2593 void MainThreadSchedulerImpl::OnPageResumed() {
2594   memory_purge_manager_.OnPageResumed();
2595   UpdatePolicy();
2596 }
2597 
BroadcastIntervention(const String & message)2598 void MainThreadSchedulerImpl::BroadcastIntervention(const String& message) {
2599   helper_.CheckOnValidThread();
2600   for (auto* page_scheduler : main_thread_only().page_schedulers)
2601     page_scheduler->ReportIntervention(message);
2602 }
2603 
OnTaskStarted(MainThreadTaskQueue * queue,const base::sequence_manager::Task & task,const TaskQueue::TaskTiming & task_timing)2604 void MainThreadSchedulerImpl::OnTaskStarted(
2605     MainThreadTaskQueue* queue,
2606     const base::sequence_manager::Task& task,
2607     const TaskQueue::TaskTiming& task_timing) {
2608   SetCurrentAgentGroupScheduler(queue ? queue->GetAgentGroupScheduler()
2609                                       : nullptr);
2610 
2611   main_thread_only().running_queues.push(queue);
2612   if (main_thread_only().nested_runloop)
2613     return;
2614 
2615   main_thread_only().current_task_start_time = task_timing.start_time();
2616   main_thread_only().task_description_for_tracing = TaskDescriptionForTracing{
2617       static_cast<TaskType>(task.task_type),
2618       queue
2619           ? base::Optional<MainThreadTaskQueue::QueueType>(queue->queue_type())
2620           : base::nullopt};
2621 
2622   main_thread_only().task_priority_for_tracing =
2623       queue ? base::Optional<TaskQueue::QueuePriority>(
2624                   queue->GetTaskQueue()->GetQueuePriority())
2625             : base::nullopt;
2626 }
2627 
OnTaskCompleted(base::WeakPtr<MainThreadTaskQueue> queue,const base::sequence_manager::Task & task,TaskQueue::TaskTiming * task_timing,base::sequence_manager::LazyNow * lazy_now)2628 void MainThreadSchedulerImpl::OnTaskCompleted(
2629     base::WeakPtr<MainThreadTaskQueue> queue,
2630     const base::sequence_manager::Task& task,
2631     TaskQueue::TaskTiming* task_timing,
2632     base::sequence_manager::LazyNow* lazy_now) {
2633   // Microtasks may detach the task queue and invalidate |queue|.
2634   PerformMicrotaskCheckpoint();
2635 
2636   task_timing->RecordTaskEnd(lazy_now);
2637 
2638   DCHECK_LE(task_timing->start_time(), task_timing->end_time());
2639   DCHECK(!main_thread_only().running_queues.empty());
2640   DCHECK(!queue ||
2641          main_thread_only().running_queues.top().get() == queue.get());
2642   if (task_timing->has_wall_time() && queue && queue->GetFrameScheduler())
2643     queue->GetFrameScheduler()->AddTaskTime(task_timing->wall_duration());
2644   main_thread_only().running_queues.pop();
2645   if (main_thread_only().nested_runloop)
2646     return;
2647 
2648   DispatchOnTaskCompletionCallbacks();
2649 
2650   if (queue) {
2651     task_queue_throttler()->OnTaskRunTimeReported(queue->GetTaskQueue(),
2652                                                   task_timing->start_time(),
2653                                                   task_timing->end_time());
2654   }
2655 
2656   // TODO(altimin): Per-page metrics should also be considered.
2657   main_thread_only().metrics_helper.RecordTaskMetrics(queue.get(), task,
2658                                                       *task_timing);
2659   main_thread_only().task_description_for_tracing = base::nullopt;
2660 
2661   // Unset the state of |task_priority_for_tracing|.
2662   main_thread_only().task_priority_for_tracing = base::nullopt;
2663 
2664   RecordTaskUkm(queue.get(), task, *task_timing);
2665 
2666   main_thread_only().compositor_priority_experiments.OnTaskCompleted(
2667       queue.get(), main_thread_only().compositor_priority, task_timing);
2668 
2669   find_in_page_budget_pool_controller_->OnTaskCompleted(queue.get(),
2670                                                         task_timing);
2671 
2672   // GetCurrentAgentGroupScheduler() should return nullptr when
2673   // it's running thread global task runners.
2674   SetCurrentAgentGroupScheduler(nullptr);
2675 }
2676 
RecordTaskUkm(MainThreadTaskQueue * queue,const base::sequence_manager::Task & task,const TaskQueue::TaskTiming & task_timing)2677 void MainThreadSchedulerImpl::RecordTaskUkm(
2678     MainThreadTaskQueue* queue,
2679     const base::sequence_manager::Task& task,
2680     const TaskQueue::TaskTiming& task_timing) {
2681   if (!helper_.ShouldRecordTaskUkm(task_timing.has_thread_time()))
2682     return;
2683 
2684   if (queue && queue->GetFrameScheduler()) {
2685     auto status = RecordTaskUkmImpl(queue, task, task_timing,
2686                                     queue->GetFrameScheduler(), true);
2687     UMA_HISTOGRAM_ENUMERATION(
2688         "Scheduler.Experimental.Renderer.UkmRecordingStatus", status,
2689         UkmRecordingStatus::kCount);
2690     return;
2691   }
2692 
2693   for (PageSchedulerImpl* page_scheduler : main_thread_only().page_schedulers) {
2694     auto status = RecordTaskUkmImpl(
2695         queue, task, task_timing,
2696         page_scheduler->SelectFrameForUkmAttribution(), false);
2697     UMA_HISTOGRAM_ENUMERATION(
2698         "Scheduler.Experimental.Renderer.UkmRecordingStatus", status,
2699         UkmRecordingStatus::kCount);
2700   }
2701 }
2702 
RecordTaskUkmImpl(MainThreadTaskQueue * queue,const base::sequence_manager::Task & task,const TaskQueue::TaskTiming & task_timing,FrameSchedulerImpl * frame_scheduler,bool precise_attribution)2703 UkmRecordingStatus MainThreadSchedulerImpl::RecordTaskUkmImpl(
2704     MainThreadTaskQueue* queue,
2705     const base::sequence_manager::Task& task,
2706     const TaskQueue::TaskTiming& task_timing,
2707     FrameSchedulerImpl* frame_scheduler,
2708     bool precise_attribution) {
2709   // Skip tasks which have deleted the frame or the page scheduler.
2710   if (!frame_scheduler)
2711     return UkmRecordingStatus::kErrorMissingFrame;
2712   if (!frame_scheduler->GetPageScheduler())
2713     return UkmRecordingStatus::kErrorDetachedFrame;
2714 
2715   ukm::UkmRecorder* ukm_recorder = frame_scheduler->GetUkmRecorder();
2716   // OOPIFs are not supported.
2717   if (!ukm_recorder)
2718     return UkmRecordingStatus::kErrorMissingUkmRecorder;
2719 
2720   ukm::builders::RendererSchedulerTask builder(
2721       frame_scheduler->GetUkmSourceId());
2722 
2723   builder.SetVersion(kUkmMetricVersion);
2724   builder.SetPageSchedulers(main_thread_only().page_schedulers.size());
2725 
2726   builder.SetRendererBackgrounded(main_thread_only().renderer_backgrounded);
2727   builder.SetRendererHidden(main_thread_only().renderer_hidden);
2728   builder.SetRendererAudible(main_thread_only().is_audio_playing);
2729   builder.SetUseCase(
2730       static_cast<int>(main_thread_only().current_use_case.get()));
2731   builder.SetTaskType(task.task_type);
2732   builder.SetQueueType(static_cast<int>(
2733       queue ? queue->queue_type() : MainThreadTaskQueue::QueueType::kDetached));
2734   builder.SetFrameStatus(static_cast<int>(
2735       GetFrameStatus(queue ? queue->GetFrameScheduler() : nullptr)));
2736   builder.SetTaskDuration(task_timing.wall_duration().InMicroseconds());
2737   builder.SetIsOOPIF(!frame_scheduler->GetPageScheduler()->IsMainFrameLocal());
2738 
2739   if (main_thread_only().renderer_backgrounded) {
2740     base::TimeDelta time_since_backgrounded =
2741         (task_timing.end_time() -
2742          main_thread_only().background_status_changed_at);
2743 
2744     // Trade off for privacy: Round to seconds for times below 10 minutes and
2745     // minutes afterwards.
2746     int64_t seconds_since_backgrounded = 0;
2747     if (time_since_backgrounded < base::TimeDelta::FromMinutes(10)) {
2748       seconds_since_backgrounded = time_since_backgrounded.InSeconds();
2749     } else {
2750       seconds_since_backgrounded =
2751           time_since_backgrounded.InMinutes() * kSecondsPerMinute;
2752     }
2753 
2754     builder.SetSecondsSinceBackgrounded(seconds_since_backgrounded);
2755   }
2756 
2757   if (task_timing.has_thread_time()) {
2758     builder.SetTaskCPUDuration(task_timing.thread_duration().InMicroseconds());
2759   }
2760 
2761   builder.Record(ukm_recorder);
2762 
2763   return UkmRecordingStatus::kSuccess;
2764 }
2765 
ComputePriority(MainThreadTaskQueue * task_queue) const2766 TaskQueue::QueuePriority MainThreadSchedulerImpl::ComputePriority(
2767     MainThreadTaskQueue* task_queue) const {
2768   DCHECK(task_queue);
2769 
2770   // If |task_queue| is associated to a frame, then the frame scheduler computes
2771   // the priority.
2772   FrameSchedulerImpl* frame_scheduler = task_queue->GetFrameScheduler();
2773 
2774   if (frame_scheduler) {
2775     return frame_scheduler->ComputePriority(task_queue);
2776   }
2777 
2778   switch (task_queue->GetPrioritisationType()) {
2779     case MainThreadTaskQueue::QueueTraits::PrioritisationType::kCompositor:
2780       return main_thread_only().compositor_priority;
2781     case MainThreadTaskQueue::QueueTraits::PrioritisationType::kInput:
2782       return TaskQueue::QueuePriority::kHighestPriority;
2783     case MainThreadTaskQueue::QueueTraits::PrioritisationType::kBestEffort:
2784       return TaskQueue::QueuePriority::kBestEffortPriority;
2785     case MainThreadTaskQueue::QueueTraits::PrioritisationType::kRegular:
2786       return TaskQueue::QueuePriority::kNormalPriority;
2787     default:
2788       NOTREACHED();
2789       return TaskQueue::QueuePriority::kNormalPriority;
2790   }
2791 }
2792 
OnBeginNestedRunLoop()2793 void MainThreadSchedulerImpl::OnBeginNestedRunLoop() {
2794   DCHECK(!main_thread_only().running_queues.empty());
2795   main_thread_only().nested_runloop = true;
2796   ApplyVirtualTimePolicy();
2797 }
2798 
OnExitNestedRunLoop()2799 void MainThreadSchedulerImpl::OnExitNestedRunLoop() {
2800   DCHECK(!main_thread_only().running_queues.empty());
2801   main_thread_only().nested_runloop = false;
2802   ApplyVirtualTimePolicy();
2803 }
2804 
AddTaskTimeObserver(TaskTimeObserver * task_time_observer)2805 void MainThreadSchedulerImpl::AddTaskTimeObserver(
2806     TaskTimeObserver* task_time_observer) {
2807   helper_.AddTaskTimeObserver(task_time_observer);
2808 }
2809 
RemoveTaskTimeObserver(TaskTimeObserver * task_time_observer)2810 void MainThreadSchedulerImpl::RemoveTaskTimeObserver(
2811     TaskTimeObserver* task_time_observer) {
2812   helper_.RemoveTaskTimeObserver(task_time_observer);
2813 }
2814 
2815 AutoAdvancingVirtualTimeDomain*
GetVirtualTimeDomain()2816 MainThreadSchedulerImpl::GetVirtualTimeDomain() {
2817   return virtual_time_domain_.get();
2818 }
2819 
GetActiveTimeDomain()2820 TimeDomain* MainThreadSchedulerImpl::GetActiveTimeDomain() {
2821   if (main_thread_only().use_virtual_time) {
2822     return GetVirtualTimeDomain();
2823   } else {
2824     return real_time_domain();
2825   }
2826 }
2827 
OnTraceLogEnabled()2828 void MainThreadSchedulerImpl::OnTraceLogEnabled() {
2829   CreateTraceEventObjectSnapshot();
2830   tracing_controller_.OnTraceLogEnabled();
2831   for (PageSchedulerImpl* page_scheduler : main_thread_only().page_schedulers) {
2832     page_scheduler->OnTraceLogEnabled();
2833   }
2834 }
2835 
OnTraceLogDisabled()2836 void MainThreadSchedulerImpl::OnTraceLogDisabled() {}
2837 
GetWeakPtr()2838 base::WeakPtr<MainThreadSchedulerImpl> MainThreadSchedulerImpl::GetWeakPtr() {
2839   return weak_factory_.GetWeakPtr();
2840 }
2841 
IsAudioPlaying() const2842 bool MainThreadSchedulerImpl::IsAudioPlaying() const {
2843   return main_thread_only().is_audio_playing;
2844 }
2845 
ShouldUpdateTaskQueuePriorities(Policy old_policy) const2846 bool MainThreadSchedulerImpl::ShouldUpdateTaskQueuePriorities(
2847     Policy old_policy) const {
2848   return old_policy.use_case() !=
2849              main_thread_only().current_policy.use_case() ||
2850          old_policy.find_in_page_priority() !=
2851              main_thread_only().current_policy.find_in_page_priority();
2852 }
2853 
current_use_case() const2854 UseCase MainThreadSchedulerImpl::current_use_case() const {
2855   return main_thread_only().current_use_case;
2856 }
2857 
2858 const MainThreadSchedulerImpl::SchedulingSettings&
scheduling_settings() const2859 MainThreadSchedulerImpl::scheduling_settings() const {
2860   return scheduling_settings_;
2861 }
2862 
SetPrioritizeCompositingAfterInput(bool prioritize_compositing_after_input)2863 void MainThreadSchedulerImpl::SetPrioritizeCompositingAfterInput(
2864     bool prioritize_compositing_after_input) {
2865   if (main_thread_only().prioritize_compositing_after_input ==
2866       prioritize_compositing_after_input) {
2867     return;
2868   }
2869   main_thread_only().prioritize_compositing_after_input =
2870       prioritize_compositing_after_input;
2871   UpdateCompositorTaskQueuePriority();
2872 }
2873 
2874 void MainThreadSchedulerImpl::
OnCompositorPriorityExperimentUpdateCompositorPriority()2875     OnCompositorPriorityExperimentUpdateCompositorPriority() {
2876   UpdateCompositorTaskQueuePriority();
2877 }
2878 
ComputeCompositorPriority() const2879 TaskQueue::QueuePriority MainThreadSchedulerImpl::ComputeCompositorPriority()
2880     const {
2881   if (main_thread_only().prioritize_compositing_after_input) {
2882     return TaskQueue::QueuePriority::kVeryHighPriority;
2883   } else if (scheduling_settings_
2884                  .prioritize_compositing_and_loading_during_early_loading &&
2885              current_use_case() == UseCase::kEarlyLoading) {
2886     return TaskQueue::QueuePriority::kHighPriority;
2887   } else {
2888     base::Optional<TaskQueue::QueuePriority> computed_compositor_priority =
2889         ComputeCompositorPriorityFromUseCase();
2890     if (computed_compositor_priority) {
2891       return computed_compositor_priority.value();
2892     } else if (main_thread_only()
2893                    .compositor_priority_experiments.IsExperimentActive()) {
2894       return main_thread_only()
2895           .compositor_priority_experiments.GetCompositorPriority();
2896     }
2897   }
2898   return TaskQueue::QueuePriority::kNormalPriority;
2899 }
2900 
UpdateCompositorTaskQueuePriority()2901 void MainThreadSchedulerImpl::UpdateCompositorTaskQueuePriority() {
2902   main_thread_only().compositor_priority = ComputeCompositorPriority();
2903   CompositorTaskQueue()->GetTaskQueue()->SetQueuePriority(
2904       ComputePriority(CompositorTaskQueue().get()));
2905 }
2906 
2907 base::Optional<TaskQueue::QueuePriority>
ComputeCompositorPriorityFromUseCase() const2908 MainThreadSchedulerImpl::ComputeCompositorPriorityFromUseCase() const {
2909   switch (current_use_case()) {
2910     case UseCase::kCompositorGesture:
2911       if (main_thread_only().blocking_input_expected_soon)
2912         return TaskQueue::QueuePriority::kHighestPriority;
2913       // What we really want to do is priorize loading tasks, but that doesn't
2914       // seem to be safe. Instead we do that by proxy by deprioritizing
2915       // compositor tasks. This should be safe since we've already gone to the
2916       // pain of fixing ordering issues with them.
2917       return TaskQueue::QueuePriority::kLowPriority;
2918 
2919     case UseCase::kSynchronizedGesture:
2920     case UseCase::kMainThreadCustomInputHandling:
2921       // In main thread input handling use case we don't have perfect knowledge
2922       // about which things we should be prioritizing, so we don't attempt to
2923       // block expensive tasks because we don't know whether they were integral
2924       // to the page's functionality or not.
2925       if (main_thread_only().main_thread_compositing_is_fast)
2926         return TaskQueue::QueuePriority::kHighestPriority;
2927       return base::nullopt;
2928 
2929     case UseCase::kMainThreadGesture:
2930     case UseCase::kTouchstart:
2931       // A main thread gesture is for example a scroll gesture which is handled
2932       // by the main thread. Since we know the established gesture type, we can
2933       // be a little more aggressive about prioritizing compositing and input
2934       // handling over other tasks.
2935       return TaskQueue::QueuePriority::kHighestPriority;
2936 
2937     case UseCase::kNone:
2938     case UseCase::kEarlyLoading:
2939     case UseCase::kLoading:
2940       return base::nullopt;
2941 
2942     default:
2943       NOTREACHED();
2944       return base::nullopt;
2945   }
2946 }
2947 
OnSafepointEntered()2948 void MainThreadSchedulerImpl::OnSafepointEntered() {
2949   DCHECK(WTF::IsMainThread());
2950   DCHECK(!main_thread_only().nested_runloop);
2951   main_thread_only().metrics_helper.OnSafepointEntered(helper_.NowTicks());
2952 }
2953 
OnSafepointExited()2954 void MainThreadSchedulerImpl::OnSafepointExited() {
2955   DCHECK(WTF::IsMainThread());
2956   DCHECK(!main_thread_only().nested_runloop);
2957   main_thread_only().metrics_helper.OnSafepointExited(helper_.NowTicks());
2958 }
2959 
ExecuteAfterCurrentTask(base::OnceClosure on_completion_task)2960 void MainThreadSchedulerImpl::ExecuteAfterCurrentTask(
2961     base::OnceClosure on_completion_task) {
2962   main_thread_only().on_task_completion_callbacks.push_back(
2963       std::move(on_completion_task));
2964 }
2965 
DispatchOnTaskCompletionCallbacks()2966 void MainThreadSchedulerImpl::DispatchOnTaskCompletionCallbacks() {
2967   for (auto& closure : main_thread_only().on_task_completion_callbacks) {
2968     std::move(closure).Run();
2969   }
2970   main_thread_only().on_task_completion_callbacks.clear();
2971 }
2972 
AllPagesFrozen() const2973 bool MainThreadSchedulerImpl::AllPagesFrozen() const {
2974   if (main_thread_only().page_schedulers.IsEmpty())
2975     return false;
2976   for (const auto* scheduler : main_thread_only().page_schedulers) {
2977     if (!scheduler->IsFrozen())
2978       return false;
2979   }
2980   return true;
2981 }
2982 
2983 // static
UseCaseToString(UseCase use_case)2984 const char* MainThreadSchedulerImpl::UseCaseToString(UseCase use_case) {
2985   switch (use_case) {
2986     case UseCase::kNone:
2987       return "none";
2988     case UseCase::kCompositorGesture:
2989       return "compositor_gesture";
2990     case UseCase::kMainThreadCustomInputHandling:
2991       return "main_thread_custom_input_handling";
2992     case UseCase::kSynchronizedGesture:
2993       return "synchronized_gesture";
2994     case UseCase::kTouchstart:
2995       return "touchstart";
2996     case UseCase::kEarlyLoading:
2997       return "early_loading";
2998     case UseCase::kLoading:
2999       return "loading";
3000     case UseCase::kMainThreadGesture:
3001       return "main_thread_gesture";
3002     default:
3003       NOTREACHED();
3004       return nullptr;
3005   }
3006 }
3007 
3008 // static
RAILModeToString(RAILMode rail_mode)3009 const char* MainThreadSchedulerImpl::RAILModeToString(RAILMode rail_mode) {
3010   switch (rail_mode) {
3011     case RAILMode::kResponse:
3012       return "response";
3013     case RAILMode::kAnimation:
3014       return "animation";
3015     case RAILMode::kIdle:
3016       return "idle";
3017     case RAILMode::kLoad:
3018       return "load";
3019     default:
3020       NOTREACHED();
3021       return nullptr;
3022   }
3023 }
3024 
3025 // static
TimeDomainTypeToString(TimeDomainType domain_type)3026 const char* MainThreadSchedulerImpl::TimeDomainTypeToString(
3027     TimeDomainType domain_type) {
3028   switch (domain_type) {
3029     case TimeDomainType::kReal:
3030       return "real";
3031     case TimeDomainType::kVirtual:
3032       return "virtual";
3033     default:
3034       NOTREACHED();
3035       return nullptr;
3036   }
3037 }
3038 
3039 // static
VirtualTimePolicyToString(VirtualTimePolicy virtual_time_policy)3040 const char* MainThreadSchedulerImpl::VirtualTimePolicyToString(
3041     VirtualTimePolicy virtual_time_policy) {
3042   switch (virtual_time_policy) {
3043     case VirtualTimePolicy::kAdvance:
3044       return "ADVANCE";
3045     case VirtualTimePolicy::kPause:
3046       return "PAUSE";
3047     case VirtualTimePolicy::kDeterministicLoading:
3048       return "DETERMINISTIC_LOADING";
3049     default:
3050       NOTREACHED();
3051       return nullptr;
3052   }
3053 }
3054 
3055 }  // namespace scheduler
3056 }  // namespace blink
3057