注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

写着玩

Bob

 
 
 

日志

 
 
 
 

Chrome的启动流程 之二  

2009-12-23 22:55:19|  分类: Chrome |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

本文主要分析chrome.dll中的ChromeMain函数。

DLLEXPORT int __cdecl ChromeMain(HINSTANCE instance,
                                 sandbox::SandboxInterfaceInfo* sandbox_info,
                                 TCHAR* command_line) {
#elif defined(OS_POSIX)
int ChromeMain(int argc, const char** argv) {
#endif
#if defined(OS_MACOSX)
  // If Breakpad is not present then turn off os crash dumps so we don't have
  // to wait eons for Apple's Crash Reporter to generate a dump.
  if (IsCrashReporterDisabled()) {
    DebugUtil::DisableOSCrashDumps();
  }
#endif
  RegisterInvalidParamHandler();
  // The exit manager is in charge of calling the dtors of singleton objects.
  base::AtExitManager exit_manager;
  // We need this pool for all the objects created before we get to the
  // event loop, but we don't want to leave them hanging around until the
  // app quits. Each "main" needs to flush this pool right before it goes into
  // its main event loop to get rid of the cruft.
  base::ScopedNSAutoreleasePool autorelease_pool;
#if defined(OS_POSIX)
  base::GlobalDescriptors* g_fds = Singleton<base::GlobalDescriptors>::get();
  g_fds->Set(kPrimaryIPCChannel,
             kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor);
#if defined(OS_LINUX)
  g_fds->Set(kCrashDumpSignal,
             kCrashDumpSignal + base::GlobalDescriptors::kBaseDescriptor);
#endif
#endif
  // Initialize the command line.
#if defined(OS_WIN)
  CommandLine::Init(0, NULL);
#else
  CommandLine::Init(argc, argv);
#endif
#if defined(OS_MACOSX)
  // Needs to be called after CommandLine::Init().
  InitCrashProcessInfo();
#endif
  const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
#if defined(OS_WIN)
  // Must do this before any other usage of command line!
  if (HasDeprecatedArguments(parsed_command_line.command_line_string()))
    return 1;
#endif
#if defined(OS_POSIX)
  // Always ignore SIGPIPE.  We check the return value of write().
  CHECK(signal(SIGPIPE, SIG_IGN) != SIG_ERR);
#endif  // OS_POSIX
  int browser_pid;
  std::wstring process_type =
    parsed_command_line.GetSwitchValue(switches::kProcessType);
  if (process_type.empty()) {
    browser_pid = base::GetCurrentProcId();
  } else {
#if defined(OS_WIN)
    std::wstring channel_name =
      parsed_command_line.GetSwitchValue(switches::kProcessChannelID);
    browser_pid = StringToInt(WideToASCII(channel_name));
    DCHECK(browser_pid != 0);
#else
    browser_pid = base::GetCurrentProcId();
#endif
#if defined(OS_POSIX)
    // When you hit Ctrl-C in a terminal running the browser
    // process, a SIGINT is delivered to the entire process group.
    // When debugging the browser process via gdb, gdb catches the
    // SIGINT for the browser process (and dumps you back to the gdb
    // console) but doesn't for the child processes, killing them.
    // The fix is to have child processes ignore SIGINT; they'll die
    // on their own when the browser process goes away.
    // Note that we *can't* rely on DebugUtil::BeingDebugged to catch this
    // case because we are the child process, which is not being debugged.
    if (!DebugUtil::BeingDebugged())
      signal(SIGINT, SIG_IGN);
#endif
  }
  SetupCRT(parsed_command_line);
  // Initialize the Chrome path provider.
  app::RegisterPathProvider();
  chrome::RegisterPathProvider();
  // Initialize the Stats Counters table.  With this initialized,
  // the StatsViewer can be utilized to read counters outside of
  // Chrome.  These lines can be commented out to effectively turn
  // counters 'off'.  The table is created and exists for the life
  // of the process.  It is not cleaned up.
  // TODO(port): we probably need to shut this down correctly to avoid
  // leaking shared memory regions on posix platforms.
  if (parsed_command_line.HasSwitch(switches::kEnableStatsTable)) {
    std::string statsfile =
        StringPrintf("%s-%d", chrome::kStatsFilename, browser_pid);
    StatsTable *stats_table = new StatsTable(statsfile,
        chrome::kStatsMaxThreads, chrome::kStatsMaxCounters);
    StatsTable::set_current(stats_table);
  }
  StatsScope<StatsCounterTimer>
      startup_timer(chrome::Counters::chrome_main());
  // Enable the heap profiler as early as possible!
  EnableHeapProfiler(parsed_command_line);
  // Enable Message Loop related state asap.
  if (parsed_command_line.HasSwitch(switches::kMessageLoopHistogrammer))
    MessageLoop::EnableHistogrammer(true);
  // Checks if the sandbox is enabled in this process and initializes it if this
  // is the case. The crash handler depends on this so it has to be done before
  // its initialization.
  SandboxInitWrapper sandbox_wrapper;
#if defined(OS_WIN)
  sandbox_wrapper.SetServices(sandbox_info);
#endif
  sandbox_wrapper.InitializeSandbox(parsed_command_line, process_type);
#if defined(OS_WIN)
  _Module.Init(NULL, instance);
#endif
  // Notice a user data directory override if any
  const std::wstring user_data_dir =
      parsed_command_line.GetSwitchValue(switches::kUserDataDir);
  if (!user_data_dir.empty())
    CHECK(PathService::Override(chrome::DIR_USER_DATA, user_data_dir));
  bool single_process =
#if defined (GOOGLE_CHROME_BUILD)
    // This is an unsupported and not fully tested mode, so don't enable it for
    // official Chrome builds.
    false;
#else
    parsed_command_line.HasSwitch(switches::kSingleProcess);
#endif
  if (single_process)
    RenderProcessHost::set_run_renderer_in_process(true);
#if defined(OS_MACOSX)
  // TODO(port-mac): This is from renderer_main_platform_delegate.cc.
  // shess tried to refactor things appropriately, but it sprawled out
  // of control because different platforms needed different styles of
  // initialization.  Try again once we understand the process
  // architecture needed and where it should live.
  if (single_process)
    InitWebCoreSystemInterface();
#endif
  bool icu_result = icu_util::Initialize();
  CHECK(icu_result);
  logging::OldFileDeletionState file_state =
      logging::APPEND_TO_OLD_LOG_FILE;
  if (process_type.empty()) {
    file_state = logging::DELETE_OLD_LOG_FILE;
  }
  logging::InitChromeLogging(parsed_command_line, file_state);
#ifdef NDEBUG
  if (parsed_command_line.HasSwitch(switches::kSilentDumpOnDCHECK) &&
      parsed_command_line.HasSwitch(switches::kEnableDCHECK)) {
#if defined(OS_WIN)
    logging::SetLogReportHandler(ChromeAssert);
#endif
  }
#endif  // NDEBUG
  if (!process_type.empty())
    CommonSubprocessInit();
  startup_timer.Stop();  // End of Startup Time Measurement.
  MainFunctionParams main_params(parsed_command_line, sandbox_wrapper,
                                 &autorelease_pool);
  // TODO(port): turn on these main() functions as they've been de-winified.
  int rv = -1;
  if (process_type == switches::kRendererProcess) {
    rv = RendererMain(main_params);
  } else if (process_type == switches::kPluginProcess) {
    rv = PluginMain(main_params);
  } else if (process_type == switches::kUtilityProcess) {
    rv = UtilityMain(main_params);
  } else if (process_type == switches::kWorkerProcess) {
#if defined(OS_WIN)
    rv = WorkerMain(main_params);
#else
    NOTIMPLEMENTED();
#endif
  } else if (process_type == switches::kZygoteProcess) {
#if defined(OS_LINUX)
    if (ZygoteMain(main_params)) {
      // Zygote::HandleForkRequest may have reallocated the command
      // line so update it here with the new version.
      const CommandLine& parsed_command_line =
        *CommandLine::ForCurrentProcess();
      MainFunctionParams main_params(parsed_command_line, sandbox_wrapper,
                                     &autorelease_pool);
      RendererMain(main_params);
    }
#else
    NOTIMPLEMENTED();
#endif
  } else if (process_type.empty()) {
#if defined(OS_LINUX)
    // Glib type system initialization. Needed at least for gconf,
    // used in net/proxy/proxy_config_service_linux.cc. Most likely
    // this is superfluous as gtk_init() ought to do this. It's
    // definitely harmless, so retained as a reminder of this
    // requirement for gconf.
    g_type_init();
    // gtk_init() can change |argc| and |argv|, but nobody else uses them.
    gtk_init(&argc, const_cast<char***>(&argv));
    SetUpGLibLogHandler();
#endif
    ScopedOleInitializer ole_initializer;
    rv = BrowserMain(main_params);
  } else {
    NOTREACHED() << "Unknown process type";
  }
  if (!process_type.empty()) {
    ResourceBundle::CleanupSharedInstance();
  }
#if defined(OS_WIN)
#ifdef _CRTDBG_MAP_ALLOC
  _CrtDumpMemoryLeaks();
#endif  // _CRTDBG_MAP_ALLOC
  _Module.Term();
#endif
  logging::CleanupChromeLogging();
  return rv;
}
 

Line 15  RegisterInvalidParamHandler();

主要是注册一些回调函数,用于调试和定位(后续采用在代码中增加一些中文注释的方法来解释)

void RegisterInvalidParamHandler() {
#if defined(OS_WIN)
    //当调用CRT函数时,参数不合法时,将调用InvalidParameter函数
    //InvalidParameter函数也就是产生中断,触发CrashReport服务
  _set_invalid_parameter_handler(InvalidParameter);
  //当系统调用纯虚函数时,将调用PureCall函数,用于调试
  _set_purecall_handler(PureCall);
  // Gather allocation failure.
  //当内存分配失败时,将调用OnNoMemory,
  std::set_new_handler(&OnNoMemory);
  // Also enable the new handler for malloc() based failures.
  //支持Malloc模式
  _set_new_mode(1);
#endif
}
 

Line 50 -- Line54可以不用关注,主要是为了规避早期Chrome的一个BUG而已。

LIne61 -- Line 75主要是获取当前Browser进程的ID。因为当前启动的是Browser进程,所以获取的肯定是Browser ID。

Line 91 设置CRT参数,比较简单。

Line 94 -- Line 95 主要初始化各种路径辅助类PathService参数。该类主要提供各种路径服务,比如获取当前目录,用户数据存储目录等服务。

Line 103 -- Line110 当启动参数中包含了 --enable-stats-table时,将初始化状态统计表辅助类,用于统计线程数量。

Line 112 -- Line 114 初始化状态统机辅助类StatsCounterTimer,该类将会启动一个计数器,在这里主要统计本函数所花时间。

Line 116   EnableHeapProfiler(parsed_command_line); 加载memory_watcher.dll,Chrome中的一个辅助类,用于统计chrome的内存占用情况。在Chrome中按下Shift + Esc可以查看内存情况,在后面就是memory_watch.dll起作用。

Chrome的启动流程 之二 - yolcy - 写着玩

Line 119 -- Line120 当Chrome启动模式指定了message-loop-histogrammer模式时,用于启动线程消息频率统计功能,当在浏览器地址栏输入about:histograms/Loop时,可以查看到效果(前提是以message-loop-histogrammer模式启动,缺省情况下是不会启动的)。

Chrome的启动流程 之二 - yolcy - 写着玩

Line 125 -- Line 133 主要是初始化SandBox服务。Chrome的Crash Report服务依赖于SandBox业务,所以这个服务需要尽早启动,保证Crash Report功能有效。

Line 135 -- Line 139 如果启动时参数中用户指定了用户数据目录,则在PathService类中替换用户数据目录为用户制定的目录。

Line 141 -- Line 159 检测启动参数是否包含了--single-process参数,如果包含了该参数,则采用单进程模式,Renderer也将包含在Browser进程中。下面这两幅图可以明显的看出在两种进程模式下的进程情况。相关的进程模式可以参考另外一篇文章(尚未发出),也可参考Chrome的官方网站说明

Chrome的启动流程 之二 - yolcy - 写着玩

单进程模式下的进程模式(所有页面都在同一进程中,与FireFox,IE一样模式)

Chrome的启动流程 之二 - yolcy - 写着玩

缺省模式下的进程模式(每一个网站实例一个进程)

Line 161 -- Line 162 初始化Unicode语言库。IBM提供的一个多语言支持库,比较大。
Line 164 -- Line 169 初始化LOG库,涉及到一个重新启动Chrome时是否删除旧的LOG选项。
process_type这个参数,在缺省情况下,都是为brower进程,但是在启动时也可以指定当前进程类型为Renderer、Plugin、Utility、Worker。这个主要通过启动参数--type=XXX来指定(这里还不是很清楚,后续搞清楚后再更新)。
Line 180 -- Line 245 主要根据不同的进程类型(process_type),调用下一步的初始化过程。在缺省情况下(不指定type参数),将会执行下一个函数BrowserMain,那将是一个更复杂一些的函数。

总结一下,在本函数中,主要也是初始化一些辅助库、全局参数等,相对起来比较好理解。
到目前为止,应该说还没有进入正题,Chrome的两个核心进程Browser和Renderer的初始化工作还没有开始。

 

 


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/xingtian713/archive/2009/07/19/4362319.aspx

  评论这张
 
阅读(1224)| 评论(1)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017