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