zoukankan      html  css  js  c++  java
  • Chromium学习笔记:程序启动入口分析(Windows)

    转自:Chromium学习笔记:程序启动入口分析(Windows)

    本篇笔记跟踪记录了Chromium的启动过程,主要关注 Browser 进程和 Renderer 进程。根据 Chromium 项目的分层设计,我们把 Content API 称作为 Content 层,而把调用 Content API 实现浏览器程序的部分称作为 Embedder 层。在项目中,Embedder 层有 chromecontent_shell 等多种实现。

    1、main() 函数

    Chromium的main函数在 chromeappchrome_exe_main_win.cc,具体如下:

    // chromeappchrome_exe_main_win.cc

    #if !defined(WIN_CONSOLE_APP)
    int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prev, wchar_t*, int) {
    #else
    int main() {
    HINSTANCE instance = GetModuleHandle(nullptr);
    #endif
    install_static::InitializeFromPrimaryModule();
    SignalInitializeCrashReporting();

    ......

    // Load and launch the chrome dll. *Everything* happens inside.
    VLOG(1) << "About to load main DLL.";
    MainDllLoader* loader = MakeMainDllLoader();
    int rc = loader->Launch(instance, exe_entry_point_ticks);
    loader->RelaunchChromeBrowserWithNewCommandLineIfNeeded();
    delete loader;
    return rc;
    }

    在main函数中,最重要的一步,就是 int rc = loader->Launch(instance, exe_entry_point_ticks); 载入 chrome.dll运行

    2、载入 chrome.dll

    在这里首先调用了 MakeMainDllLoader() 函数,这是一个静态函数,在chromeappmain_dll_loader.cc 中,内容如下:

    // chromeappmain_dll_loader.cc

    MainDllLoader* MakeMainDllLoader() {
    #if defined(GOOGLE_CHROME_BUILD)
    return new ChromeDllLoader();
    #else
    return new ChromiumDllLoader();
    #endif
    }

    函数创建并返回一个 ChromiumDllLoader,紧接着再调用它的 Launch 函数,内容如下:

    // chromeappmain_dll_loader.cc

    int MainDllLoader::Launch(HINSTANCE instance,
    base::TimeTicks exe_entry_point_ticks) {
    const base::CommandLine& cmd_line = *base::CommandLine::ForCurrentProcess();
    process_type_ = cmd_line.GetSwitchValueASCII(switches::kProcessType);

    ......

    dll_ = Load(&file);
    if (!dll_)
    return chrome::RESULT_CODE_MISSING_DATA;

    OnBeforeLaunch(cmd_line, process_type_, file);
    DLL_MAIN chrome_main =
    reinterpret_cast<DLL_MAIN>(::GetProcAddress(dll_, "ChromeMain"));
    int rc = chrome_main(instance, &sandbox_info,
    exe_entry_point_ticks.ToInternalValue());
    OnBeforeExit(file);
    return rc;
    }

    这里完成了 chrome.dll 的载入,并且执行里面的 ChromeMain 函数。

    3、ChromeMain() 函数

    ChromeMain 函数负责 Embedder 层的实现类创建,并传递给 Content 层,定义在 chromeappchrome_main.cc 中,内容如下:

    // chromeappchrome_main.cc

    extern "C" {
    DLLEXPORT int __cdecl ChromeMain(HINSTANCE instance,
    sandbox::SandboxInterfaceInfo* sandbox_info,
    int64_t exe_entry_point_ticks);
    }

    ......

    #if defined(OS_WIN)
    DLLEXPORT int __cdecl ChromeMain(HINSTANCE instance,
    sandbox::SandboxInterfaceInfo* sandbox_info,
    int64_t exe_entry_point_ticks) {
    #elif defined(OS_POSIX)
    int ChromeMain(int argc, const char** argv) {
    int64_t exe_entry_point_ticks = 0;
    #endif

    #if defined(OS_WIN)
    install_static::InitializeFromPrimaryModule();
    #endif

    ChromeMainDelegate chrome_main_delegate(
    base::TimeTicks::FromInternalValue(exe_entry_point_ticks));
    content::ContentMainParams params(&chrome_main_delegate);

    ......

    int rv = content::ContentMain(params);

    return rv;
    }

    在ChromeMain中,最终执行到了 content::ContentMain 这个函数。

    4、content::ContentMain() 函数

    代码执行到这里,进入了 Content 层,并且传入参数 content::ContentMainParams 类型的参数 params,它是由 Embedder 层传递过来的重要参数,里面包含了 Embedder 层的具体实现信息,此结构体在 contentpublicappcontent_main.h 中定义如下:

    // contentpublicappcontent_main.h

    struct ContentMainParams {
    explicit ContentMainParams(ContentMainDelegate* delegate)
    : delegate(delegate) {}

    ContentMainDelegate* delegate;

    ......

    其中有一个重要的成员变量 delegate,其类型为 content::ContentMainDelegate,它在 contentpublicappcontent_main_delegate.cc 中定义如下:

    // contentpublicappcontent_main_delegate.cc

    class CONTENT_EXPORT ContentMainDelegate {
    public:
    virtual ~ContentMainDelegate() {}

    virtual bool BasicStartupComplete(int* exit_code);
    virtual void PreSandboxStartup() {}
    virtual void SandboxInitialized(const std::string& process_type) {}
    virtual int RunProcess(
    const std::string& process_type,
    const MainFunctionParams& main_function_params);
    virtual void ProcessExiting(const std::string& process_type) {}

    ......

    virtual void PreCreateMainMessageLoop() {}

    ......

    protected:
    friend class ContentClientInitializer;

    virtual ContentBrowserClient* CreateContentBrowserClient();
    virtual ContentGpuClient* CreateContentGpuClient();
    virtual ContentRendererClient* CreateContentRendererClient();
    virtual ContentUtilityClient* CreateContentUtilityClient();
    };

    可以看到,这里定义了一系列与启动相关的操作,并且通过几个 CreateXXX 的函数,获取 ContentBrowserClientContentRendererClient 等接口具体的实现,这也是 content API 的巧妙设计,通过这种方式,将浏览器的实现放入了 content 中。

    继续往下看,content::ContentMain() 中调用了 contentappcontent_main.cc 中的 service_manager::Main()

    // contentappcontent_main.cc

    int ContentMain(const ContentMainParams& params) {
    ContentServiceManagerMainDelegate delegate(params);
    service_manager::MainParams main_params(&delegate);
    #if !defined(OS_WIN) && !defined(OS_ANDROID)
    main_params.argc = params.argc;
    main_params.argv = params.argv;
    #endif
    return service_manager::Main(main_params);
    }

    在这里,使用一个 content::ContentServiceManagerMainDelegate 对象来构建了 main_params,并传入了 service_manager::Main()

    5、service_manager::Main 函数

    service_manager::Main 函数位于 servicesservice_managerembeddermain.cc,接收一个 MainParams 类型的参数,具体如下:

    // servicesservice_managerembeddermain.cc

    int Main(const MainParams& params) {
    MainDelegate* delegate = params.delegate;

    ......

    ProcessType process_type = delegate->OverrideProcessType();

    ......
    // A flag to indicate whether Main() has been called before. On Android, we
    // may re-run Main() without restarting the browser process. This flag
    // prevents initializing things more than once.
    static bool is_initialized = false;
    #if !defined(OS_ANDROID)
    DCHECK(!is_initialized);
    #endif
    if (!is_initialized) {
    is_initialized = true;

    ......

    #if defined(OS_WIN)
    base::win::RegisterInvalidParamHandler();
    ui::win::CreateATLModuleIfNeeded();
    #endif // defined(OS_WIN)

    ......

    base::CommandLine::Init(argc, argv);

    ......

    const auto& command_line = *base::CommandLine::ForCurrentProcess();

    #if defined(OS_WIN)
    base::win::SetupCRT(command_line);
    #endif

    MainDelegate::InitializeParams init_params;

    ......
    mojo::core::Init(mojo_config);

    ......

    exit_code = delegate->Initialize(init_params);

    ......

    }

    const auto& command_line = *base::CommandLine::ForCurrentProcess();
    if (process_type == ProcessType::kDefault) {
    std::string type_switch =
    command_line.GetSwitchValueASCII(switches::kProcessType);
    if (type_switch == switches::kProcessTypeServiceManager) {
    process_type = ProcessType::kServiceManager;
    } else if (type_switch == switches::kProcessTypeService) {
    process_type = ProcessType::kService;
    } else {
    process_type = ProcessType::kEmbedder;
    }
    }
    switch (process_type) {
    case ProcessType::kDefault:
    NOTREACHED();
    break;

    case ProcessType::kServiceManager:
    exit_code = RunServiceManager(delegate);
    break;

    case ProcessType::kService:
    CommonSubprocessInit();
    exit_code = RunService(delegate);
    break;

    case ProcessType::kEmbedder:
    if (delegate->IsEmbedderSubprocess())
    CommonSubprocessInit();
    exit_code = delegate->RunEmbedderProcess();
    break;
    }

    ......

    if (process_type == ProcessType::kEmbedder)
    delegate->ShutDownEmbedderProcess();

    return exit_code;
    }

    这里截取的代码比较长,也非常重要,我们主要关注这四个部分:

    • 根据传入的 delegate 和 command_line 决定进程的类型
    • 运行环境的初始化,比如 CreateATLModuleIfNeededSetupCRT 并用 is_initialized 来防止重复执行
    • 通过传入的 delegate 进行程序的初始化操作,delegate->Initialize(init_params)
    • 根据进程类型启动相应的工作

    这里的 delegate 类型为 service_manager::MainDelegate*,是在 services/service_manager/embedder/main_delegate.h 中定义的抽象类,在这里我们主要关注它的 InitializeRunEmbedderProcess 和 ShutDownEmbedderProcess,其中 Initialize 为被声明为纯虚函数,RunEmbedderProcess 和 ShutDownEmbedderProcess 又是什么都不做的,代码如下:

    // services/service_manager/embedder/main_delegate.h

    class COMPONENT_EXPORT(SERVICE_MANAGER_EMBEDDER) MainDelegate {
    public:
    // Perform early process initialization. Returns -1 if successful, or the exit
    // code with which the process should be terminated due to initialization
    // failure.
    virtual int Initialize(const InitializeParams& params) = 0;

    ......

    // Runs the embedder's own main process logic. Called exactly once after a
    // successful call to Initialize(), and only if the Service Manager core does
    // not know what to do otherwise -- i.e., if it is not starting a new Service
    // Manager instance or launching an embedded service.
    //
    // Returns the exit code to use when terminating the process after
    // RunEmbedderProcess() (and then ShutDown()) completes.
    virtual int RunEmbedderProcess();

    ......

    // Called just before process exit if RunEmbedderProcess() was called.
    virtual void ShutDownEmbedderProcess();
    // services/service_manager/embedder/main_delegate.cc

    int MainDelegate::RunEmbedderProcess() {
    return 0;
    }

    ...

    void MainDelegate::ShutDownEmbedderProcess() {}

    回到 service_manager::Main(),我们看到第一句 MainDelegate* delegate = params.delegate; 中的 params.delegate 就是前面在 content::ContentMain 中构建 main_params 所使用的 content::ContentServiceManagerMainDelegate 对象,因此,上述的三个函数 InitializeRunEmbedderProcessShutDownEmbedderProcess 是由 ContentServiceManagerMainDelegate 来最终实现的,来看代码:

    // contentappcontent_service_manager_main_delegate.cc

    int ContentServiceManagerMainDelegate::Initialize(
    const InitializeParams& params) {

    ......

    return content_main_runner_->Initialize(content_main_params_);
    }

    ......

    int ContentServiceManagerMainDelegate::RunEmbedderProcess() {
    return content_main_runner_->Run(start_service_manager_only_);
    }

    ......

    void ContentServiceManagerMainDelegate::ShutDownEmbedderProcess() {
    #if !defined(OS_ANDROID)
    content_main_runner_->Shutdown();
    #endif
    }

    在这三个函数的定义中,都使用了 content_main_runner_ 这个成员变量来具体执行,它的定义为 std::unique_ptr<ContentMainRunnerImpl>

    6、整个程序的Runner,content::ContentMainRunnerImpl

    这个 content::ContentMainRunnerImpl 是 content::ContentMainRunner 接口的一个实现,先来看接口的声明:

    // contentappcontent_main_runner_impl.h

    class CONTENT_EXPORT ContentMainRunner {
    public:
    virtual ~ContentMainRunner() {}

    // Create a new ContentMainRunner object.
    static ContentMainRunner* Create();

    // Initialize all necessary content state.
    virtual int Initialize(const ContentMainParams& params) = 0;

    // Perform the default run logic.
    virtual int Run(bool start_service_manager_only) = 0;

    // Shut down the content state.
    virtual void Shutdown() = 0;
    };

    再来看实现类的代码:

    // contentappcontent_main_runner_impl.h

    class ContentMainRunnerImpl : public ContentMainRunner {
    public:
    static ContentMainRunnerImpl* Create();

    ContentMainRunnerImpl();
    ~ContentMainRunnerImpl() override;

    int TerminateForFatalInitializationError();

    // ContentMainRunner:
    int Initialize(const ContentMainParams& params) override;
    int Run(bool start_service_manager_only) override;
    void Shutdown() override;

    ......

    }

    7、ContentMainRunner::Initialize() 函数

    先来看 Initialize 函数:

    // contentappcontent_main_runner_impl.cc

    int ContentMainRunnerImpl::Initialize(const ContentMainParams& params) {
    ui_task_ = params.ui_task;
    created_main_parts_closure_ = params.created_main_parts_closure;

    #if defined(OS_WIN)
    sandbox_info_ = *params.sandbox_info;
    #else // !OS_WIN

    ......

    is_initialized_ = true;
    delegate_ = params.delegate;

    ......

    int exit_code = 0;
    if (delegate_->BasicStartupComplete(&exit_code))
    return exit_code;
    completed_basic_startup_ = true;

    ......

    delegate_->PreSandboxStartup();
    #if defined(OS_WIN)
    if (!InitializeSandbox(
    service_manager::SandboxTypeFromCommandLine(command_line),
    params.sandbox_info))
    return TerminateForFatalInitializationError();
    #elif defined(OS_MACOSX)

    ......

    #endif

    delegate_->SandboxInitialized(process_type);

    ......

    // Return -1 to indicate no early termination.
    return -1;
    }

    大致看一下,在这个 Initialize 中,主要是根据 command_line 启动了相应的 sandbox service,并在启动前后都触发了 delegate_->PreSandboxStartup() 和 delegate_->SandboxInitialized(process_type),这个 delegate_ 来自于传入的 content::ContentMainParams 结构体,这个结构体是在 chrome_main.cc 中调用 content::ContentMain(params) 时所创建,所以这个 delegate_ 正是前面所提到的巧妙设计中,继承自 content::ContentMainDelegate 的 ChromeMainDelegate 对象,通过这一系列的调用,content 层就把创建 sandbox service 前后的事件触发了出来,具体实现者只要在 ChromeMainDelegate 中填充这两个时间点要做的事即可。

    8、进程入口,ContentMainRunner::Run() 函数

    再来看 Run 函数:

    // // contentappcontent_main_runner_impl.cc

    int ContentMainRunnerImpl::Run(bool start_service_manager_only) {

    ......

    const base::CommandLine& command_line =
    *base::CommandLine::ForCurrentProcess();
    std::string process_type =
    command_line.GetSwitchValueASCII(switches::kProcessType);

    ......

    MainFunctionParams main_params(command_line);
    main_params.ui_task = ui_task_;
    main_params.created_main_parts_closure = created_main_parts_closure_;

    ......

    if (process_type.empty())
    return RunServiceManager(main_params, start_service_manager_only);

    return RunOtherNamedProcessTypeMain(process_type, main_params, delegate_);
    }

    此处先判断 process_type 是否为空,为空则代表当前执行的是默认进程(一般情况下为 Browser 进程),则调用 RunServiceManager(),否则调用 RunOtherNamedProcessTypeMain 根据process_type 来执行相应的进程。先来看 RunServiceManager

    // contentappcontent_main_runner_impl.cc

    int ContentMainRunnerImpl::RunServiceManager(MainFunctionParams& main_params,
    bool start_service_manager_only) {

    ......

    if (!service_manager_context_) {

    ......

    delegate_->PreCreateMainMessageLoop();

    ......

    delegate_->PostEarlyInitialization(main_params.ui_task != nullptr);

    ......

    }

    if (should_start_service_manager_only)
    return -1;

    is_browser_main_loop_started_ = true;
    startup_data_ = std::make_unique<StartupDataImpl>();
    startup_data_->thread = std::move(service_manager_thread_);
    startup_data_->service_manager_context = service_manager_context_.get();
    main_params.startup_data = startup_data_.get();
    return RunBrowserProcessMain(main_params, delegate_);
    }

    同样,这里通过 delegate_ 做了一些操作之后,最后调用了 RunBrowserProcessMain() 函数,内容如下:

    // contentappcontent_main_runner_impl.cc

    int RunBrowserProcessMain(const MainFunctionParams& main_function_params,
    ContentMainDelegate* delegate) {
    int exit_code = delegate->RunProcess("", main_function_params);
    #if defined(OS_ANDROID)
    // In Android's browser process, the negative exit code doesn't mean the
    // default behavior should be used as the UI message loop is managed by
    // the Java and the browser process's default behavior is always
    // overridden.
    return exit_code;
    #else
    if (exit_code >= 0)
    return exit_code;
    return BrowserMain(main_function_params);
    #endif
    }

    非常简单明了,首先通过 delegate->RunProcess 把执行默认进程的优先权交由 Embedder 层,如果 Embedder 层成功执行了进程并最终返回了成功标志(exit_code >= 0),那么就退出函数;如果 Embedder 层对默认进程没有定义,就继续执行 content::BrowserMain,由此,Browser 进程开始执行。

    再来看 RunOtherNamedProcessTypeMain 函数:

    // contentappcontent_main_runner_impl.cc

    int RunOtherNamedProcessTypeMain(const std::string& process_type,
    const MainFunctionParams& main_function_params,
    ContentMainDelegate* delegate) {
    static const MainFunction kMainFunctions[] = {

    ......

    {switches::kUtilityProcess, UtilityMain},
    {switches::kRendererProcess, RendererMain},
    {switches::kGpuProcess, GpuMain},
    };

    for (size_t i = 0; i < base::size(kMainFunctions); ++i) {
    if (process_type == kMainFunctions[i].name) {
    int exit_code = delegate->RunProcess(process_type, main_function_params);
    if (exit_code >= 0)
    return exit_code;
    return kMainFunctions[i].function(main_function_params);
    }
    }

    ......

    // If it's a process we don't know about, the embedder should know.
    return delegate->RunProcess(process_type, main_function_params);
    }

    先建立了一个进程类型和入口函数指针的对应数组,再根据进程类型去具体执行,执行的过程与 Browser 进程一样,先通过 delegate->RunProcess 交由 Embedder 层处理,如果未处理再调用默认的进程入口函数,可以看到分别提供了 UtilityMainRendererMainGpuMain 这三个进程的入口,其中 RendererMain 则是我们关注的 Renderer 进程的入口函数,Renderer 进程从此处开始执行。最后一句,如果进程类型不在以上范围内,则交由 Embedder 去处理。

    9、程序结束

    void ContentMainRunnerImpl::Shutdown() {
    DCHECK(is_initialized_);
    DCHECK(!is_shutdown_);

    if (completed_basic_startup_) {
    const base::CommandLine& command_line =
    *base::CommandLine::ForCurrentProcess();
    std::string process_type =
    command_line.GetSwitchValueASCII(switches::kProcessType);

    delegate_->ProcessExiting(process_type);
    }

    #if !defined(CHROME_MULTIPLE_DLL_CHILD)
    // The BrowserTaskExecutor needs to be destroyed before |exit_manager_|.
    BrowserTaskExecutor::Shutdown();
    #endif // !defined(CHROME_MULTIPLE_DLL_CHILD)

    #if defined(OS_WIN)
    #ifdef _CRTDBG_MAP_ALLOC
    _CrtDumpMemoryLeaks();
    #endif // _CRTDBG_MAP_ALLOC
    #endif // OS_WIN

    exit_manager_.reset(nullptr);

    delegate_ = nullptr;
    is_shutdown_ = true;
    }

    首先通过 delegate_->ProcessExiting(process_type) 通知 Embedder 层处理,然后做了一些善后释放的工作,最后将 is_shutdown_ 标记置为 true

    10、总结

    前面分析了这么多,其实结合类图来看一下还是很简单明了的,主要起到作用的就是图中标红的三个,service_manager::Main 通过 content::ContentServiceManagerMainDelegate 的实例调用了 content::ContentMainRunnerImpl 实例中的 Initialize()Run()Shutdown() 函数,而在这个Runner中,又通过 content::ContentMainDelegate 接口指针调用到了由 Embedder 层创建的 ChromeMainDelegate 实例中的函数,由此完成了程序的启动以及 Content 层对 Embedder 的交互。

  • 相关阅读:
    [轉]windows下mysql 启动 mysqlbinlog二进制日志文件
    [轉]MySQL创建、删除、重建和查看索引命令
    [轉]PHP权限控制系统PHPGACL
    [轉]mysql5存储过程语法
    Web Application Stress Tool(WAS) & SQLIOSim
    information_schema資料庫表信息
    [轉]MySQL系统变量应用探究
    [轉]httping 1.5.2 发布,HTTP连接响应测试
    [轉]批处理命令手册
    Google Native Client介紹
  • 原文地址:https://www.cnblogs.com/bigben0123/p/14001779.html
Copyright © 2011-2022 走看看