1 // Copyright 2015 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 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_MAIN_THREAD_MAIN_THREAD_TASK_QUEUE_H_
6 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_MAIN_THREAD_MAIN_THREAD_TASK_QUEUE_H_
7 
8 #include <memory>
9 
10 #include "base/memory/weak_ptr.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/task/sequence_manager/task_queue.h"
13 #include "base/task/sequence_manager/task_queue_impl.h"
14 #include "base/task/sequence_manager/time_domain.h"
15 #include "net/base/request_priority.h"
16 #include "third_party/blink/renderer/platform/scheduler/main_thread/agent_group_scheduler_impl.h"
17 #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
18 #include "third_party/blink/renderer/platform/scheduler/public/web_scheduling_priority.h"
19 
20 namespace base {
21 namespace sequence_manager {
22 class SequenceManager;
23 }
24 }  // namespace base
25 
26 namespace blink {
27 namespace scheduler {
28 
29 using TaskQueue = base::sequence_manager::TaskQueue;
30 
31 namespace main_thread_scheduler_impl_unittest {
32 class MainThreadSchedulerImplTest;
33 }
34 
35 namespace agent_interference_recorder_test {
36 class AgentInterferenceRecorderTest;
37 }
38 
39 class FrameSchedulerImpl;
40 class MainThreadSchedulerImpl;
41 
42 // TODO(kdillon): Remove ref-counting of MainThreadTaskQueues as it's no longer
43 // needed.
44 class PLATFORM_EXPORT MainThreadTaskQueue
45     : public base::RefCountedThreadSafe<MainThreadTaskQueue> {
46  public:
47   enum class QueueType {
48     // Keep MainThreadTaskQueue::NameForQueueType in sync.
49     // This enum is used for a histogram and it should not be re-numbered.
50     // TODO(altimin): Clean up obsolete names and use a new histogram when
51     // the situation settles.
52     kControl = 0,
53     kDefault = 1,
54 
55     // 2 was used for default loading task runner but this was deprecated.
56 
57     // 3 was used for default timer task runner but this was deprecated.
58 
59     // 4: kUnthrottled, obsolete.
60 
61     kFrameLoading = 5,
62     // 6 : kFrameThrottleable, replaced with FRAME_THROTTLEABLE.
63     // 7 : kFramePausable, replaced with kFramePausable
64     kCompositor = 8,
65     kIdle = 9,
66     kTest = 10,
67     kFrameLoadingControl = 11,
68     kFrameThrottleable = 12,
69     kFrameDeferrable = 13,
70     kFramePausable = 14,
71     kFrameUnpausable = 15,
72     kV8 = 16,
73     // 17 : kIPC, obsolete
74     kInput = 18,
75 
76     // Detached is used in histograms for tasks which are run after frame
77     // is detached and task queue is gracefully shutdown.
78     // TODO(altimin): Move to the top when histogram is renumbered.
79     kDetached = 19,
80 
81     // 20 : kCleanup, obsolete.
82     // 21 : kWebSchedulingUserInteraction, obsolete.
83     // 22 : kWebSchedulingBestEffort, obsolete.
84 
85     kWebScheduling = 24,
86     kNonWaking = 25,
87 
88     kIPCTrackingForCachedPages = 26,
89 
90     // Used to group multiple types when calculating Expected Queueing Time.
91     kOther = 23,
92     kCount = 27
93   };
94 
95   // Returns name of the given queue type. Returned string has application
96   // lifetime.
97   static const char* NameForQueueType(QueueType queue_type);
98 
99   // Returns true if task queues of the given queue type can be created on a
100   // per-frame basis, and false if they are only created on a shared basis for
101   // the entire main thread.
102   static bool IsPerFrameTaskQueue(QueueType);
103 
104   using QueueTraitsKeyType = int;
105 
106   // QueueTraits represent the deferrable, throttleable, pausable, and freezable
107   // properties of a MainThreadTaskQueue. For non-loading task queues, there
108   // will be at most one task queue with a specific set of QueueTraits, and the
109   // the QueueTraits determine which queues should be used to run which task
110   // types.
111   struct QueueTraits {
QueueTraitsQueueTraits112     QueueTraits()
113         : can_be_deferred(false),
114           can_be_throttled(false),
115           can_be_intensively_throttled(false),
116           can_be_paused(false),
117           can_be_frozen(false),
118           can_run_in_background(true),
119           can_run_when_virtual_time_paused(true),
120           can_be_paused_for_android_webview(false) {}
121 
122     // Separate enum class for handling prioritisation decisions in task queues.
123     enum class PrioritisationType {
124       kInternalScriptContinuation = 0,
125       kBestEffort = 1,
126       kRegular = 2,
127       kLoading = 3,
128       kLoadingControl = 4,
129       kFindInPage = 5,
130       kExperimentalDatabase = 6,
131       kJavaScriptTimer = 7,
132       kHighPriorityLocalFrame = 8,
133       kCompositor = 9,  // Main-thread only.
134       kInput = 10,
135 
136       kCount = 11
137     };
138 
139     // kPrioritisationTypeWidthBits is the number of bits required
140     // for PrioritisationType::kCount - 1, which is the number of bits needed
141     // to represent |prioritisation_type| in QueueTraitKeyType.
142     // We need to update it whenever there is a change in
143     // PrioritisationType::kCount.
144     // TODO(sreejakshetty) make the number of bits calculation automated.
145     static constexpr int kPrioritisationTypeWidthBits = 4;
146     static_assert(static_cast<int>(PrioritisationType::kCount) <=
147                       (1 << kPrioritisationTypeWidthBits),
148                   "Wrong Instanstiation for kPrioritisationTypeWidthBits");
149 
150     QueueTraits(const QueueTraits&) = default;
151 
SetCanBeDeferredQueueTraits152     QueueTraits SetCanBeDeferred(bool value) {
153       can_be_deferred = value;
154       return *this;
155     }
156 
SetCanBeThrottledQueueTraits157     QueueTraits SetCanBeThrottled(bool value) {
158       can_be_throttled = value;
159       return *this;
160     }
161 
SetCanBeIntensivelyThrottledQueueTraits162     QueueTraits SetCanBeIntensivelyThrottled(bool value) {
163       can_be_intensively_throttled = value;
164       return *this;
165     }
166 
SetCanBePausedQueueTraits167     QueueTraits SetCanBePaused(bool value) {
168       can_be_paused = value;
169       return *this;
170     }
171 
SetCanBeFrozenQueueTraits172     QueueTraits SetCanBeFrozen(bool value) {
173       can_be_frozen = value;
174       return *this;
175     }
176 
SetCanRunInBackgroundQueueTraits177     QueueTraits SetCanRunInBackground(bool value) {
178       can_run_in_background = value;
179       return *this;
180     }
181 
SetCanRunWhenVirtualTimePausedQueueTraits182     QueueTraits SetCanRunWhenVirtualTimePaused(bool value) {
183       can_run_when_virtual_time_paused = value;
184       return *this;
185     }
186 
SetPrioritisationTypeQueueTraits187     QueueTraits SetPrioritisationType(PrioritisationType type) {
188       prioritisation_type = type;
189       return *this;
190     }
191 
SetCanBePausedForAndroidWebviewQueueTraits192     QueueTraits SetCanBePausedForAndroidWebview(bool value) {
193       can_be_paused_for_android_webview = value;
194       return *this;
195     }
196 
197     bool operator==(const QueueTraits& other) const {
198       return can_be_deferred == other.can_be_deferred &&
199              can_be_throttled == other.can_be_throttled &&
200              can_be_intensively_throttled ==
201                  other.can_be_intensively_throttled &&
202              can_be_paused == other.can_be_paused &&
203              can_be_frozen == other.can_be_frozen &&
204              can_run_in_background == other.can_run_in_background &&
205              can_run_when_virtual_time_paused ==
206                  other.can_run_when_virtual_time_paused &&
207              prioritisation_type == other.prioritisation_type &&
208              can_be_paused_for_android_webview ==
209                  other.can_be_paused_for_android_webview;
210     }
211 
212     // Return a key suitable for WTF::HashMap.
KeyQueueTraits213     QueueTraitsKeyType Key() const {
214       // offset for shifting bits to compute |key|.
215       // |key| starts at 1 since 0 and -1 are used for empty/deleted values.
216       int offset = 0;
217       int key = 1 << (offset++);
218       key |= can_be_deferred << (offset++);
219       key |= can_be_throttled << (offset++);
220       key |= can_be_intensively_throttled << (offset++);
221       key |= can_be_paused << (offset++);
222       key |= can_be_frozen << (offset++);
223       key |= can_run_in_background << (offset++);
224       key |= can_run_when_virtual_time_paused << (offset++);
225       key |= can_be_paused_for_android_webview << (offset++);
226       key |= static_cast<int>(prioritisation_type) << offset;
227       offset += kPrioritisationTypeWidthBits;
228       return key;
229     }
230 
231     bool can_be_deferred : 1;
232     bool can_be_throttled : 1;
233     bool can_be_intensively_throttled : 1;
234     bool can_be_paused : 1;
235     bool can_be_frozen : 1;
236     bool can_run_in_background : 1;
237     bool can_run_when_virtual_time_paused : 1;
238     bool can_be_paused_for_android_webview : 1;
239     PrioritisationType prioritisation_type = PrioritisationType::kRegular;
240   };
241 
242   struct QueueCreationParams {
QueueCreationParamsQueueCreationParams243     explicit QueueCreationParams(QueueType queue_type)
244         : queue_type(queue_type),
245           spec(NameForQueueType(queue_type)),
246           agent_group_scheduler(nullptr),
247           frame_scheduler(nullptr),
248           freeze_when_keep_active(false) {}
249 
SetFreezeWhenKeepActiveQueueCreationParams250     QueueCreationParams SetFreezeWhenKeepActive(bool value) {
251       freeze_when_keep_active = value;
252       return *this;
253     }
254 
SetWebSchedulingPriorityQueueCreationParams255     QueueCreationParams SetWebSchedulingPriority(
256         base::Optional<WebSchedulingPriority> priority) {
257       web_scheduling_priority = priority;
258       return *this;
259     }
260 
261     // Forwarded calls to |queue_traits|
262 
SetCanBeDeferredQueueCreationParams263     QueueCreationParams SetCanBeDeferred(bool value) {
264       queue_traits = queue_traits.SetCanBeDeferred(value);
265       ApplyQueueTraitsToSpec();
266       return *this;
267     }
268 
SetCanBeThrottledQueueCreationParams269     QueueCreationParams SetCanBeThrottled(bool value) {
270       queue_traits = queue_traits.SetCanBeThrottled(value);
271       ApplyQueueTraitsToSpec();
272       return *this;
273     }
274 
SetCanBePausedQueueCreationParams275     QueueCreationParams SetCanBePaused(bool value) {
276       queue_traits = queue_traits.SetCanBePaused(value);
277       ApplyQueueTraitsToSpec();
278       return *this;
279     }
280 
SetCanBeFrozenQueueCreationParams281     QueueCreationParams SetCanBeFrozen(bool value) {
282       queue_traits = queue_traits.SetCanBeFrozen(value);
283       ApplyQueueTraitsToSpec();
284       return *this;
285     }
286 
SetCanRunInBackgroundQueueCreationParams287     QueueCreationParams SetCanRunInBackground(bool value) {
288       queue_traits = queue_traits.SetCanRunInBackground(value);
289       ApplyQueueTraitsToSpec();
290       return *this;
291     }
292 
SetCanRunWhenVirtualTimePausedQueueCreationParams293     QueueCreationParams SetCanRunWhenVirtualTimePaused(bool value) {
294       queue_traits = queue_traits.SetCanRunWhenVirtualTimePaused(value);
295       ApplyQueueTraitsToSpec();
296       return *this;
297     }
298 
SetPrioritisationTypeQueueCreationParams299     QueueCreationParams SetPrioritisationType(
300         QueueTraits::PrioritisationType type) {
301       queue_traits = queue_traits.SetPrioritisationType(type);
302       ApplyQueueTraitsToSpec();
303       return *this;
304     }
305 
SetQueueTraitsQueueCreationParams306     QueueCreationParams SetQueueTraits(QueueTraits value) {
307       queue_traits = value;
308       ApplyQueueTraitsToSpec();
309       return *this;
310     }
311 
312     // Forwarded calls to |spec|.
313 
SetAgentGroupSchedulerQueueCreationParams314     QueueCreationParams SetAgentGroupScheduler(
315         AgentGroupSchedulerImpl* scheduler) {
316       agent_group_scheduler = scheduler;
317       return *this;
318     }
319 
SetFrameSchedulerQueueCreationParams320     QueueCreationParams SetFrameScheduler(FrameSchedulerImpl* scheduler) {
321       frame_scheduler = scheduler;
322       return *this;
323     }
324 
SetShouldMonitorQuiescenceQueueCreationParams325     QueueCreationParams SetShouldMonitorQuiescence(bool should_monitor) {
326       spec = spec.SetShouldMonitorQuiescence(should_monitor);
327       return *this;
328     }
329 
SetShouldNotifyObserversQueueCreationParams330     QueueCreationParams SetShouldNotifyObservers(bool run_observers) {
331       spec = spec.SetShouldNotifyObservers(run_observers);
332       return *this;
333     }
334 
SetTimeDomainQueueCreationParams335     QueueCreationParams SetTimeDomain(
336         base::sequence_manager::TimeDomain* domain) {
337       spec = spec.SetTimeDomain(domain);
338       return *this;
339     }
340 
341     QueueType queue_type;
342     TaskQueue::Spec spec;
343     AgentGroupSchedulerImpl* agent_group_scheduler;
344     FrameSchedulerImpl* frame_scheduler;
345     QueueTraits queue_traits;
346     bool freeze_when_keep_active;
347     base::Optional<WebSchedulingPriority> web_scheduling_priority;
348 
349    private:
ApplyQueueTraitsToSpecQueueCreationParams350     void ApplyQueueTraitsToSpec() {
351       spec = spec.SetDelayedFencesAllowed(queue_traits.can_be_throttled);
352     }
353   };
354 
queue_type()355   QueueType queue_type() const { return queue_type_; }
356 
CanBeDeferred()357   bool CanBeDeferred() const { return queue_traits_.can_be_deferred; }
358 
CanBeThrottled()359   bool CanBeThrottled() const { return queue_traits_.can_be_throttled; }
360 
CanBeIntensivelyThrottled()361   bool CanBeIntensivelyThrottled() const {
362     return queue_traits_.can_be_intensively_throttled;
363   }
364 
CanBePaused()365   bool CanBePaused() const { return queue_traits_.can_be_paused; }
366 
367   // Used for WebView's pauseTimers API. This API expects layout, parsing, and
368   // Javascript timers to be paused. Though this suggests we should pause
369   // loading (where parsing happens) as well, there are some expectations of JS
370   // still being able to run during pause. Because of this we only pause timers
371   // as well as any other pausable frame task queue.
372   // https://developer.android.com/reference/android/webkit/WebView#pauseTimers()
CanBePausedForAndroidWebview()373   bool CanBePausedForAndroidWebview() const {
374     return queue_traits_.can_be_paused_for_android_webview;
375   }
376 
CanBeFrozen()377   bool CanBeFrozen() const { return queue_traits_.can_be_frozen; }
378 
CanRunInBackground()379   bool CanRunInBackground() const {
380     return queue_traits_.can_run_in_background;
381   }
382 
CanRunWhenVirtualTimePaused()383   bool CanRunWhenVirtualTimePaused() const {
384     return queue_traits_.can_run_when_virtual_time_paused;
385   }
386 
FreezeWhenKeepActive()387   bool FreezeWhenKeepActive() const { return freeze_when_keep_active_; }
388 
GetQueueTraits()389   QueueTraits GetQueueTraits() const { return queue_traits_; }
390 
GetPrioritisationType()391   QueueTraits::PrioritisationType GetPrioritisationType() const {
392     return queue_traits_.prioritisation_type;
393   }
394 
395   void OnTaskReady(const void* frame_scheduler,
396                    const base::sequence_manager::Task& task,
397                    base::sequence_manager::LazyNow* lazy_now);
398 
399   void OnTaskStarted(const base::sequence_manager::Task& task,
400                      const TaskQueue::TaskTiming& task_timing);
401 
402   void OnTaskCompleted(const base::sequence_manager::Task& task,
403                        TaskQueue::TaskTiming* task_timing,
404                        base::sequence_manager::LazyNow* lazy_now);
405 
406   void SetOnIPCTaskPosted(
407       base::RepeatingCallback<void(const base::sequence_manager::Task&)>
408           on_ipc_task_posted_callback);
409   void DetachOnIPCTaskPostedWhileInBackForwardCache();
410 
411   void DetachFromMainThreadScheduler();
412 
413   void ShutdownTaskQueue();
414 
415   WebAgentGroupScheduler* GetAgentGroupScheduler();
416 
417   FrameSchedulerImpl* GetFrameScheduler() const;
418 
CreateTaskRunner(TaskType task_type)419   scoped_refptr<base::SingleThreadTaskRunner> CreateTaskRunner(
420       TaskType task_type) {
421     return task_queue_->CreateTaskRunner(static_cast<int>(task_type));
422   }
423 
424   void SetNetRequestPriority(net::RequestPriority net_request_priority);
425   base::Optional<net::RequestPriority> net_request_priority() const;
426 
427   void SetWebSchedulingPriority(WebSchedulingPriority priority);
428   base::Optional<WebSchedulingPriority> web_scheduling_priority() const;
429 
430   // TODO(kdillon): Improve MTTQ API surface so that we no longer
431   // need to expose the raw pointer to the queue.
GetTaskQueue()432   TaskQueue* GetTaskQueue() { return task_queue_.get(); }
433 
434   // This method returns the default task runner with task type kTaskTypeNone
435   // and is mostly used for tests. For most use cases, you'll want a more
436   // specific task runner and should use the 'CreateTaskRunner' method and pass
437   // the desired task type.
438   const scoped_refptr<base::SingleThreadTaskRunner>&
GetTaskRunnerWithDefaultTaskType()439   GetTaskRunnerWithDefaultTaskType() {
440     return task_queue_->task_runner();
441   }
442 
AsWeakPtr()443   base::WeakPtr<MainThreadTaskQueue> AsWeakPtr() {
444     return weak_ptr_factory_.GetWeakPtr();
445   }
446 
447  protected:
448   void SetFrameSchedulerForTest(FrameSchedulerImpl* frame_scheduler);
449 
450   // TODO(kdillon): Remove references to TaskQueueImpl once TaskQueueImpl
451   // inherits from TaskQueue.
452   MainThreadTaskQueue(
453       std::unique_ptr<base::sequence_manager::internal::TaskQueueImpl> impl,
454       const TaskQueue::Spec& spec,
455       const QueueCreationParams& params,
456       MainThreadSchedulerImpl* main_thread_scheduler);
457 
458   ~MainThreadTaskQueue();
459 
460  private:
461   friend class base::RefCountedThreadSafe<MainThreadTaskQueue>;
462   friend class base::sequence_manager::SequenceManager;
463   friend class blink::scheduler::main_thread_scheduler_impl_unittest::
464       MainThreadSchedulerImplTest;
465   friend class agent_interference_recorder_test::AgentInterferenceRecorderTest;
466 
467   // Clear references to main thread scheduler and frame scheduler and dispatch
468   // appropriate notifications. This is the common part of ShutdownTaskQueue and
469   // DetachFromMainThreadScheduler.
470   void ClearReferencesToSchedulers();
471 
472   scoped_refptr<TaskQueue> task_queue_;
473 
474   const QueueType queue_type_;
475   const QueueTraits queue_traits_;
476   const bool freeze_when_keep_active_;
477 
478   // Warning: net_request_priority is not the same as the priority of the queue.
479   // It is the priority (at the loading stack level) of the resource associated
480   // to the queue, if one exists.
481   //
482   // Used to track UMA metrics for resource loading tasks split by net priority.
483   base::Optional<net::RequestPriority> net_request_priority_;
484 
485   // |web_scheduling_priority_| is the priority of the task queue within the web
486   // scheduling API. This priority is used in conjunction with the frame
487   // scheduling policy to determine the task queue priority.
488   base::Optional<WebSchedulingPriority> web_scheduling_priority_;
489 
490   // Needed to notify renderer scheduler about completed tasks.
491   MainThreadSchedulerImpl* main_thread_scheduler_;  // NOT OWNED
492 
493   AgentGroupSchedulerImpl* agent_group_scheduler_{nullptr};  // NOT OWNED
494 
495   // Set in the constructor. Cleared in ClearReferencesToSchedulers(). Can never
496   // be set to a different value afterwards (except in tests).
497   FrameSchedulerImpl* frame_scheduler_;  // NOT OWNED
498 
499   base::WeakPtrFactory<MainThreadTaskQueue> weak_ptr_factory_{this};
500 
501   DISALLOW_COPY_AND_ASSIGN(MainThreadTaskQueue);
502 };
503 
504 }  // namespace scheduler
505 }  // namespace blink
506 
507 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_MAIN_THREAD_MAIN_THREAD_TASK_QUEUE_H_
508