这里研究和分析一下chromium启动的初步,浅析一下。
我们先从整体看一下,普通情况下,chromium的主进程主线程的运行情况,看一下栈路径
0:000> kL
# Child-SP RetAddr Call Site
00 00000000`002ef1c8 000007fe`fd8c1420 ntdll!NtWaitForMultipleObjects+0xa
01 00000000`002ef1d0 00000000`76c12cf3 KERNELBASE!WaitForMultipleObjectsEx+0xe8
02 00000000`002ef2d0 00000000`77098f7d kernel32!WaitForMultipleObjectsExImplementation+0xb3
03 00000000`002ef360 00000000`770962b2 USER32!RealMsgWaitForMultipleObjectsEx+0x12a
04 00000000`002ef400 000007fe`ec2b1c9c USER32!MsgWaitForMultipleObjectsEx+0x46
05 00000000`002ef440 000007fe`ec2b1b11 chrome_7feec210000!base::MessagePumpForUI::WaitForWork+0x2c
06 00000000`002ef4b0 000007fe`ec2b1732 chrome_7feec210000!base::MessagePumpForUI::DoRunLoop+0xe1
07 00000000`002ef520 000007fe`ec29dd83 chrome_7feec210000!base::MessagePumpWin::Run+0x42
08 (Inline Function) --------`-------- chrome_7feec210000!base::MessageLoop::RunHandler+0x15
09 00000000`002ef560 000007fe`ecb5b8a8 chrome_7feec210000!base::RunLoop::Run+0x83
0a 00000000`002ef5b0 000007fe`ed33f870 chrome_7feec210000!ChromeBrowserMainParts::MainMessageLoopRun+0xbc
0b 00000000`002ef630 000007fe`ed33b993 chrome_7feec210000!content::BrowserMainLoop::RunMainMessageLoopParts+0x74
0c 00000000`002ef680 000007fe`ed2e3c15 chrome_7feec210000!content::BrowserMainRunnerImpl::Run+0x17
0d 00000000`002ef6b0 000007fe`ecbf17d6 chrome_7feec210000!content::BrowserMain+0x101
0e 00000000`002ef730 000007fe`ecbf1613 chrome_7feec210000!content::RunNamedProcessTypeMain+0x18e
0f 00000000`002ef8a0 000007fe`ecbeeae1 chrome_7feec210000!content::ContentMainRunnerImpl::Run+0x93
10 00000000`002ef930 000007fe`ecae1c7e chrome_7feec210000!content::ContentMain+0x35
11 00000000`002ef960 00000001`3ffa0f6f chrome_7feec210000!ChromeMain+0x82
12 00000000`002ef9f0 00000001`3ffa01b0 chrome!MainDllLoader::Launch+0x317
13 00000000`002efb10 00000001`3ffde018 chrome!wWinMain+0x234
14 00000000`002efd30 00000000`76c0652d chrome!__tmainCRTStartup+0x148
15 00000000`002efd70 00000000`772fc521 kernel32!BaseThreadInitThunk+0xd
16 00000000`002efda0 00000000`00000000 ntdll!RtlUserThreadStart+0x1d
一般情况下,在chromium的目录结构中,位于*\app文件夹中的文件基本上都是模块的启动代码文件。我们从进程启动处看。其位于chrome_exe_main_win.cc文件中,位于chrome\app的文件夹根目录里。
#if !defined(WIN_CONSOLE_APP)
int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prev, wchar_t*, int) {
#else
int main() {
HINSTANCE instance = GetModuleHandle(nullptr);
#endif
// Initialize the CommandLine singleton from the environment.
base::CommandLine::Init(0, nullptr);
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
const std::string process_type =
command_line->GetSwitchValueASCII(switches::kProcessType);
startup_metric_utils::InitializePreReadOptions(
BrowserDistribution::GetDistribution()->GetRegistryPath());
// Confirm that an explicit prefetch profile is used for all process types
// except for the browser process. Any new process type will have to assign
// itself a prefetch id. See kPrefetchArgument* constants in
// content_switches.cc for details.
DCHECK(!startup_metric_utils::GetPreReadOptions().use_prefetch_argument ||
process_type.empty() ||
HasValidWindowsPrefetchArgument(*command_line));
if (process_type == crash_reporter::switches::kCrashpadHandler) {
return crash_reporter::RunAsCrashpadHandler(
*base::CommandLine::ForCurrentProcess());
}
crash_reporter::SetCrashReporterClient(g_chrome_crash_client.Pointer());
crash_reporter::InitializeCrashpadWithEmbeddedHandler(process_type.empty(),
process_type);
SwitchToLFHeap();
startup_metric_utils::RecordExeMainEntryPointTime(base::Time::Now());
// Signal Chrome Elf that Chrome has begun to start.
SignalChromeElf();
// The exit manager is in charge of calling the dtors of singletons.
base::AtExitManager exit_manager;
// We don't want to set DPI awareness on pre-Win7 because we don't support
// DirectWrite there. GDI fonts are kerned very badly, so better to leave
// DPI-unaware and at effective 1.0. See also ShouldUseDirectWrite().
if (base::win::GetVersion() >= base::win::VERSION_WIN7)
EnableHighDPISupport();
if (AttemptFastNotify(*command_line))
return 0;
// Load and launch the chrome dll. *Everything* happens inside.
VLOG(1) << "About to load main DLL.";
MainDllLoader* loader = MakeMainDllLoader();
int rc = loader->Launch(instance);
loader->RelaunchChromeBrowserWithNewCommandLineIfNeeded();
delete loader;
return rc;
进程启动,进行了一系列的设置,主要的设置都是出于chrome顶级的级别,即最开始要处理的事情,这里获取进程命令行,启动crashpad进程,或者如果是crashpad进程,我们流向crashpad处理。等等的之后,创建主DLL加载类,使用MainDllLoader的Launch来做进一步的启动
// Launching is a matter of loading the right dll and calling the entry point.
// Derived classes can add custom code in the OnBeforeLaunch callback.
int MainDllLoader::Launch(HINSTANCE instance) {
const base::CommandLine& cmd_line = *base::CommandLine::ForCurrentProcess();
process_type_ = cmd_line.GetSwitchValueASCII(switches::kProcessType);
base::FilePath file;
if (process_type_ == switches::kWatcherProcess) {
chrome::RegisterPathProvider();
base::win::ScopedHandle parent_process;
base::win::ScopedHandle on_initialized_event;
DWORD main_thread_id = 0;
if (!InterpretChromeWatcherCommandLine(cmd_line, &parent_process,
&main_thread_id,
&on_initialized_event)) {
return chrome::RESULT_CODE_UNSUPPORTED_PARAM;
}
base::FilePath watcher_data_directory;
if (!PathService::Get(chrome::DIR_WATCHER_DATA, &watcher_data_directory))
return chrome::RESULT_CODE_MISSING_DATA;
base::string16 channel_name = GoogleUpdateSettings::GetChromeChannel(
!InstallUtil::IsPerUserInstall(cmd_line.GetProgram()));
// Intentionally leaked.
HMODULE watcher_dll = Load(&file);
if (!watcher_dll)
return chrome::RESULT_CODE_MISSING_DATA;
ChromeWatcherMainFunction watcher_main =
reinterpret_cast<ChromeWatcherMainFunction>(
::GetProcAddress(watcher_dll, kChromeWatcherDLLEntrypoint));
return watcher_main(
chrome::kBrowserExitCodesRegistryPath, parent_process.Take(),
main_thread_id, on_initialized_event.Take(),
watcher_data_directory.value().c_str(), channel_name.c_str());
}
// Initialize the sandbox services.
sandbox::SandboxInterfaceInfo sandbox_info = {0};
content::InitializeSandboxInfo(&sandbox_info);
dll_ = Load(&file);
if (!dll_)
return chrome::RESULT_CODE_MISSING_DATA;
OnBeforeLaunch(process_type_, file);
DLL_MAIN chrome_main =
reinterpret_cast<DLL_MAIN>(::GetProcAddress(dll_, "ChromeMain"));
int rc = chrome_main(instance, &sandbox_info);
rc = OnBeforeExit(rc, file);
return rc;
}
这个过程依旧比较简洁,分两个部分,根据命令行,判断是启动的是watcher进程还是主进程,如果是watcher进程,继续watcher进程的处理,如果是主进程,那么Load加载主dll,获取ChromeMain函数地址,调用ChromeMain函数。
接着开始是chrome级别的启动过程
#if defined(OS_WIN)
DLLEXPORT int __cdecl ChromeMain(HINSTANCE instance,
sandbox::SandboxInterfaceInfo* sandbox_info) {
#elif defined(OS_POSIX)
int ChromeMain(int argc, const char** argv) {
#endif
#if defined(OS_WIN) && defined(ARCH_CPU_X86_64)
// VS2013 only checks the existence of FMA3 instructions, not the enabled-ness
// of them at the OS level (this is fixed in VS2015). We force off usage of
// FMA3 instructions in the CRT to avoid using that path and hitting illegal
// instructions when running on CPUs that support FMA3, but OSs that don't.
// See http://crbug.com/436603.
_set_FMA3_enable(0);
#endif // WIN && ARCH_CPU_X86_64
ChromeMainDelegate chrome_main_delegate;
content::ContentMainParams params(&chrome_main_delegate);
#if defined(OS_WIN)
// The process should crash when going through abnormal termination.
base::win::SetShouldCrashOnProcessDetach(true);
base::win::SetAbortBehaviorForCrashReporting();
params.instance = instance;
params.sandbox_info = sandbox_info;
// SetDumpWithoutCrashingFunction must be passed the DumpProcess function
// from the EXE and not from the DLL in order for DumpWithoutCrashing to
// function correctly.
typedef void (__cdecl *DumpProcessFunction)();
DumpProcessFunction DumpProcess = reinterpret_cast<DumpProcessFunction>(
::GetProcAddress(::GetModuleHandle(chrome::kBrowserProcessExecutableName),
"DumpProcessWithoutCrash"));
base::debug::SetDumpWithoutCrashingFunction(DumpProcess);
#else
params.argc = argc;
params.argv = argv;
#endif
#if BUILDFLAG(ENABLE_PACKAGE_MASH_SERVICES)
#if !defined(OS_WIN)
base::CommandLine::Init(params.argc, params.argv);
#endif
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
// TODO(sky): only do this for dev builds and if on canary channel.
if (command_line.HasSwitch("mash"))
return MashMain();
#endif
int rv = content::ContentMain(params);
#if defined(OS_WIN)
base::win::SetShouldCrashOnProcessDetach(false);
#endif
return rv;
}
在这里,windows情况下,先这是无crash下的dump函数然后获取命令行,之后调用ContentMain,进行Content模块的初始化。
int ContentMain(const ContentMainParams& params) {
scoped_ptr<ContentMainRunner> main_runner(ContentMainRunner::Create());
int exit_code = main_runner->Initialize(params);
if (exit_code >= 0)
return exit_code;
exit_code = main_runner->Run();
main_runner->Shutdown();
return exit_code;
}
ContentMain比较简洁,其主要执行都位于Initialize和Run函数中。intiialize负责content这个级别的初始化操作,主要是根据命令行的一些开关命令,做初始化操作,配置TraceConfig等等。
ContentMain中实际的工作都由Run函数来具体的操作。
int Run() override {
DCHECK(is_initialized_);
DCHECK(!is_shutdown_);
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_;
#if defined(OS_WIN)
main_params.sandbox_info = &sandbox_info_;
#elif defined(OS_MACOSX)
main_params.autorelease_pool = autorelease_pool_.get();
#endif
#if !defined(OS_IOS)
return RunNamedProcessTypeMain(process_type, main_params, delegate_);
#else
return 1;
#endif
}
这里记录沙箱信息,以及获取我们要启动的进程类型,因为chrome.exe是一个壳,用来分别启动不同的进程,一套代码依据不同的命令行,启动不同的进程,在wWinMain中启动watcher和crashpad进程,而在这里依据不同的进程类型,使用RunNamedProcessTypeMain来具体的去执行不同的操作。
// Run the FooMain() for a given process type.
// If |process_type| is empty, runs BrowserMain().
// Returns the exit code for this process.
int RunNamedProcessTypeMain(
const std::string& process_type,
const MainFunctionParams& main_function_params,
ContentMainDelegate* delegate) {
static const MainFunction kMainFunctions[] = {
#if !defined(CHROME_MULTIPLE_DLL_CHILD)
{ "", BrowserMain },
#endif
#if !defined(CHROME_MULTIPLE_DLL_BROWSER)
#if defined(ENABLE_PLUGINS)
#if !defined(OS_LINUX)
{ switches::kPluginProcess, PluginMain },
#endif
{ switches::kPpapiPluginProcess, PpapiPluginMain },
{ switches::kPpapiBrokerProcess, PpapiBrokerMain },
#endif // ENABLE_PLUGINS
{ switches::kUtilityProcess, UtilityMain },
{ switches::kRendererProcess, RendererMain },
{ switches::kGpuProcess, GpuMain },
#if defined(OS_ANDROID)
{ switches::kDownloadProcess, DownloadMain},
#endif
#endif // !CHROME_MULTIPLE_DLL_BROWSER
};
RegisterMainThreadFactories();
for (size_t i = 0; i < arraysize(kMainFunctions); ++i) {
if (process_type == kMainFunctions[i].name) {
if (delegate) {
int exit_code = delegate->RunProcess(process_type,
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.
if (process_type.empty())
return exit_code;
#endif
if (exit_code >= 0)
return exit_code;
}
return kMainFunctions[i].function(main_function_params);
}
}
#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
// Zygote startup is special -- see RunZygote comments above
// for why we don't use ZygoteMain directly.
if (process_type == switches::kZygoteProcess)
return RunZygote(main_function_params, delegate);
#endif
// If it's a process we don't know about, the embedder should know.
if (delegate)
return delegate->RunProcess(process_type, main_function_params);
NOTREACHED() << "Unknown process type: " << process_type;
return 1;
}
函数中,在函数头部,我们可以看到几个模块的主入口,BrowserMain,GpuMain,RendererMain,等等我们常见的几个进程。这个函数其实比较简单,根据参数里的进程类型,查找列表,找到对应的进程的Main函数。这里我们主要关心主进程,即BrowserMain。
类似于ContentMain,其也会包装一个BrowserMainRunner来做具体的事务
// Main routine for running as the Browser process.
int BrowserMain(const MainFunctionParams& parameters) {
ScopedBrowserMainEvent scoped_browser_main_event;
base::trace_event::TraceLog::GetInstance()->SetProcessName("Browser");
base::trace_event::TraceLog::GetInstance()->SetProcessSortIndex(
kTraceEventBrowserProcessSortIndex);
scoped_ptr<BrowserMainRunner> main_runner(BrowserMainRunner::Create());
int exit_code = main_runner->Initialize(parameters);
if (exit_code >= 0)
return exit_code;
exit_code = main_runner->Run();
main_runner->Shutdown();
return exit_code;
}
从上面的函数中我们可以看出,这里主要分成两部分,一个是initialize,一部分是run函数。我们重点分析initialize函数,run函数主要用来browser进程主线程的消息处理。
int Initialize(const MainFunctionParams& parameters) override {
SCOPED_UMA_HISTOGRAM_LONG_TIMER(
"Startup.BrowserMainRunnerImplInitializeLongTime");
// TODO(vadimt, yiyaoliu): Remove all tracked_objects references below once
// crbug.com/453640 is fixed.
tracked_objects::ThreadData::InitializeThreadContext("CrBrowserMain");
TRACK_SCOPED_REGION(
"Startup", "BrowserMainRunnerImpl::Initialize");
TRACE_EVENT0("startup", "BrowserMainRunnerImpl::Initialize");
// On Android we normally initialize the browser in a series of UI thread
// tasks. While this is happening a second request can come from the OS or
// another application to start the browser. If this happens then we must
// not run these parts of initialization twice.
if (!initialization_started_) {
initialization_started_ = true;
const base::TimeTicks start_time_step1 = base::TimeTicks::Now();
SkGraphics::Init();
#if !defined(OS_IOS)
if (parameters.command_line.HasSwitch(switches::kWaitForDebugger))
base::debug::WaitForDebugger(60, true);
#endif
#if defined(OS_WIN)
if (base::win::GetVersion() < base::win::VERSION_VISTA) {
// When "Extend support of advanced text services to all programs"
// (a.k.a. Cicero Unaware Application Support; CUAS) is enabled on
// Windows XP and handwriting modules shipped with Office 2003 are
// installed, "penjpn.dll" and "skchui.dll" will be loaded and then
// crash unless a user installs Office 2003 SP3. To prevent these
// modules from being loaded, disable TSF entirely. crbug.com/160914.
// TODO(yukawa): Add a high-level wrapper for this instead of calling
// Win32 API here directly.
ImmDisableTextFrameService(static_cast<DWORD>(-1));
}
#endif // OS_WIN
base::StatisticsRecorder::Initialize();
notification_service_.reset(new NotificationServiceImpl);
#if defined(OS_WIN)
// Ole must be initialized before starting message pump, so that TSF
// (Text Services Framework) module can interact with the message pump
// on Windows 8 Metro mode.
ole_initializer_.reset(new ui::ScopedOleInitializer);
// Enable DirectWrite font rendering if needed.
gfx::win::MaybeInitializeDirectWrite();
#endif // OS_WIN
main_loop_.reset(new BrowserMainLoop(parameters));
main_loop_->Init();
main_loop_->EarlyInitialization();
// Must happen before we try to use a message loop or display any UI.
if (!main_loop_->InitializeToolkit())
return 1;
main_loop_->PreMainMessageLoopStart();
main_loop_->MainMessageLoopStart();
main_loop_->PostMainMessageLoopStart();
// WARNING: If we get a WM_ENDSESSION, objects created on the stack here
// are NOT deleted. If you need something to run during WM_ENDSESSION add it
// to browser_shutdown::Shutdown or BrowserProcess::EndSession.
ui::InitializeInputMethod();
UMA_HISTOGRAM_TIMES("Startup.BrowserMainRunnerImplInitializeStep1Time",
base::TimeTicks::Now() - start_time_step1);
}
const base::TimeTicks start_time_step2 = base::TimeTicks::Now();
main_loop_->CreateStartupTasks();
int result_code = main_loop_->GetResultCode();
if (result_code > 0)
return result_code;
UMA_HISTOGRAM_TIMES("Startup.BrowserMainRunnerImplInitializeStep2Time",
base::TimeTicks::Now() - start_time_step2);
// Return -1 to indicate no early termination.
return -1;
}
此函数开始处做了一定的初始化操作,设置文本,设置StatisticsRecorder以及OLE的操作,,可是这些都不是重点,重点是其初始化BrowserMainLoop。这个类里面有比较实际的线程进程初始化的操作。
这是由BrowserMainLoop类引发的。
void BrowserMainLoop::MainMessageLoopStart() {
// DO NOT add more code here. Use PreMainMessageLoopStart() above or
// PostMainMessageLoopStart() below.
TRACE_EVENT0("startup", "BrowserMainLoop::MainMessageLoopStart");
TRACK_SCOPED_REGION("Startup", "BrowserMainLoop::MainMessageLoopStart");
// Create a MessageLoop if one does not already exist for the current thread.
if (!base::MessageLoop::current())
main_message_loop_.reset(new base::MessageLoopForUI);
InitializeMainThread();
}
这里是主消息循环的启动部分,从这个函数里首先为线程创建UI循环泵,然后初始化主线程。
void BrowserMainLoop::InitializeMainThread() {
TRACE_EVENT0("startup", "BrowserMainLoop::InitializeMainThread");
static const char kThreadName[] = "CrBrowserMain";
base::PlatformThread::SetName(kThreadName);
if (main_message_loop_)
main_message_loop_->set_thread_name(kThreadName);
// Register the main thread by instantiating it, but don't call any methods.
main_thread_.reset(
new BrowserThreadImpl(BrowserThread::UI, base::MessageLoop::current()));
}
BrowserMainLoop* BrowserMainLoop::GetInstance() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
return g_current_browser_main_loop;
}
初始化主线程,设置主线程名,然后创建线程管理,记录线程对象。这里比较重要的全局类实例就是g_current_browser_main_loop了,这是浏览器主进程CrBrowserMain线程的主循环实例。
我们可以通过windbg查看这一数据。
0:101> x chrome_7feef2b0000!*::g_current_browser_main_loop
000007fe`f1f34518 chrome_7feef2b0000!content::g_current_browser_main_loop = 0x00000000`0051f8f0
0:101> dx -id 0,0 -r1 (*((chrome_7feef2b0000!content::BrowserMainLoop *)0x51f8f0))
(*((chrome_7feef2b0000!content::BrowserMainLoop *)0x51f8f0)) [Type: content::BrowserMainLoop]
[+0x008] parameters_ : 0x30f558 [Type: content::MainFunctionParams &]
[+0x010] parsed_command_line_ : 0x4ddba0 [Type: base::CommandLine &]
[+0x018] result_code_ : 0
[+0x01c] created_threads_ : true
......
我们回到BrowserMainRunner的Initialize继续向下看,还有一个重要的地方,那就是CreateStartupTasks,创建启动任务。
void BrowserMainLoop::CreateStartupTasks() {
TRACE_EVENT0("startup", "BrowserMainLoop::CreateStartupTasks");
TRACK_SCOPED_REGION("Startup", "BrowserMainLoop::CreateStartupTasks");
// First time through, we really want to create all the tasks
if (!startup_task_runner_.get()) {
#if defined(OS_ANDROID)
startup_task_runner_ = make_scoped_ptr(
new StartupTaskRunner(base::Bind(&BrowserStartupComplete),
base::ThreadTaskRunnerHandle::Get()));
#else
startup_task_runner_ = make_scoped_ptr(
new StartupTaskRunner(base::Callback<void(int)>(),
base::ThreadTaskRunnerHandle::Get()));
#endif
StartupTask pre_create_threads =
base::Bind(&BrowserMainLoop::PreCreateThreads, base::Unretained(this));
startup_task_runner_->AddTask(pre_create_threads);
StartupTask create_threads =
base::Bind(&BrowserMainLoop::CreateThreads, base::Unretained(this));
startup_task_runner_->AddTask(create_threads);
StartupTask browser_thread_started = base::Bind(
&BrowserMainLoop::BrowserThreadsStarted, base::Unretained(this));
startup_task_runner_->AddTask(browser_thread_started);
StartupTask pre_main_message_loop_run = base::Bind(
&BrowserMainLoop::PreMainMessageLoopRun, base::Unretained(this));
startup_task_runner_->AddTask(pre_main_message_loop_run);
#if defined(OS_ANDROID)
if (BrowserMayStartAsynchronously()) {
startup_task_runner_->StartRunningTasksAsync();
}
#endif
}
#if defined(OS_ANDROID)
if (!BrowserMayStartAsynchronously()) {
// A second request for asynchronous startup can be ignored, so
// StartupRunningTasksAsync is only called first time through. If, however,
// this is a request for synchronous startup then it must override any
// previous call for async startup, so we call RunAllTasksNow()
// unconditionally.
startup_task_runner_->RunAllTasksNow();
}
#else
startup_task_runner_->RunAllTasksNow();
#endif
}
这是一个创建工作线程的函数。分别使用PreCreateThreads,CreateThreads,BrowserThreadsStarted,PreMainMessageLoopRun来做具体的线程创建操作。
我们重点分析CreateThreads函数内部。
int BrowserMainLoop::CreateThreads() {
TRACE_EVENT0("startup", "BrowserMainLoop::CreateThreads");
TRACK_SCOPED_REGION("Startup", "BrowserMainLoop::CreateThreads");
base::Thread::Options io_message_loop_options;
io_message_loop_options.message_loop_type = base::MessageLoop::TYPE_IO;
base::Thread::Options ui_message_loop_options;
ui_message_loop_options.message_loop_type = base::MessageLoop::TYPE_UI;
for (size_t thread_id = BrowserThread::UI + 1;
thread_id < BrowserThread::ID_COUNT;
++thread_id) {
scoped_ptr<BrowserProcessSubThread>* thread_to_start = NULL;
base::Thread::Options options;
switch (thread_id) {
case BrowserThread::DB:
TRACE_EVENT_BEGIN1("startup",
"BrowserMainLoop::CreateThreads:start",
"Thread", "BrowserThread::DB");
thread_to_start = &db_thread_;
options.timer_slack = base::TIMER_SLACK_MAXIMUM;
break;
case BrowserThread::FILE_USER_BLOCKING:
TRACE_EVENT_BEGIN1("startup",
"BrowserMainLoop::CreateThreads:start",
"Thread", "BrowserThread::FILE_USER_BLOCKING");
thread_to_start = &file_user_blocking_thread_;
break;
case BrowserThread::FILE:
TRACE_EVENT_BEGIN1("startup",
"BrowserMainLoop::CreateThreads:start",
"Thread", "BrowserThread::FILE");
thread_to_start = &file_thread_;
#if defined(OS_WIN)
// On Windows, the FILE thread needs to be have a UI message loop
// which pumps messages in such a way that Google Update can
// communicate back to us.
options = ui_message_loop_options;
#else
options = io_message_loop_options;
#endif
options.timer_slack = base::TIMER_SLACK_MAXIMUM;
break;
case BrowserThread::PROCESS_LAUNCHER:
TRACE_EVENT_BEGIN1("startup",
"BrowserMainLoop::CreateThreads:start",
"Thread", "BrowserThread::PROCESS_LAUNCHER");
thread_to_start = &process_launcher_thread_;
options.timer_slack = base::TIMER_SLACK_MAXIMUM;
break;
case BrowserThread::CACHE:
TRACE_EVENT_BEGIN1("startup",
"BrowserMainLoop::CreateThreads:start",
"Thread", "BrowserThread::CACHE");
thread_to_start = &cache_thread_;
#if defined(OS_WIN)
options = io_message_loop_options;
#endif // defined(OS_WIN)
options.timer_slack = base::TIMER_SLACK_MAXIMUM;
break;
case BrowserThread::IO:
TRACE_EVENT_BEGIN1("startup",
"BrowserMainLoop::CreateThreads:start",
"Thread", "BrowserThread::IO");
thread_to_start = &io_thread_;
options = io_message_loop_options;
break;
case BrowserThread::UI:
case BrowserThread::ID_COUNT:
default:
NOTREACHED();
break;
}
BrowserThread::ID id = static_cast<BrowserThread::ID>(thread_id);
if (thread_to_start) {
(*thread_to_start).reset(new BrowserProcessSubThread(id));
if (!(*thread_to_start)->StartWithOptions(options)) {
LOG(FATAL) << "Failed to start the browser thread: id == " << id;
}
} else {
NOTREACHED();
}
TRACE_EVENT_END0("startup", "BrowserMainLoop::CreateThreads:start");
}
created_threads_ = true;
return result_code_;
}
这里创建线程,线程类对象是BrowserProcessSubThread,其继承自Thread,StartWithOptions用来启动线程,内部封装了win32线程启动函数.
我们可以查看头文件,规整的很好。如下所示,我们可以清晰的看到每个函数都做了那些操作,初始化了那些线程。
// Members initialized in |Init()| -------------------------------------------
// Destroy |parts_| before |main_message_loop_| (required) and before other
// classes constructed in content (but after |main_thread_|).
scoped_ptr<BrowserMainParts> parts_;
// Members initialized in |InitializeMainThread()| ---------------------------
// This must get destroyed before other threads that are created in |parts_|.
scoped_ptr<BrowserThreadImpl> main_thread_;
// Members initialized in |CreateStartupTasks()| -----------------------------
scoped_ptr<StartupTaskRunner> startup_task_runner_;
// Members initialized in |PreCreateThreads()| -------------------------------
// Torn down in ShutdownThreadsAndCleanUp.
scoped_ptr<base::MemoryPressureMonitor> memory_pressure_monitor_;
// Members initialized in |CreateThreads()| ----------------------------------
scoped_ptr<BrowserProcessSubThread> db_thread_;
scoped_ptr<BrowserProcessSubThread> file_user_blocking_thread_;
scoped_ptr<BrowserProcessSubThread> file_thread_;
scoped_ptr<BrowserProcessSubThread> process_launcher_thread_;
scoped_ptr<BrowserProcessSubThread> cache_thread_;
scoped_ptr<BrowserProcessSubThread> io_thread_;
// Members initialized in |BrowserThreadsStarted()| --------------------------
scoped_ptr<base::Thread> indexed_db_thread_;
scoped_ptr<MojoShellContext> mojo_shell_context_;
scoped_ptr<IPC::ScopedIPCSupport> mojo_ipc_support_;