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

1、main() 函数

Chromium的main函数在 ​​chrome\app\chrome_exe_main_win.cc​​,具体如下:


// chrome\app\chrome_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()​​ 函数,这是一个静态函数,在​​chrome\app\main_dll_loader.cc​​ 中,内容如下:


// chrome\app\main_dll_loader.cc

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



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


// chrome\app\main_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​​ 层,定义在 ​​chrome\app\chrome_main.cc​​ 中,内容如下:


// chrome\app\chrome_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​​ 层的具体实现信息,此结构体在 ​​content\public\app\content_main.h​​ 中定义如下:


// content\public\app\content_main.h

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

ContentMainDelegate* delegate;

......



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


// content\public\app\content_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​​ 的函数,获取 ​​ContentBrowserClient​​、​​ContentRendererClient​​ 等接口具体的实现,这也是 ​​content API​​ 的巧妙设计,通过这种方式,将浏览器的实现放入了 ​​content​​ 中。

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


// content\app\content_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​​ 函数位于 ​​services\service_manager\embedder\main.cc​​,接收一个 ​​MainParams​​ 类型的参数,具体如下:


// services\service_manager\embedder\main.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​​ 决定进程的类型
  • 运行环境的初始化,比如 ​​CreateATLModuleIfNeeded​​,​​SetupCRT​​ 并用 ​​is_initialized​​ 来防止重复执行
  • 通过传入的 ​​delegate​​ 进行程序的初始化操作,​​delegate->Initialize(init_params)​
  • 根据进程类型启动相应的工作

这里的 ​​delegate​​ 类型为 ​​service_manager::MainDelegate*​​,是在 ​​services/service_manager/embedder/main_delegate.h​​ 中定义的抽象类,在这里我们主要关注它的 ​​Initialize​​、​​RunEmbedderProcess​​ 和 ​​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​​ 对象,因此,上述的三个函数 ​​Initialize​​、​​RunEmbedderProcess​​、​​ShutDownEmbedderProcess​​ 是由 ​​ContentServiceManagerMainDelegate​​ 来最终实现的,来看代码:


// content\app\content_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​​ 接口的一个实现,先来看接口的声明:


// content\app\content_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;
};



再来看实现类的代码:


// content\app\content_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​​ 函数:


// content\app\content_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​​ 函数:


// // content\app\content_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​​:


// content\app\content_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()​​ 函数,内容如下:


// content\app\content_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​​ 函数:


// content\app\content_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​​ 层处理,如果未处理再调用默认的进程入口函数,可以看到分别提供了 ​​UtilityMain​​、​​RendererMain​​、​​GpuMain​​ 这三个进程的入口,其中 ​​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、总结

Chromium学习笔记:程序启动入口分析(Windows)_#if

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