1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241
  242

content / browser / scheduler / browser_task_executor.h [blame]

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_BROWSER_SCHEDULER_BROWSER_TASK_EXECUTOR_H_
#define CONTENT_BROWSER_SCHEDULER_BROWSER_TASK_EXECUTOR_H_

#include <memory>

#include "base/gtest_prod_util.h"
#include "base/memory/scoped_refptr.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "build/build_config.h"
#include "content/browser/scheduler/browser_io_thread_delegate.h"
#include "content/browser/scheduler/browser_ui_thread_scheduler.h"
#include "content/common/content_export.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"

// The BrowserTaskExecutor's job is to map base::TaskTraits to actual task
// queues for the browser process.
//
// We actually have two TaskExecutors:
// * BrowserTaskExecutor::UIThreadExecutor registered with UI thread TLS.
// * BrowserTaskExecutor::IOThreadExecutor registered with IO thread TLS.
//
// This lets us efficiently implement base::CurrentThread on UI and IO threads.
namespace content {

class BrowserTaskExecutorTest;
class BrowserProcessIOThread;

class CONTENT_EXPORT BaseBrowserTaskExecutor {
 public:
  BaseBrowserTaskExecutor();
  virtual ~BaseBrowserTaskExecutor();

  // Returns the task runner for |traits| under |identifier|. Note: during the
  // migration away from task traits extension, |traits| may also contain a
  // browser thread id, if so, it should match |identifier| (|identifier| has to
  // be provided explicitly because in the new source of tasks it's not part of
  // |traits|) -- ref. crbug.com/1026641.
  scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner(
      BrowserThread::ID identifier,
      const BrowserTaskTraits& traits) const;

  // Helper to match a QueueType from TaskTraits.
  // TODO(crbug.com/40108370): Take BrowserTaskTraits as a parameter when
  // getting off the need to support base::TaskTraits currently passed to this
  // class in its role as a base::TaskExecutor.
  static BrowserTaskQueues::QueueType GetQueueType(
      const BrowserTaskTraits& traits);

 protected:
  scoped_refptr<BrowserUIThreadScheduler::Handle> browser_ui_thread_handle_;
  scoped_refptr<BrowserIOThreadDelegate::Handle> browser_io_thread_handle_;
};

class CONTENT_EXPORT BrowserTaskExecutor : public BaseBrowserTaskExecutor {
 public:
  // Creates and registers a BrowserTaskExecutor on the current thread which
  // owns a BrowserUIThreadScheduler. This facilitates posting tasks to a
  // BrowserThread via //base/task/post_task.h.
  // TODO(crbug.com/40108370): Clean this up now that post_task.h is deprecated.
  // All BrowserThread::UI task queues except best effort ones are also enabled.
  // TODO(carlscab): These queues should be enabled in
  // BrowserMainLoop::InitializeMainThread() but some Android tests fail if we
  // do so.
  static void Create();

  BrowserTaskExecutor(const BrowserTaskExecutor&) = delete;
  BrowserTaskExecutor& operator=(const BrowserTaskExecutor&) = delete;

  // Creates the IO thread using the scheduling infrastructure set up in the
  // Create() method. That means that clients have access to TaskRunners
  // associated with the IO thread before that thread is even created. In order
  // to do so this class will own the Thread::Delegate for the IO thread
  // (BrowserIOThreadDelegate) until the thread is created, at which point
  // ownership will be transferred and the |BrowserTaskExecutor| will only
  // communicate with it via TaskRunner instances.
  //
  // Browser task queues will initially be disabled, that is tasks posted to
  // them will not run. But the default task runner of the thread (the one you
  // get via SingleThreadTaskRunner::GetCurrentDefault()) will be active. This
  // is the same task runner you get by calling
  // BrowserProcessIOThread::task_runner(). The queues can be initialized by
  // calling InitializeIOThread which is done during Chromium startup in
  // BrowserMainLoop::CreateThreads.
  //
  // Early on during Chromium startup we initialize the ServiceManager and it
  // needs to run tasks immediately. The ServiceManager itself does not know
  // about the IO thread (it does not use the browser task traits), it only uses
  // the task runner provided to it during initialization and possibly
  // SingleThreadTaskRunner::GetCurrentDefault() from tasks it posts. But we
  // currently run it on the IO thread so we need the default task runner to be
  // active for its tasks to run. Note that since tasks posted via the browser
  // task traits will not run they won't be able to access the default task
  // runner either, so for those tasks the default task queue is also
  // "disabled".
  //
  // Attention: This method can only be called once (as there must be only one
  // IO thread).
  // Attention: Must be called after Create()
  // Attention: Can not be called after Shutdown() or ResetForTesting()
  static std::unique_ptr<BrowserProcessIOThread> CreateIOThread();

  // Enables non best effort queues on the IO thread. Usually called from
  // BrowserMainLoop::CreateThreads.
  static void InitializeIOThread();

  // Informs BrowserTaskExecutor that startup is complete.
  // It will communicate that to UI and IO thread BrowserTaskQueues.
  // Can be called multiple times.
  static void OnStartupComplete();

  // Helpers to statically call into BaseBrowserTaskExecutor::GetTaskRunner()
  // from browser_thread_impl.cc. Callers should use browser_thread.h's
  // GetUIThreadTaskRunner over this.
  // TODO(crbug.com/40108370): Clean up this indirection after the migration
  // (once registering a base::BrowserTaskExecutor is no longer necessary).
  static scoped_refptr<base::SingleThreadTaskRunner> GetUIThreadTaskRunner(
      const BrowserTaskTraits& traits);
  static scoped_refptr<base::SingleThreadTaskRunner> GetIOThreadTaskRunner(
      const BrowserTaskTraits& traits);

  // As Create but with the user provided objects.
  static void CreateForTesting(
      std::unique_ptr<BrowserUIThreadScheduler> browser_ui_thread_scheduler,
      std::unique_ptr<BrowserIOThreadDelegate> browser_io_thread_delegate);

  // This must be called after the FeatureList has been initialized in order
  // for scheduling experiments to function.
  static void PostFeatureListSetup();

  // Called when some part of the browser begins handling input. Must be called
  // from the browser UI thread and the value must be reset once input is
  // finished.
  static std::optional<BrowserUIThreadScheduler::UserInputActiveHandle>
  OnUserInputStart();

  // Winds down the BrowserTaskExecutor, after this no tasks can be executed
  // and the base::TaskExecutor APIs are non-functional but won't crash if
  // called. In unittests however we need to clean up, so
  // BrowserTaskExecutor::ResetForTesting should be
  // called (~BrowserTaskEnvironment() takes care of this).
  static void Shutdown();

  // Unregister and delete the TaskExecutor after a test.
  static void ResetForTesting();

  // Runs all pending tasks for the given thread. Tasks posted after this method
  // is called (in particular any task posted from within any of the pending
  // tasks) will be queued but not run. Conceptually this call will disable all
  // queues, run any pending tasks, and re-enable all the queues.
  //
  // If any of the pending tasks posted a task, these could be run by calling
  // this method again or running a regular RunLoop. But if that were the case
  // you should probably rewrite you tests to wait for a specific event instead.
  static void RunAllPendingTasksOnThreadForTesting(
      BrowserThread::ID identifier);

 private:
  friend class BrowserIOThreadDelegate;
  friend class BrowserTaskExecutorTest;

  // Constructed on UI thread and registered with UI thread TLS. This backs the
  // implementation of base::CurrentThread for the browser UI thread.
  class UIThreadExecutor : public BaseBrowserTaskExecutor {
   public:
    explicit UIThreadExecutor(
        std::unique_ptr<BrowserUIThreadScheduler> browser_ui_thread_scheduler);

    ~UIThreadExecutor() override;

    scoped_refptr<BrowserUIThreadScheduler::Handle> GetUIThreadHandle();

    void SetIOThreadHandle(
        scoped_refptr<BrowserUIThreadScheduler::Handle> io_thread_handle);

    void BindToCurrentThread();

    std::optional<BrowserUIThreadScheduler::UserInputActiveHandle>
    OnUserInputStart();

    void PostFeatureListSetup();

   private:
    std::unique_ptr<BrowserUIThreadScheduler> browser_ui_thread_scheduler_;
  };

  // Constructed on UI thread and later registered with IO thread TLS. This
  // backs the implementation of base::CurrentThread for the browser IO thread.
  class IOThreadExecutor : public BaseBrowserTaskExecutor {
   public:
    explicit IOThreadExecutor(
        std::unique_ptr<BrowserIOThreadDelegate> browser_io_thread_delegate);

    ~IOThreadExecutor() override;

    scoped_refptr<BrowserUIThreadScheduler::Handle> GetIOThreadHandle();

    void SetUIThreadHandle(
        scoped_refptr<BrowserUIThreadScheduler::Handle> ui_thread_handle);

    std::unique_ptr<BrowserIOThreadDelegate> TakeDelegate() {
      return std::move(browser_io_thread_delegate_);
    }

   private:
    std::unique_ptr<BrowserIOThreadDelegate> browser_io_thread_delegate_;
  };

  static void CreateInternal(
      std::unique_ptr<BrowserUIThreadScheduler> browser_ui_thread_scheduler,
      std::unique_ptr<BrowserIOThreadDelegate> browser_io_thread_delegate);

  // For GetProxyTaskRunnerForThread().
  FRIEND_TEST_ALL_PREFIXES(BrowserTaskExecutorTest,
                           EnsureUIThreadTraitPointsToExpectedQueue);
  FRIEND_TEST_ALL_PREFIXES(BrowserTaskExecutorTest,
                           EnsureIOThreadTraitPointsToExpectedQueue);
  FRIEND_TEST_ALL_PREFIXES(BrowserTaskExecutorTest,
                           BestEffortTasksRunAfterStartup);

  // For Get();
  FRIEND_TEST_ALL_PREFIXES(BrowserTaskExecutorTest,
                           RegisterExecutorForBothThreads);
  explicit BrowserTaskExecutor(
      std::unique_ptr<BrowserUIThreadScheduler> browser_ui_thread_scheduler,
      std::unique_ptr<BrowserIOThreadDelegate> browser_io_thread_delegate);
  ~BrowserTaskExecutor() override;

  static BrowserTaskExecutor* Get();

  std::unique_ptr<UIThreadExecutor> ui_thread_executor_;
  std::unique_ptr<IOThreadExecutor> io_thread_executor_;
};

}  // namespace content

#endif  // CONTENT_BROWSER_SCHEDULER_BROWSER_TASK_EXECUTOR_H_