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

content / public / browser / browser_main_parts.h [blame]

// Copyright 2012 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_PUBLIC_BROWSER_BROWSER_MAIN_PARTS_H_
#define CONTENT_PUBLIC_BROWSER_BROWSER_MAIN_PARTS_H_

#include <memory>

#include "base/functional/callback.h"
#include "base/types/strong_alias.h"
#include "content/common/content_export.h"

namespace base {
class RunLoop;
}

namespace content {

// This class contains different "stages" to be executed by |BrowserMain()|.
//
// Stages:
//
//  ** Cross-platform startup stages.
//  ** Invoked during BrowserMainRunnerImpl::Initialize(), after
//     ContentMainRunner's full initialization.
//
//  - PreEarlyInitialization: things to be be done as soon as possible on
//    program start (such as setting up signal handlers; checking auto-restarts
//    on update; etc.). Core APIs like base::FeatureList,
//    base::SingleThreadTaskRunner::CurrentDefaultHandle, and base::ThreadPool
//    are already functional at this point (ThreadPool will accept but not run
//    tasks until PostCreateThreads).
//
//  - PostEarlyInitialization: things to be be done as soon as possible but that
//    can/must wait until after the few things in BrowserMainLoop's own
//    EarlyInitialization have completed.
//
//  - ToolkitInitialized: similar to PostEarlyInitialization but for the UI
//    toolkit. Allows an embedder to do any extra toolkit initialization.
//
//  - PreCreateMainMessageLoop: things to be done at some generic time before
//    the creation of the main message loop.
//
//  - PostCreateMainMessageLoop: things to be done as early as possible but that
//    need the main message loop to be around (i.e. BrowserThread::UI is up).
//
//  - PreCreateThreads: things that don't need to happen super early but still
//    need to happen during single-threaded initialization (e.g. immutable
//    Singletons that are initialized once and read-only from all threads
//    thereafter).
//    Note: other threads might exist before this point but no child threads
//    owned by content. As such, this is still "single-threaded" initialization
//    as far as content and its embedders are concerned and the right place to
//    initialize thread-compatible objects:
//    https://chromium.googlesource.com/chromium/src/+/main/docs/threading_and_tasks.md#threading-lexicon
//
//  - PostCreateThreads: things that should be done as early as possible but
//    need browser process threads to be alive (i.e. BrowserThread::IO is up and
//    base::ThreadPool is running tasks).
//
//  - PreMainMessageLoopRun: IN DOUBT, PUT THINGS HERE. At this stage all core
//    APIs have been initialized. Services that must be initialized before the
//    browser is considered functional can be initialized from here. Ideally
//    only the frontend is initialized here while the backend takes advantage of
//    a base::ThreadPool worker to come up asynchronously. Things that must
//    happen on the main thread eventually but don't need to block startup
//    should post a BEST_EFFORT task from this stage.
//
//  ** End of cross-platform startup stages.
//  ** Stages above are run as part of startup stages in
//  ** BrowserMainLoop::CreateStartupTasks() and can even be run eagerly (e.g.
//  ** Android app warmup attempts to run these async.
//
//  - WillRunMainMessageLoop: The main thread's RunLoop will be run
//    *immediately* upon returning from this method. While PreMainMessageLoopRun
//    gives that impression, in practice it's part of initialization phases
//    which are triggered independently from MainMessageLoopRun (and can even
//    happen async). In browser tests, PreMainMessageLoopRun() will run before
//    entering test bodies whereas WillRunMainMessageLoop() won't (the control
//    is given to the test rather running the loop). Furthermore, this is only
//    called on platforms where BrowserMainLoop::RunMainMessageLoop is called.
//    Thus, very few things should be done at this stage. It's mostly intended
//    as a way for embedders to override or cancel the default RunLoop if
//    needed.
//
//  - OnFirstIdle: The main thread reached idle for the first time since
//    WillRunMainMessageLoop(). In other words, it's done running any tasks
//    posted as part of the above phases and anything else posted from these.
//
//  - PostMainMessageLoopRun: stop and cleanup things that can/should be cleaned
//    up while base::ThreadPool and BrowserThread::IO are still running.
//    Note: Also see BrowserMainLoop::ShutdownThreadsAndCleanUp() which is often
//    a good fit to stop services (PostMainMessageLoopRun() is called from it).
//
//  - PostDestroyThreads: stop and cleanup things that need to be cleaned up in
//    the single-threaded teardown phase (i.e. typically things that had to
//    created in PreCreateThreads()).
//
//
// How to add stuff (to existing parts):
//  - Figure out when your new code should be executed. What must happen
//    before/after your code is executed? Are there performance reasons for
//    running your code at a particular time? Document these things!
//  - Split out any platform-specific bits. Please avoid #ifdefs it at all
//    possible. You have two choices for platform-specific code: (1) Execute it
//    from one of the |Pre/Post...()| methods in an embedder's platform-specific
//    override (e.g., ChromeBrowserMainPartsWin::PreCreateMainMessageLoop()); do
//    this if the code is unique to an embedder and platform type. Or (2)
//    execute it from one of the "stages" (e.g.,
//    |BrowserMainLoop::EarlyInitialization()|) and provide platform-specific
//    implementations of your code (in a virtual method); do this if you need to
//    provide different implementations across most/all platforms.
//  - Unless your new code is just one or two lines, put it into a separate
//    method with a well-defined purpose. (Likewise, if you're adding to an
//    existing chunk which makes it longer than one or two lines, please move
//    the code out into a separate method.)
//
class CONTENT_EXPORT BrowserMainParts {
 public:
  BrowserMainParts() {}
  virtual ~BrowserMainParts() {}

  // See class comment above for a description of each phase.
  //
  // A return value other than RESULT_CODE_NORMAL_EXIT on any of these methods
  // indicates an error, aborts startup, and is used as the exit status.
  virtual int PreEarlyInitialization();
  virtual void PostEarlyInitialization() {}
  virtual void ToolkitInitialized() {}
  virtual void PreCreateMainMessageLoop() {}
  virtual void PostCreateMainMessageLoop() {}
  virtual int PreCreateThreads();
  virtual void PostCreateThreads() {}
  virtual int PreMainMessageLoopRun();

  // This method returns true by default, telling InterceptMainMessageLoopRun
  // that it should attempt to intercept the main message loop run. Overriding
  // it enables the embedder to conditionally cancel that attempt and the
  // message loop run itself(by returning false). This is key in some
  // integration tests that verify early exit by testing that the test body
  // (entered when the main message loop run is intercepted) is never entered.
  // On Android, BrowserMainLoop never enters MainMessageLoopRun() but this
  // method is still relevant to control whether InterceptMainMessageLoopRun()
  // is allowed to take control of the browser main loop (browser tests).
  virtual bool ShouldInterceptMainMessageLoopRun();

  // This gives BrowserMainParts one last opportunity to tweak the upcoming main
  // message loop run. The embedder may replace |run_loop| to alter the default
  // RunLoop about to be run (must not be nullified, override
  // ShouldInterceptMainMessageLoopRun to cancel the run). Note: This point is
  // never reached on Android as it never invokes MainMessageLoopRun(),
  // InterceptMainMessageLoopRun() is Android's last chance at altering the
  // default native loop run.
  virtual void WillRunMainMessageLoop(
      std::unique_ptr<base::RunLoop>& run_loop) {}

  virtual void OnFirstIdle() {}
  virtual void PostMainMessageLoopRun() {}
  virtual void PostDestroyThreads() {}
};

}  // namespace content

#endif  // CONTENT_PUBLIC_BROWSER_BROWSER_MAIN_PARTS_H_