Chrome源代码分析之Renderer进程初始化(十五)

http://blog.csdn.net/namelcx/article/details/8939824

前面已经分析过,一个RenderProcess与一个主进程中的RenerProcessHost对应。RenderProcess到底在什么时候创建,答案是在RenerProcessHos初始化的时候创建,对应的过程在BrowserRenderProcessHost::Init函数中实现。我们来看看这个函数,函数对应的文件是:

src\chrome\browser\renderer_host\browser_render_process_host.cc


Init开始部分做一些准备工作,比如获取IO线程对象的指针:base::Thread* io_thread = g_browser_process->io_thread();

初始化进程间通信消息过滤对象:

  scoped_refptr<ResourceMessageFilter> resource_message_filter(
      new ResourceMessageFilter(g_browser_process->resource_dispatcher_host(),
                                id(),
                                audio_renderer_host_.get(),
                                PluginService::GetInstance(),
                                g_browser_process->print_job_manager(),
                                profile(),
                                widget_helper_));


比较重要的是创建IPC对象,首先是初始化一个ChannelID,ChannelID标识了一个属于本RenerProcessHost的唯一的命名管道名,接着用这个ID创建一个IPC对象:

  channel_.reset(
      new IPC::SyncChannel(channel_id, IPC::Channel::MODE_SERVER, this,
                           resource_message_filter,
                           io_thread->message_loop(), true,
                           g_browser_process->shutdown_event()));


接着到了比较重要的地方,会对当前的运行模式做一个判断,如果是单进程模式,不会创建进程,而是在主进程中创建一个RendererMainThread线程,如果是非按进程模式,会接着创建一个新的RenderProcess。调用的函数是:

  static bool run_renderer_in_process() {
    return run_renderer_in_process_;
  }


这是BrowserRenderProcessHost的父类的静态成员函数,run_renderer_in_process_也是一个静态变量,回顾一下主进程的初始化过程,ChromeMain的第三个参数TCHAR* command_line代表的就是启动chrome.exe的时候传递进来的参数,前面一章已经介绍过,如果command_line是--single-process,那么将运行在单进程模式下,那么,会调用下面的代码设置run_renderer_in_process_的值:

  if (single_process)
    RenderProcessHost::set_run_renderer_in_process(true);


再回到刚才的代码,如果是单进程模型:

    in_process_renderer_.reset(new RendererMainThread(channel_id));


    base::Thread::Options options;
#if !defined(TOOLKIT_USES_GTK)
    // In-process plugins require this to be a UI message loop.
    options.message_loop_type = MessageLoop::TYPE_UI;
#else
    // We can't have multiple UI loops on GTK, so we don't support
    // in-process plugins.
    options.message_loop_type = MessageLoop::TYPE_DEFAULT;
#endif
    in_process_renderer_->StartWithOptions(options);


    OnProcessLaunched();  // Fake a callback that the process is ready.


首先创建RendererMainThread的对象,接着设置线程的类型为TYPE_UI,也就是说,这个线程是一个能接收处理windows系统消息的线程,这与多进程模型是完全不同的。

最后调用n_process_renderer_->StartWithOptions(options);启动这个线程的消息循环。


如果是标准的多进程模型:

    CommandLine* cmd_line = new CommandLine(renderer_path);
    if (!renderer_prefix.empty())
      cmd_line->PrependWrapper(renderer_prefix);
    AppendRendererCommandLine(cmd_line);
    cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);


    // Spawn the child process asynchronously to avoid blocking the UI thread.
    // As long as there's no renderer prefix, we can use the zygote process
    // at this stage.
    child_process_.reset(new ChildProcessLauncher(
#if defined(OS_WIN)
        FilePath(),
#elif defined(POSIX)
        renderer_prefix.empty(),
        base::environment_vector(),
        channel_->GetClientFileDescriptor(),
#endif
        cmd_line,
        this));


    fast_shutdown_started_ = false;


上面做的主要工作就是创建一个新的RenderProcess,并且通过cmd_line把ChannelID传递给这个新的进程,这样RenderProcess和RenerProcessHost才能建立一对一的关系,完成正常的进程间通信的任务。

接着再看看创建进程的具体实现,代码位于:

src\chrome\browser\child_process_launcher.cc

代码如下:

ChildProcessLauncher::ChildProcessLauncher(
#if defined(OS_WIN)
    const FilePath& exposed_dir,
#elif defined(OS_POSIX)
    bool use_zygote,
    const base::environment_vector& environ,
    int ipcfd,
#endif
    CommandLine* cmd_line,
    Client* client) {
  context_ = new Context();
  context_->Launch(
#if defined(OS_WIN)
      exposed_dir,
#elif defined(OS_POSIX)
      use_zygote,
      environ,
      ipcfd,
#endif
      cmd_line,
      client);
}

重点是context_->Launch,context_->Launch的唯一工作就是向BrowserThread线程发起一个Task,执行LaunchInternal函数,该函数调用handle = sandbox::StartProcessWithAccess(cmd_line, exposed_dir);

StartProcessWithAccess先通过传递的cmd_line确定进程的类型,枚举类型定义在ChildProcessInfo类里面,如下:

  enum ProcessType {
    UNKNOWN_PROCESS = 1,
    BROWSER_PROCESS,
    RENDER_PROCESS,
    PLUGIN_PROCESS,
    WORKER_PROCESS,
    NACL_LOADER_PROCESS,
    UTILITY_PROCESS,
    PROFILE_IMPORT_PROCESS,
    ZYGOTE_PROCESS,
    SANDBOX_HELPER_PROCESS,
    NACL_BROKER_PROCESS,
    GPU_PROCESS
  };


经过一系列判断,如果非sandbox进程,那么调用: base::LaunchApp(*cmd_line, false, false, &process);

如果是sandbox进程,调用  result = g_broker_services->SpawnTarget(
      cmd_line->GetProgram().value().c_str(),
      cmd_line->command_line_string().c_str(),
      policy, &target);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值