chromium WinMain

入口函数

这里研究和分析一下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

wWinMain

一般情况下,在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_main

接着开始是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模块的初始化。

ContentMain

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。

BrowserMain

Main入口

类似于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进程主线程的消息处理。

Initialize

  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。这个类里面有比较实际的线程进程初始化的操作。

MainMessageLoopStart

这是由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
    ......

CreateStartupTasks

我们回到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_;
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值