// 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 { … }; } // namespace content #endif // CONTENT_PUBLIC_BROWSER_BROWSER_MAIN_PARTS_H_