http://blog.sina.com.cn/s/blog_5e83fce60100q583.html
现在我要关注的问题是:
一个RenderProcess的消息怎么发送到BrowserProcess进程中的,这个消息走了那些路?注意,所说的IO线程是Browser进程中的IO线程,非Render进程中发的IO。所谓的IO线程主要用来接受网络消息和进程间的消息,我先把网络消息抛到一边,单独分析下RenderProcess进程给BrowserProcess的消息是怎样流动的?
通常把网络包分为上行和下行,在这里我把RenderProcess到BrowserProcess称为上行消息,BrowserProcess到RenderProcess的消息称为下行消息,这章只讨论上行消息。
需要特别注意的几个类分别是:
WebContents: WebContents包括了RenderViewHost和NavigationController。
RenderViewHostManager:存在于WebContents主要保存一个RenderViewHost对象,但是有一种情况比较复杂,那就是当一个Interstitial webpage存在时,它负责加载Interstitial webpage,并切换到用户请求页面。关于Interstitial webpage请参看上上篇文章的解释。由于这种复杂度,这里没有直接采用RenderViewHost而是采用RenderViewHostManager来控制管理。
NavigationController:
RenderViewHost:对应于一个HTML页面
Channel:
ChannelProxy:
ChannelProxy::Context:
SyncChannel:
SyncChannel::SyncContext:
ResourceDispatcherHost:所有消息将通过ResourceDispatcherHost来过滤,ResourceMessageFilter的消息也会通过ResourceDispatcherHost,ResourceDispatcherHost还过滤网络消息,并且做相应的转发。
ResourceMessageFilter:
MessageLoopForIO:
先大致走一趟上行消息的简单流程,然后结合代码仔细分析。
消息最先达到的地方当然是Channel这个对象了,Channel是被ChannelProxy::Context所封装,所以消息会被分派到ChannelProxy::Context中,ChannelProxy::Context对象是存在于ChannelProxy中的,ChannelProxy::Contex又把消息提交给了ChannelProxy,ChannelProxy先过滤消息,如果消息没有被过滤掉,把消息推给RenderProcessHost,然后由RenderProcessHost把消息分配给每个相应的RenderViewHost。
0:一个TAB页面是怎么被创建的出来的?
1:ChannelProxy怎么由UI线程给分派到IO线程中去运行?
2:一个命名管道的消息怎么被通知到BrowserProcess进程中的?
3:消息是通过什么方法逐渐往上一层传递的?
4:ResourceMessageFilter是怎么加进ChannelProxy中的,它会过滤掉什么样的消息,什么消息它会继续转发?
5:ResourceMessageFilter和ResourceDispatcherHost有什么瓜葛?
一:先来分析第一个问题:
一个TAB页面是怎么被创建的出来的?
当用户点击浏览器上的添加按钮或者是从一个网页的一个连接来打开一个新的页面,这样一个新的页面就被创建了。一个WebContents对象对应于一个HTML页面和关联该页面的标签,创建一个页面其实就是创建一个WebContents对象。
上面提到过RenderViewHostManager
仔细看RenderProcessHost的结构会发现,RenderProcessHost中有两个方法:
用这两个方法来关联和取消关联,具体细节参见前面的UML
这样一个RenderViewHost的对象就被创建并关联到相应的RenderProcessHost中了。
二:分析第二个问题:
ChannelProxy怎么由UI线程给分派到IO线程中去运行?
根据chrome官方技术文档可以看出来,每个RenderProcessHost对应一个RenderProcess,他们之间通过ChannelProxy来通讯的,也就是说RenderProcessHost是通过ChannelProxy和RenderProcess的ChannelProxy来通讯的。RenderProcessHost和RenderProcess分别都拥有一个ChannelProxy,RenderProcessHost和RenderProcess都是通过他们的大使ChannelProxy来沟通的。先抛开RenderProcess和它的大使ChannelProxy,专心来分析RenderProcessHost和它的大使ChannelProxy。
先来分析RenderProcessHost是怎么创建的?
上面分析过,RenderProcessHost是从SiteInstance中获取的,先分析一段SiteInstance获取RenderProcessHost的代码:
RenderProcessHost* SiteInstance::GetProcess()
{
//
{
//
}
这样一个对象就创建了,这里采用的策略是lazycreate,即是到了需要创建的时候才创建该对象。
注意了,channel并不是在这个时候被创建的,channel是在加载时被创建的,
RenderProcessHost中的Init函数中创建的。
RenderProcess也是在该函数中创建的,关于该函数,很长,我选出其中比较重要的几段,为了不影响阅读,我把一些sandbox的代码给去掉了,简化后的代码如下:
bool
{
一堆生成命令行的代码、被我注释掉了。
}
{
else
}
当我开始启动一个浏览器的时候,调试堆栈如下,可以看出Init函数是什么时候第一次被调用的。
上面的代码还是运行在UI线程中的,我还没有看出来channel对象是怎么给 分派带IO线程中去运行的?