Chromium网页Frame Tree创建过程分析
Posted 罗升阳
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Chromium网页Frame Tree创建过程分析相关的知识,希望对你有一定的参考价值。
Chromium在加载一个网页之前,需要在Browser进程创建一个Frame Tree。Browser进程为网页创建了Frame Tree之后,再请求Render进程加载其内容。Frame Tree将网页抽象为Render Frame。Render Frame是为实现Out-of-Process iframes设计的。本文接下来就分析Frame Tree的创建过程,为后面分析网页加载过程打基础。
老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注!
《android系统源代码情景分析》一书正在进击的程序员网(http://0xcc0xcd.com)中连载,点击进入!
关于Chromium的Out-of-Process iframes的详细介绍,可以参考官方文档:Out-of-Process iframes (OOPIFs),或者前面Chromium网页加载过程简要介绍和学习计划一文。我们通过图1所示的例子简单介绍,如下所示:
图1 Out-of-Process iframes
在图1中,网页A在一个Tab显示,并且它通过iframe标签包含了网页B和网页C。网页C通过window.open在另外一个Tab中打开了另外一个网页C实例。新打开的网页C通过iframe标签包含了网页D,网页D又通过iframe标签包含了网页A的另外一个实例。
这时候Browser进程会分别为图1的两个Tab创建一个WebContents对象,如图2所示:
图2 RenderFrameHost/RenderFrameProxyHost
在Browser进程中,一个网页使用一个WebContents对象描述。每一个WebContents对象都又关联有一个Frame Tree。Frame Tree的每一个Node代表一个网页。其中,Frame Tree的根Node描述的是主网页,子Node描述的是通过iframe标签嵌入的子网页。例如,第一个Tab的Frame Tree包含有三个Node,分别代表网页A、B和C,第二个Tab的Frame Tree也包含有三个Node,分别代表网页C、D和A。
网页A、B、C和D在Chromium中形成了一个Browsing Instance。关于Chromium的Browsing Instance,可以参考官方文档:Process Models,它对应于html5规范中的Browsing Context。
我们观察代表网页B的子Node,它关联有一个RenderFrameHost对象和三个RenderFrameProxyHost对象。其中,RenderFrameHost对象描述的是网页B本身,另外三个RenderFrameProxyHosts对象描述的是网页A、C和D。表示网页B可以通过javascript接口window.postMessage向网页A、C和D发送消息。
假设图1所示的网页A、B、C和D分别在不同的Render进程中渲染,如图3所示:
图3 RenderFrame/RenderFrameProxy
在负责加载和渲染网页B的Render进程中,有一个RenderFrame对象,代表图1所示的网页B。负责加载和渲染网页B的Render进程还包含有五个RenderFrameProxy对象,分别代表图1所示的两个网页A实例、两个网页C实例和一个网页D实例。在负责渲染网页A、C和D的Render进程中,也有类似的RenderFrame对象和RenderFrameProxy对象。
Browser进程的RenderFrameHost对象和Render进程的RenderFrame对象是一一对应的。同样,Browser进程的RenderFrameHostProxy对象和Render进程的RenderFrameProxy对象也是一一对应的。RenderFrame对象和RenderFrameProxy对象的存在,使得在同一个Browsing Instance或者Browsing Context中的网页可以通过Javascript接口window.postMessage相互发送消息。
例如,当网页B要向网页A发送消息时,负责加载和渲染网页B的Render进程就会在当前进程中找到与网页B对应的RenderFrame对象,以及与网页A对应的RenderFrameProxy对象,然后将要发送的消息从找到的RenderFrame对象传递给找到的RenderFrameProxy对象即可。与网页A对应RenderFrameProxy对象接收到消息之后,会进一步将该消息发送给负责加载和渲染网页A的Render进程处理,从而完成消息的发送和处理过程。
接下来,我们就结合源码分析Chromium为网页创建Frame Tree的过程,这个过程涉及到WebContents、RenderFrameHost和RenderFrame等重要对象的创建。
前面提到,Frame Tree是在Browser进程中创建的,并且与一个WebContents对象关联。从前面Chromium网页加载过程简要介绍和学习计划一文可以知道,WebContents是Chromium的Content模块提供的一个高级接口,通过这个接口可以将一个网页渲染在一个可视区域中。我们可以认为,一个WebContents对象就是用来实现一个网页的加载、解析、渲染和导航等功能的。
Frame Tree是在与其关联的WebContents对象的创建过程中创建的,因此接下来我们就从WebContents对象的创建过程开始分析Frame Tree的创建过程。以Chromium硬件加速渲染的OpenGL上下文绘图表面创建过程分析一文提到的Shell APK为例,它会为每一个要加载的网页在Native层创建一个Shell。在创建这个Shell的过程中,就会同时创建一个WebContents对象。
从前面Chromium硬件加速渲染的OpenGL上下文绘图表面创建过程分析一文可以知道,Shell APK是通过调用Native层的Shell类的静态成员函数CreateNewWindow为要加载的网页创建一个Shell的,它的实现如下所示:
Shell* Shell::CreateNewWindow(BrowserContext* browser_context,
const GURL& url,
SiteInstance* site_instance,
int routing_id,
const gfx::Size& initial_size) {
WebContents::CreateParams create_params(browser_context, site_instance);
create_params.routing_id = routing_id;
create_params.initial_size = AdjustWindowSize(initial_size);
WebContents* web_contents = WebContents::Create(create_params);
Shell* shell = CreateShell(web_contents, create_params.initial_size);
......
return shell;
}
这个函数定义在文件external/chromium_org/content/shell/browser/shell.cc中。
Shell类的静态成员函数CreateNewWindow首先是调用WebContents类的静态成员函数Create创建一个WebContentsImpl对象,接着再调用Shell类的静态成员函数CreateShell根据前面创建的WebContentsImpl对象创建一个Shell对象,并且返回给调用者。
接下来,我们先分析WebContents类的静态成员函数Create的实现,接着再分析Shell类的静态成员函数CreateShell的实现。
WebContents类的静态成员函数Create的实现如下所示:
WebContents* WebContents::Create(const WebContents::CreateParams& params) {
return WebContentsImpl::CreateWithOpener(
params, static_cast<WebContentsImpl*>(params.opener));
}
这个函数定义在文件external/chromium_org/content/browser/web_contents/web_contents_impl.cc中。
WebContents类的静态成员函数Create调用另外一个静态成员函数CreateWithOpener创建一个WebContentsImpl对象,并且返回给调用者。
WebContents类的静态成员函数CreateWithOpener的实现如下所示:
WebContentsImpl* WebContentsImpl::CreateWithOpener(
const WebContents::CreateParams& params,
WebContentsImpl* opener) {
......
WebContentsImpl* new_contents = new WebContentsImpl(
params.browser_context, params.opener_suppressed ? NULL : opener);
......
new_contents->Init(params);
return new_contents;
}
这个函数定义在文件external/chromium_org/content/browser/web_contents/web_contents_impl.cc中。
WebContents类的静态成员函数CreateWithOpener首先是创建一个WebContentsImpl对象。在将这个WebContentsImpl对象返回给调用者之前,会先调用它的成员函数Init对它进行初始化。
接下来,我们先分析WebContentsImpl对象的创建过程,即WebContentsImpl类的构造函数的实现,接下来再分析WebContentsImpl对象的初始化过程,即WebContentsImpl类的成员函数Init的实现。
WebContentsImpl类的构造函数的实现如下所示:
WebContentsImpl::WebContentsImpl(
BrowserContext* browser_context,
WebContentsImpl* opener)
: ......,
controller_(this, browser_context),
......,
frame_tree_(new NavigatorImpl(&controller_, this),
this, this, this, this),
...... {
......
}
这个函数定义在文件external/chromium_org/content/browser/web_contents/web_contents_impl.cc中。
WebContentsImpl类的成员变量controller_描述的是一个NavigationControllerImpl对象。后面我们可以看到,这个NavigationControllerImpl对象负责执行加载URL的操作。现在我们分析它的创建过程,如下所示:
NavigationControllerImpl::NavigationControllerImpl(
NavigationControllerDelegate* delegate,
BrowserContext* browser_context)
: ......,
delegate_(delegate),
...... {
......
}
这个函数定义在文件external/chromium_org/content/browser/frame_host/navigation_controller_impl.cc中。
从前面的调用过程可以知道,参数delegate指向的是一个WebContentsImpl对象。这个WebContentsImpl对象保存在NavigationControllerImpl类的成员变量delegate_中。
回到WebContentsImpl类的构造函数中,它构造了一个NavigationControllerImpl对象之后,接下来又根据该NavigationControllerImpl对象创建一个NavigatorImpl对象。这个NavigatorImpl对象也是在加载URL时使用到的,它的创建过程如下所示:
NavigatorImpl::NavigatorImpl(
NavigationControllerImpl* navigation_controller,
NavigatorDelegate* delegate)
: controller_(navigation_controller),
delegate_(delegate) {
}
这个函数定义在文件external/chromium_org/content/browser/frame_host/navigator_impl.cc
从前面的调用过程可以知道,参数navigation_controller和delegate指向的分别是一个NavigationControllerImpl对象和一个WebContentsImpl对象,它们分别保存在NavigatorImpl类的成员变量controller_和delegate_中。
再回到WebContentsImpl类的构造函数中,它创建了一个NavigatorImpl对象之后,又根据该NavigatorImpl对象创建一个FrameTree对象,并且保存在成员变量frame_tree_中。这个FrameTree对象描述的就是一个Frame Tree。
接下来我们继续分析FrameTree对象的创建过程,也就是FrameTree类的构造函数的实现,如下所示:
FrameTree::FrameTree(Navigator* navigator,
RenderFrameHostDelegate* render_frame_delegate,
RenderViewHostDelegate* render_view_delegate,
RenderWidgetHostDelegate* render_widget_delegate,
RenderFrameHostManager::Delegate* manager_delegate)
: render_frame_delegate_(render_frame_delegate),
render_view_delegate_(render_view_delegate),
render_widget_delegate_(render_widget_delegate),
manager_delegate_(manager_delegate),
root_(new FrameTreeNode(this,
navigator,
render_frame_delegate,
render_view_delegate,
render_widget_delegate,
manager_delegate,
std::string())),
...... {
}
这个函数定义在文件external/chromium_org/content/browser/frame_host/frame_tree.cc中。
从前面的调用过程可以知道,参数navigator指向的是一个NavigatorImpl对象,其余四个参数指向的是同一个WebContentsImpl对象,分别被保存在FrameTree类的成员变量render_frame_delegate_、render_view_delegate_、render_widget_delegate_和manager_delegate_中。
FrameTree类的构造函数接下来做的一件事情是创建一个FrameTreeNode对象,并且保存在成员变量root_中,作为当前正在创建的Frame Tree的根节点。这个根节点描述的就是后面要加载的网页。
FrameTreeNode对象的创建过程,即FrameTreeNode类的构造函数的实现,如下所示:
FrameTreeNode::FrameTreeNode(FrameTree* frame_tree,
Navigator* navigator,
RenderFrameHostDelegate* render_frame_delegate,
RenderViewHostDelegate* render_view_delegate,
RenderWidgetHostDelegate* render_widget_delegate,
RenderFrameHostManager::Delegate* manager_delegate,
const std::string& name)
: frame_tree_(frame_tree),
navigator_(navigator),
render_manager_(this,
render_frame_delegate,
render_view_delegate,
render_widget_delegate,
manager_delegate),
...... {}
这个函数定义在文件external/chromium_org/content/browser/frame_host/frame_tree_node.cc中。
从前面的调用过程可以知道,参数frame_tree和navigator指向的分别是一个FrameTree对象和一个NavigatorImpl对象,它们分别被保存在FrameTreeNode类的成员变量frame_tree_和navigator_中。
FrameTreeNode类的构造函数接下来做的一件事情是构造一个RenderFrameHostManager对象,并且保存在成员变量render_manager_中。这个RenderFrameHostManager对象负责管理与当前正在创建的FrameTreeNode对象关联的一个RenderFrameHost对象,它的构造过程如下所示:
RenderFrameHostManager::RenderFrameHostManager(
FrameTreeNode* frame_tree_node,
RenderFrameHostDelegate* render_frame_delegate,
RenderViewHostDelegate* render_view_delegate,
RenderWidgetHostDelegate* render_widget_delegate,
Delegate* delegate)
: frame_tree_node_(frame_tree_node),
delegate_(delegate),
......,
render_frame_delegate_(render_frame_delegate),
render_view_delegate_(render_view_delegate),
render_widget_delegate_(render_widget_delegate),
...... {
......
}
这个函数定义在文件external/chromium_org/content/browser/frame_host/render_frame_host_manager.cc中。
从前面的调用过程可以知道,参数frame_tree_node指向的是一个FrameTreeNode对象,它被保存在RenderFrameHostManager类的成员变量frame_tree_node_中,其余四个参数指向的是同一个WebContentsImpl对象,分别被保存在RenderFrameHostManager类的成员变量delegate_、render_frame_delegate_、render_view_delegate_和render_widget_delegate_中。
这一步执行完成之后,一个Frame Tree就创建出来了。这是一个只有根节点的Frame Tree。根节点描述的网页就是接下来要进行加载的。根节点描述的网页加载完成之后,就会进行解析。在解析的过程中,如果碰到iframe标签,那么就会创建另外一个子节点,并且添加到当前正在创建的Frame Tree中去。
返回到WebContents类的静态成员函数CreateWithOpener中,它创建了一个WebContentsImpl对象之后,接下来会调用这个WebContentsImpl对象的成员函数Init执行初始化工作,如下所示:
void WebContentsImpl::Init(const WebContents::CreateParams& params) {
......
GetRenderManager()->Init(
params.browser_context, params.site_instance, params.routing_id,
params.main_frame_routing_id);
......
if (browser_plugin_guest_) {
......
} else {
// Regular WebContentsView.
view_.reset(CreateWebContentsView(
this, delegate, &render_view_host_delegate_view_));
}
......
}
这个函数定义在文件external/chromium_org/content/browser/web_contents/web_contents_impl.cc中。
WebContentsImpl类的成员函数Init首先是调用成员函数GetRenderManager获得一个RenderFrameHostManager对象,接下来再调用这个RenderFrameHostManager对象的成员函数Init对其进行初始化。
WebContentsImpl类的成员函数GetRenderManager的实现如下所示:
RenderFrameHostManager* WebContentsImpl::GetRenderManager() const {
return frame_tree_.root()->render_manager();
}
这个函数定义在文件external/chromium_org/content/browser/web_contents/web_contents_impl.cc中。
从前面的分析可以知道,WebContentsImpl类的成员变量frame_tree_指向的是一个FrameTree对象。调用这个FrameTree对象的成员函数root获得的是一个FrameTreeNode对象。这个FrameTreeNode对象描述的是前面创建的Frame Tree的根节点。WebContentsImpl类的成员函数GetRenderManager最后调用该FrameTreeNode对象的成员函数render_manager获得一个RenderFrameHostManager对象,并且返回给调用者。
FrameTreeNode类的成员函数render_manager的实现如下所示:
class CONTENT_EXPORT FrameTreeNode {
public:
......
RenderFrameHostManager* render_manager() {
return &render_manager_;
}
......
private:
......
RenderFrameHostManager render_manager_;
......
};
这个函数定义在文件external/chromium_org/content/browser/frame_host/frame_tree_node.h中。
从这里可以看到,FrameTreeNode类的成员函数render_manager返回的是成员变量render_manager_描述的一个RenderFrameHostManager对象。这个RenderFrameHostManager对象是在前面分析的FrameTreeNode类的构造函数创建的。
回到WebContentsImpl类的成员函数Init中,它获得了一个RenderFrameHostManager对象之后,就调用它的成员函数Init对它进行初始化,如下所示:
void RenderFrameHostManager::Init(BrowserContext* browser_context,
SiteInstance* site_instance,
int view_routing_id,
int frame_routing_id) {
......
SetRenderFrameHost(CreateRenderFrameHost(site_instance,
view_routing_id,
frame_routing_id,
false,
delegate_->IsHidden()));
......
}
这个函数定义在文件external/chromium_org/content/browser/frame_host/render_frame_host_manager.cc中。
RenderFrameHostManager类的成员函数Init主要做了两件事情。第一件事情是调用成员函数CreateRenderFrameHost创建了一个RenderFrameHostImpl对象。第二件事情是调用成员函数SetRenderFrameHost将该RenderFrameHostImpl对象保存在内部,如下所示:
scoped_ptr<RenderFrameHostImpl> RenderFrameHostManager::SetRenderFrameHost(
scoped_ptr<RenderFrameHostImpl> render_frame_host) {
// Swap the two.
scoped_ptr<RenderFrameHostImpl> old_render_frame_host =
render_frame_host_.Pass();
render_frame_host_ = render_frame_host.Pass();
......
return old_render_frame_host.Pass();
}
这个函数定义在文件external/chromium_org/content/browser/frame_host/render_frame_host_manager.cc中。
RenderFrameHostManager类的成员函数SetRenderFrameHost主要是将参数render_frame_host描述的一个RenderFrameHostImpl对象保存在成员变量render_frame_host_中。
回到RenderFrameHostManager类的成员函数Init中,接下来我们主要分析它调用成员函数CreateRenderFrameHost创建RenderFrameHostImpl对象的过程,如下所示:
scoped_ptr<RenderFrameHostImpl> RenderFrameHostManager::CreateRenderFrameHost(
SiteInstance* site_instance,
int view_routing_id,
int frame_routing_id,
bool swapped_out,
bool hidden) {
......
FrameTree* frame_tree = frame_tree_node_->frame_tree();
RenderViewHostImpl* render_view_host = NULL;
if (frame_tree_node_->IsMainFrame()) {
render_view_host = frame_tree->CreateRenderViewHostForMainFrame(
site_instance, view_routing_id, frame_routing_id, swapped_out, hidden);
}
......
scoped_ptr<RenderFrameHostImpl> render_frame_host =
make_scoped_ptr(RenderFrameHostFactory::Create(render_view_host,
render_frame_delegate_,
frame_tree,
frame_tree_node_,
frame_routing_id,
swapped_out).release());
return render_frame_host.Pass();
}
这个函数定义在文件external/chromium_org/content/browser/frame_host/render_frame_host_manager.cc中。
从前面的分析可以知道,当前正在处理的RenderFrameHostManager对象的成员变量frame_tree_node_描述的是一个Frame Tree的根节点。一个Frame Tree的根节点描述的网页是一个Main Frame(网页中的iframe标签描述的网页称为Sub Frame),因此RenderFrameHostManager类的成员函数CreateRenderFrameHost是调用FrameTree类的成员函数CreateRenderViewHostForMainFrame创建一个RenderViewHostImpl对象,并且保存在本地变量render_view_host中。
FrameTree类的成员函数CreateRenderViewHostForMainFrame的实现如下所示:
RenderViewHostImpl* FrameTree::CreateRenderViewHostForMainFrame(
SiteInstance* site_instance,
int routing_id,
int main_frame_routing_id,
bool swapped_out,
bool hidden) {
.....
RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
RenderViewHostFactory::Create(site_instance,
render_view_delegate_,
render_widget_delegate_,
routing_id,
main_frame_routing_id,
swapped_out,
hidden));
render_view_host_map_[site_instance->GetId()] = rvh;
return rvh;
}
这个函数定义在文件external/chromium_org/content/browser/frame_host/frame_tree.cc中。
FrameTree类的成员函数CreateRenderViewHostForMainFrame调用RenderViewHostFactory类的静态成员函数Create创建了一个RenderViewHostImpl对象。在将这个RenderViewHostImpl对象返回给调用者之前,会以参数site_instance描述的一个Site Instance的ID为键值,将该RenderViewHostImpl对象保存在成员变量render_view_host_map_描述的一个Hash Map中,以便以后可以进行查找。
RenderViewHostFactory类的静态成员函数Create的实现如下所示:
RenderViewHost* RenderViewHostFactory::Create(
SiteInstance* instance,
RenderViewHostDelegate* delegate,
RenderWidgetHostDelegate* widget_delegate,
int routing_id,
int main_frame_routing_id,
bool swapped_out,
bool hidden) {
......
return new RenderViewHostImpl(instance, delegate, widget_delegate, routing_id,
main_frame_routing_id, swapped_out, hidden);
}
这个函数定义在文件external/chromium_org/content/browser/renderer_host/render_view_host_factory.cc中。
RenderViewHostFactory类的静态成员函数Create首先是创建了一个RenderViewHostImpl对象,然后再将这个RenderViewHostImpl对象返回给调用者。从前面Chromium的Render进程启动过程分析一文可以知道,在创建RenderViewHostImpl对象的过程中,将会启动一个Render进程。这个Render进程接下来将会负责加载指定的URL。
这一步执行完成之后,回到RenderFrameHostManager类的成员函数CreateRenderFrameHost中,它接下来调用RenderFrameHostFactory类的静态成员函数Create创建了一个RenderFrameHostImpl对象。这个RenderFrameHostImpl对象返回给RenderFrameHostManager类的成员函数Init后,将会被保存在成员变量render_frame_host_中。
RenderFrameHostFactory类的静态成员函数Create的实现如下所示:
scoped_ptr<RenderFrameHostImpl> RenderFrameHostFactory::Create(
RenderViewHostImpl* render_view_host,
RenderFrameHostDelegate* delegate,
FrameTree* frame_tree,
FrameTreeNode* frame_tree_node,
int routing_id,
bool is_swapped_out) {
......
return make_scoped_ptr(new RenderFrameHostImpl(
render_view_host, delegate, frame_tree, frame_tree_node, routing_id,
is_swapped_out));
}
这个函数定义在文件external/chromium_org/content/browser/frame_host/render_frame_host_factory.cc中。
从这里可以看到,RenderFrameHostFactory类的静态成员函数Create创建的是一个RenderFrameHostImpl对象,并且将这个RenderFrameHostImpl对象返回给调用者。
RenderFrameHostImpl对象的创建过程,即RenderFrameHostImpl类的构造函数的实现,如下所示:
RenderFrameHostImpl::RenderFrameHostImpl(
RenderViewHostImpl* render_view_host,
RenderFrameHostDelegate* delegate,
FrameTree* frame_tree,
FrameTreeNode* frame_tree_node,
int routing_id,
bool is_swapped_out)
: render_view_host_(render_view_host),
...... {
......
}
这个函数定义在文件external/chromium_org/content/browser/frame_host/render_frame_host_impl.cc中。
RenderFrameHostImpl类的构造函数将参数render_view_host描述的一个RenderViewHostImpl对象保存在成员变量render_view_host_中,这个RenderViewHostImpl对象就是前面调用RenderViewHostFactory类的静态成员函数Create创建的。
这一步执行完成之后,回到WebContentsImpl类的成员函数Init中,它接下来还做有另外一个初始化工作,如下所示:
void WebContentsImpl::Init(const WebContents::CreateParams& params) {
......
if (browser_plugin_guest_) {
......
} else {
// Regular WebContentsView.
view_.reset(CreateWebContentsView(
this, delegate, &render_view_host_delegate_view_));
}
......
}
这个函数定义在文件external/chromium_org/content/browser/web_contents/web_contents_impl.cc中。
当WebContentsImpl类的成员变量browser_plugin_guest_指向了一个BrowserPluginGuest对象时,表示当前正在处理的WebContentsImpl对象用来为一个Browser Plugin加载网页。我们不考虑这种情况。这时候WebContentsImpl类的成员函数Init就会调用函数CreateWebContentsView创建一个WebContentsViewAndroid对象,并且保存在成员变量view_中。
函数CreateWebContentsView的实现如下所示:
WebContentsView* CreateWebContentsView(
WebContentsImpl* web_contents,
WebContentsViewDelegate* delegate,
RenderViewHostDelegateView** render_view_host_delegate_view) {
WebContentsViewAndroid* rv = new WebContentsViewAndroid(
web_contents, delegate);
*render_view_host_delegate_view = rv;
return rv;
}
这个函数定义在文件external/chromium_org/content/browser/web_contents/web_contents_view_android.cc中。
从这里可以看到,在Android平台上,函数CreateWebContentsView返回给调用者的是一个WebContentsViewAndroid对象。
这一步执行完成之后,回到Shell类的静态成员函数CreateNewWindow,这时候它就创建了一个WebContentsImpl对象,接下来这个WebContentsImpl对象会用来创建一个Shell对象,这是通过调用Shell类的静态成员函数CreateShell实现的,如下所示:
Shell* Shell::CreateShell(WebContents* web_contents,
const gfx::Size& initial_size) {
Shell* shell = new Shell(web_contents);
......
shell->web_contents_.reset(web_contents);
......
shell->PlatformSetContents();
......
return shell;
}
这个函数定义在文件external/chromium_org/content/shell/browser/shell.cc中。
从前面的调用过程可以知道,参数web_contents指向的是一个WebContentsImpl对象。
Shell类的静态成员函数CreateShell首先创建了一个Shell对象,接下来将参数web_contents指向的WebContentsImpl对象保存在该Shell对象的成员变量web_contents_中,最后又调用该Shell对象的成员函数PlatformSetContents执行一些平台相关的初始化操作。
Shell类的成员函数PlatformSetContents的实现如下所示:
void Shell::PlatformSetContents() {
JNIEnv* env = AttachCurrentThread();
Java_Shell_initFromNativeTabContents(
env, java_object_.obj(), reinterpret_cast<intptr_t>(web_contents()));
}
这个函数定义在文件external/chromium_org/content/shell/browser/shell_android.cc中。
Shell类的成员函数PlatformSetContents调用函数Java_Shell_initFromNativeTabContents调用成员变量java_object_描述的一个Java层Shell对象的成员函数initFromNativeTabContents执行平台相关的初始化操作。同时传递给该Java层Shell对象的成员函数initFromNativeTabContents一个WebContentsImpl对象。这个WebContentsImpl对象是通过调用Native层Shell类的成员函数web_contents获得的,如下所示:
class Shell : public WebContentsDelegate,
public WebContentsObserver {
public:
......
WebContents* web_contents() const { return web_contents_.get(); }
......
private:
......
scoped_ptr<WebContents> web_contents_;
......
}
这个函数定义在文件external/chromium_org/content/shell/browser/shell.h中。
从前面的分析可以知道,Shell类的成员变量web_contents_指向的一个WebContentsImpl对象,Shell类的成员函数web_contents将这个WebContentsImpl对象返回给调用者。
接下来我们继续分析Java层Shell类的成员函数initFromNativeTabContents的实现,如下所示:
public class Shell extends LinearLayout {
......
private ContentViewCore mContentViewCore;
......
@CalledByNative
private void initFromNativeTabContents(long nativeWebContents) {
Context context = getContext();
mContentViewCore = new ContentViewCore(context);
......
mContentViewCore.initialize(cv, cv, nativeWebContents, mWindow);
......
}
......
}
这个函数定义在文件external/chromium_org/content/shell/android/java/src/org/chromium/content_shell/Shell.java中。
从前面的调用过程可以知道,参数nativeWebContents描述的实际上是一个Native层的WebContentsImpl对象。Shell类的成员函数initFromNativeTabContents主要是创建了一个ContentViewCore对象,保存在成员变量mContentViewCore中,并且调用该ContentViewCore对象的成员函数initialize执行初始化操作。
ContenttViewCore类的成员函数initialize的实现如下所示:
public class ContentViewCore
implements NavigationClient, AccessibilityStateChangeListener, ScreenOrientationObserver {
......
private long mNativeContentViewCore = 0;
......
public void initialize(ViewGroup containerView, InternalAccessDelegate internalDispatcher,
long nativeWebContents, WindowAndroid windowAndroid) {
......
mNativeContentViewCore = nativeInit(
nativeWebContents, viewAndroidNativePointer, windowNativePointer,
mRetainedJavaScriptObjects);
......
}
......
}
这个函数定义在文件external/chromium_org/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java中。
ContentViewCore类的成员函数initialize执行了一个操作,就是调用另外一个成员函数nativeInit创建了一个Native层的ContentViewCoreImpl对象,并且将它的地址保存在成员变量mNativeContentViewCore中。
ContentViewCore类的成员函数nativeInit是一个JNI函数,由Native层的Java_com_android_org_chromium_content_browser_ContentViewCore_nativeInit函数实现,如下所示:
static jlong Init(JNIEnv* env, jobject jcaller,
jlong webContentsPtr,
jlong viewAndroidPtr,
jlong windowAndroidPtr,
jobject retainedObjectSet);
__attribute__((visibility("default")))
jlong
Java_com_android_org_chromium_content_browser_ContentViewCore_nativeInit(JNIEnv*
env, jobject jcaller,
jlong webContentsPtr,
jlong viewAndroidPtr,
jlong windowAndroidPtr,
jobject retainedObjectSet) {
return Init(env, jcaller, webContentsPtr, viewAndroidPtr, windowAndroidPtr,
retainedObjectSet);
}
这个函数定义在文件out/target/product/generic/obj/GYP/shared_intermediates/content/jni/ContentViewCore_jni.h中。
函数Java_com_android_org_chromium_content_browser_ContentViewCore_nativeInit调用另外一个函数Init创建一个Native层的ContentViewCoreImpl对象,并且将该ContentViewCoreImpl对象的地址返回给调用者。
函数Init的实现如下所示:
jlong Init(JNIEnv* env,
jobject obj,
jlong native_web_contents,
jlong view_android,
jlong window_android,
jobject retained_objects_set) {
ContentViewCoreImpl* view = new ContentViewCoreImpl(
env, obj,
reinterpret_cast<WebContents*>(native_web_contents),
reinterpret_cast<ui::ViewAndroid*>(view_android),
reinterpret_cast<ui::WindowAndroid*>(window_android),
retained_objects_set);
return reinterpret_cast<intptr_t>(view);
}
这个函数定义在文件external/chromium_org/content/browser/android/content_view_core_impl.cc中。
从这里可以看到,函数Init创建了一个ContentViewCoreImpl对象,并且将该ContentViewCoreImpl对象的地址返回给调用者。
ContentViewCoreImpl对象的创建过程,即ContentViewCoreImpl类的构造函数的实现,如下所示:
ContentViewCoreImpl::ContentViewCoreImpl(
JNIEnv* env,
jobject obj,
WebContents* web_contents,
ui::ViewAndroid* view_android,
ui::WindowAndroid* window_android,
jobject java_bridge_retained_object_set)
: ......,
web_contents_(static_cast<WebContentsImpl*>(web_contents)),
...... {
......
}
这个函数定义在文件external/chromium_org/content/browser/android/content_view_core_impl.cc中。
从前面的调用过程可以知道,参数web_contents描述的是一个WebContentsImpl对象。这个WebContentsImpl对象保存在ContentViewCoreImpl类的成员变量web_contents_中。
这一步执行完成后,Browser进程在加载一个URL之前,就在Native层创建了一个Shell对象和一个WebContentsImpl对象。创建的Native层WebContentsImpl对象内部维护有一个Frame Tree。创建的Native层Shell对象在Java层也有一个对应的Shell对象。这个Java层的Shell对象的创建过程可以参考前面Chromium硬件加速渲染的OpenGL上下文绘图表面创建过程分析一文。
从前面Chromium硬件加速渲染的OpenGL上下文绘图表面创建过程分析一文还可以知道,Browser进程接下来会调用上述Java层Shell对象的成员函数loadUrl加载指定的URL,它的实现如下所示:
public class Shell extends LinearLayout {
......
public void loadUrl(String url) {
......
if (TextUtils.equals(url, mContentViewCore.getUrl())) {
mContentViewCore.reload(true);
} else {
mContentViewCore.loadUrl(new LoadUrlParams(sanitizeUrl(url)));
}
......
}
......
}
这个函数定义在文件external/chromium_org/content/shell/android/java/src/org/chromium/content_shell/Shell.java中。
从前面的分析可以知道,Shell类的成员变量mContentViewCore指向的是一个ContentViewCore对象,Shell类的成员函数loadUrl调用它的成员函数reload或者loadUrl加载参数url描述的URL,取决于该ContentViewCore对象之前是否加载过URL,以及加载过的URL是否与参数url描述的URL相同。
我们假设Shell类的成员变量mContentViewCore指向的ContentViewCore对象之前没有加载过URL,那么Shell类的成员函数loadUrl接下来就会调用它的成员函数loadUrl加载参数url描述的URL。
ContentViewCore类的成员函数loadUrl的实现如下所示:
public class ContentViewCore
implements NavigationClient, AccessibilityStateChangeListener, ScreenOrientationObserver {
......
public void loadUrl(LoadUrlParams params) {
......
nativeLoadUrl(mNativeContentViewCore,
params.mUrl,
params.mLoadUrlType,
params.mTransitionType,
params.getReferrer() != null ? params.getReferrer().getUrl() : null,
params.getReferrer() != null ? params.getReferrer().getPolicy() : 0,
params.mUaOverrideOption,
params.getExtraHeadersString(),
params.mPostData,
params.mBaseUrlForDataUrl,
params.mVirtualUrlForDataUrl,
params.mCanLoadLocalResources,
params.mIsRendererInitiated);
}
......
}
这个函数定义在文件external/chromium_org/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java中。
ContentViewCore类的成员函数loadUrl调用另外一个成员函数nativeLoadUrl加载参数params描述的URL。
ContentViewCore类的成员函数nativeLoadUrl是一个JNI函数,由Native层的函数Java_com_android_org_chromium_content_browser_ContentViewCore_nativeLoadUrl实现,如下所示:
__attribute__((visibility("default")))
void
Java_com_android_org_chromium_content_browser_ContentViewCore_nativeLoadUrl(JNIEnv*
env,
jobject jcaller,
jlong nativeContentViewCoreImpl,
jstring url,
jint loadUrlType,
jint transitionType,
jstring referrerUrl,
jint referrerPolicy,
jint uaOverrideOption,
jstring extraHeaders,
jbyteArray postData,
jstring baseUrlForDataUrl,
jstring virtualUrlForDataUrl,
jboolean canLoadLocalResources,
jboolean isRendererInitiated) {
ContentViewCoreImpl* native =
reinterpret_cast<ContentViewCoreImpl*>(nativeContentViewCoreImpl);
CHECK_NATIVE_PTR(env, jcaller, native, "LoadUrl");
return native->LoadUrl(env, jcaller, url, loadUrlType, transitionType,
referrerUrl, referrerPolicy, uaOverrideOption, extraHeaders, postData,
baseUrlForDataUrl, virtualUrlForDataUrl, canLoadLocalResources,
isRendererInitiated);
}
这个函数定义在文件out/target/product/generic/obj/GYP/shared_intermediates/content/jni/ContentViewCore_jni.h中。
从前面的调用过程可以知道,参数nativeContentViewCoreImpl来自Java层的ContentViewCore类的成员变量mNativeContentViewCore。ContentViewCore类的成员变量mNativeContentViewCore指向的是一个Native层的ContentViewCoreImpl对象。因此,函数Java_com_android_org_chromium_content_browser_ContentViewCore_nativeLoadUrl可以将参数nativeContentViewCoreImpl强制转换为一个Native层的ContentViewCoreImpl对象,并且会调用该Native层ContentViewCoreImpl对象的成员函数LoadUrl加载参数url描述的URL。
ContentViewCoreImpl类的成员函数LoadUrl的实现如下所示:
void ContentViewCoreImpl::LoadUrl(
JNIEnv* env, jobject obj,
jstring url,
jint load_url_type,
jint transition_type,
jstring j_referrer_url,
jint referrer_policy,
jint ua_override_option,
jstring extra_headers,
jbyteArray post_data,
jstring base_url_for_data_url,
jstring virtual_url_for_data_url,
jboolean can_load_local_resources,
jboolean is_renderer_initiated) {
......
NavigationController::LoadURLParams params(
GURL(ConvertJavaStringToUTF8(env, url)));
......
LoadUrl(params);
}
这个函数定义在文件external/chromium_org/content/browser/android/content_view_core_impl.cc中。
ContentViewCoreImpl类的成员函数LoadUrl主要是将要加载的URL封装在一个NavigationController::LoadURLParams对象中,并且调用另外一个重载版本的成员函数LoadUrl执行加载该URL的操作,如下所示:
void ContentViewCoreImpl::LoadUrl(
NavigationController::LoadURLParams& params) {
GetWebContents()->GetController().LoadURLWithParams(params);
}
这个函数定义在文件external/chromium_org/content/browser/android/content_view_core_impl.cc中。
ContentViewCoreImpl类的成员函数LoadUrl首先调用另外一个成员函数GetWebContents获得一个WebContentsImpl对象,如下所示:
WebContents* ContentViewCoreImpl::GetWebContents() const {
return web_contents_;
}
这个函数定义在文件external/chromium_org/content/browser/android/content_view_core_impl.cc中。
从前面的分析可以知道,ContentViewCoreImpl类的成员变量web_contents_指向的是一个WebContentsImpl对象,ContentViewCoreImpl类的成员函数GetWebContents将它返回给调用者。
回到ContentViewCoreImpl类的成员函数LoadUrl,它获得了一个WebContentsImpl对象之后,再调用该WebContentsImpl对象的成员函数GetController获得一个NavigationControllerImpl对象,如下所示:
NavigationControllerImpl& WebContentsImpl::GetController() {
return controller_;
}
这个函数定义在文件external/chromium_org/content/browser/web_contents/web_contents_impl.cc中。
从前面的分析可以知道,WebContentsImpl类的成员变量controller_描述的是一个NavigationControllerImpl对象,WebContentsImpl类的成员函数GetController将它返回给调用者。
回到ContentViewCoreImpl类的成员函数LoadUrl,它获得了一个NavigationControllerImpl对象之后,再调用该NavigationControllerImpl对象的成员函数LoadURLWithParams加载参数params描述的URL,如下所示:
void NavigationControllerImpl::LoadURLWithParams(const LoadURLParams& params) {
......
NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
CreateNavigationEntry(
params.url,
params.referrer,
params.transition_type,
params.is_renderer_initiated,
params.extra_headers,
browser_context_));
......
LoadEntry(entry);
}
这个函数定义在文件external/chromium_org/content/browser/frame_host/navigation_controller_impl.cc中。
NavigationControllerImpl类的成员函数LoadURLWithParams首先是调用静态成员函数CreateNavigationEntry创建一个NavigationEntryImpl对象,如下所示:
NavigationEntry* NavigationController::CreateNavigationEntry(
const GURL& url,
const Referrer& referrer,
PageTransition transition,
bool is_renderer_initiated,
const std::string& extra_headers,
BrowserContext* browser_context) {
......
NavigationEntryImpl* entry = new NavigationEntryImpl(
NULL, // The site instance for tabs is sent on navigation
// (WebContents::GetSiteInstance).
-1,
loaded_url,
referrer,
base::string16(),
transition,
is_renderer_initiated);
......
return entry;
}
这个函数定义在文件external/chromium_org/content/browser/frame_host/navigation_controller_impl.cc中。
从这里可以看到,NavigationControllerImpl类的静态成员函数CreateNavigationEntry创建出来的NavigationEntryImpl对象封装了参数url描述的URL。
注意,NavigationControllerImpl类的静态成员函数CreateNavigationEntry返回的是一个NavigationEntry指针,但是它实际上指向的是一个NavigationEntryImpl对象,NavigationControllerImpl类的成员函数LoadURLWithParams会通过调用NavigationEntryImpl类的静态成员函数FromNavigationEntry将该得到的NavigationEntry指针强制转换为一个NavigationEntryImpl对象,如下所示:
NavigationEntryImpl* NavigationEntryImpl::FromNavigationEntry(
NavigationEntry* entry) {
return static_cast<NavigationEntryImpl*>(entry);
}
这个函数定义在文件external/chromium_org/content/browser/frame_host/navigation_entry_impl.cc中。
回到NavigationControllerImpl类的成员函数LoadURLWithParams中,它将要加载的URL封装在一个NavigationEntryImpl对象之后,传递给另外一个成员函数LoadEntry,让后者执行加载URL的操作。
NavigationControllerImpl类的成员函数LoadEntry的实现如下所示:
void NavigationControllerImpl::LoadEntry(NavigationEntryImpl* entry) {
// When navigating to a new page, we don't know for sure if we will actually
// end up leaving the current page. The new page load could for example
// result in a download or a 'no content' response (e.g., a mailto: URL).
SetPendingEntry(entry);
NavigateToPendingEntry(NO_RELOAD);
}
这个函数定义在文件external/chromium_org/content/browser/frame_host/navigation_controller_impl.cc中。
NavigationControllerImpl类的成员函数LoadEntry首先调用另外一个成员函数SetPendingEntry将参数entry指向的一个NavigationEntryImpl对象保存在成员变量pending_entry_中,表示NavigationEntryImpl对象封装的URL正在等待加载,如下所示:
void NavigationControllerImpl::SetPendingEntry(NavigationEntryImpl* entry) {
......
pending_entry_ = entry;
......
}
这个函数定义在文件external/chromium_org/content/browser/frame_host/navigation_controller_impl.cc中。
回到NavigationControllerImpl类的成员函数LoadEntry中,将要加载的URL保存在成员变量pending_entry_之后,接下来就调用另外一个成员函数NavigateToPendingEntry对其进行加载,如下所示:
void NavigationControllerImpl::NavigateToPendingEntry(ReloadType reload_type) {
......
bool success = delegate_->NavigateToPendingEntry(reload_type);
......
}
这个函数定义在文件external/chromium_org/content/browser/frame_host/navigation_controller_impl.cc中。
从前面的分析可以知道,NavigationControllerImpl类的成员变量delegate_指向的是一个WebContentsImpl对象,NavigationControllerImpl类的成员函数NavigateToPendingEntry调用它的成员函数NavigateToPendingEntry加载前面指定的URL。
WebContentsImpl类的成员函数NavigateToPendingEntry的实现如下所示:
bool WebContentsImpl::NavigateToPendingEntry(
NavigationController::ReloadType reload_type) {
FrameTreeNode* node = frame_tree_.root();
......
return node->navigator()->NavigateToPendingEntry(
node->current_frame_host(), reload_type);
}
这个函数定义在文件external/chromium_org/content/browser/web_contents/web_contents_impl.cc中。
从前面的分析可以知道,WebContentsImpl类的成员变量frame_tree_指向的是一个FrameTree对象。这个FrameTree对象描述的是一个Frame Tree。WebContentsImpl类的成员函数NavigateToPendingEntry调用这个FrameTree对象的成员函数root可以获得一个FrameTreeNode对象。这个FrameTreeNode对象代表的就是正在等待加载的网页的Main Frame。
WebContentsImpl类的成员函数NavigateToPendingEntry接下来调用前面获得的FrameTreeNode对象的成员函数navigator和current_frame_host分别获得一个NavigatorImpl对象和一个RenderFrameHostImpl对象。
FrameTreeNode类的成员函数navigator的实现如下所示:
class CONTENT_EXPORT FrameTreeNode {
public:
......
Navigator* navigator() {
return navigator_.get();
}
......
private:
......
scoped_refptr<Navigator> navigator_;
......
}
这个函数定义在文件external/chromium_org/content/browser/frame_host/frame_tree_node.h中。
从前面的分析可以知道,FrameTreeNode类的成员变量navigator_指向的是一个NavigatorImpl对象,FrameTreeNode对象的成员函数navigator会将这个NavigatorImpl对象返回给调用者。
FrameTreeNode类的成员函数current_frame_host的实现如下所示:
class CONTENT_EXPORT FrameTreeNode {
public:
......
RenderFrameHostImpl* current_frame_host() const {
return render_manager_.current_frame_host();
}
private:
......
RenderFrameHostManager render_manager_;
......
};
这个函数定义在文件external/chromium_org/content/browser/frame_host/frame_tree_node.h中。
FrameTreeNode类的成员函数current_frame_host调用成员变量render_manager_描述的一个RenderFrameHostManager对象的成员函数current_frame_host获得一个RenderFrameHostImpl对象返回给调用者。
RenderFrameHostManager类的成员函数current_frame_host的实现如下所示:
class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
public:
......
RenderFrameHostImpl* current_frame_host() const {
return render_frame_host_.get();
}
......
private:
......
scoped_ptr<RenderFrameHostImpl> render_frame_host_;
......
};
这个函数定义在文件external/chromium_org/content/browser/frame_host/render_frame_host_manager.h
RenderFrameHostManager类的成员函数current_frame_host返回的是成员变量render_frame_host_描述的一个RenderFrameHostImpl对象。这个RenderFrameHostImpl对象是在前面分析的RenderFrameHostFactory类的静态成员函数Create中创建的。
回到WebContentsImpl类的成员函数NavigateToPendingEntry中,它获得了一个NavigatorImpl对象和一个RenderFrameHostImpl对象之后,就调用获得的NavigatorImpl对象的成员函数NavigateToPendingEntry加载正在等待加载的URL,如下所示:
bool NavigatorImpl::NavigateToPendingEntry(
RenderFrameHostImpl* render_frame_host,
NavigationController::ReloadType reload_type) {
return NavigateToEntry(
render_frame_host,
*NavigationEntryImpl::FromNavigationEntry(controller_->GetPendingEntry()),
reload_type);
}
这个函数定义在文件external/chromium_org/content/browser/frame_host/navigator_impl.cc中。
从前面的分析可以知道,NavigatorImpl类的成员变量controller_描述的是一个NavigationControllerImpl对象,NavigatorImpl对象的成员函数NavigateToPendingEntry首先会调用这个NavigationControllerImpl对象的成员函数GetPendingEntry获得正在等待加载的URL,如下所示:
NavigationEntry* NavigationControllerImpl::GetPendingEntry() const {
return pending_entry_;
}
这个函数定义在文件external/chromium_org/content/browser/frame_host/navigation_controller_impl.cc中。
NavigationControllerImpl对象的成员函数GetPendingEntry返回的是成员变量pending_entry_描述的一个NavigationEntryImpl对象。从前面的分析可以知道,这个NavigationEntryImpl对象描述的就是正在等待加载的URL。
回到NavigatorImpl类的成员函数NavigateToPendingEntry中,获得了等待加载的URL之后,它接下来调用另外一个成员函数NavigateToEntry对该URL进行加载,如下所示:
bool NavigatorImpl::NavigateToEntry(
RenderFrameHostImpl* render_frame_host,
const NavigationEntryImpl& entry,
NavigationController::ReloadType reload_type) {
......
RenderFrameHostManager* manager =
render_frame_host->frame_tree_node()->render_manager();
RenderFrameHostImpl* dest_render_frame_host = manager->Navigate(entry);
// Navigate in the desired RenderFrameHost.
FrameMsg_Navigate_Params navigate_params;
MakeNavigateParams(entry, *controller_, reload_type, &navigate_params);
dest_render_frame_host->Navigate(navigate_params);
......
}
这个函数定义在文件external/chromium_org/content/browser/frame_host/navigator_impl.cc中。
从前面的调用过程可以知道,参数render_frame_host描述的就是前面调用RenderFrameHostManager类的成员函数current_frame_host获得的RenderFrameHostImpl对象。NavigatorImpl类的成员函数NavigateToEntry首先获得这个RenderFrameHostImpl对象对应的Frame Tree Node,接着又获得该Frame Tree Node所关联的RenderFrameHostManager对象。有了这个RenderFrameHostManager对象之后,NavigatorImpl类的成员函数NavigateToEntry就调用它的成员函数Navigate,用来通知它即将要导航到指定的URL去。
RenderFrameHostManager类的成员函数Navigate会返回一个RenderFrameHostImpl对象dest_render_frame_host。RenderFrameHostImpl对象dest_render_frame_host与RenderFrameHostImpl对象render_frame_host有可能是相同的,也有可能是不同的。什么情况下相同呢?如果上述RenderFrameHostManager对象即将要导航到的URL与它之前已经导航至的URL属于相同站点,那么就是相同的。反之则是不同的。无论是哪一种情况,导航至指定的URL的操作最后都是通过调用RenderFrameHostImpl对象dest_render_frame_host的成员函数Navigate完成的。
接下来我们就先分析RenderFrameHostManager类的成员函数Navigate的实现,然后再分析RenderFrameHostImpl类的成员函数Navigate的实现。
RenderFrameHostManager类的成员函数Navigate的实现如下所示:
RenderFrameHostImpl* RenderFrameHostManager::Navigate(
const NavigationEntryImpl& entry) {
......
RenderFrameHostImpl* dest_render_frame_host = UpdateStateForNavigate(entry);
......
if (!dest_render_frame_host->render_view_host()->IsRenderViewLive()) {
......
if (!InitRenderView(dest_render_frame_host->render_view_host(),
opener_route_id,
MSG_ROUTING_NONE,
frame_tree_node_->IsMainFrame()))
return NULL;
......
}
......
return dest_render_frame_host;
}
这个函数定义在文件external/chromium_org/content/browser/frame_host/render_frame_host_manager.cc中。
RenderFrameHostManager类的成员函数Navigate首先调用另外一个成员函数UpdateStateForNavigate获得与即将要加载的URL对应的一个RenderFrameHostImpl对象。获得了这个RenderFrameHostImpl对象之后,调用它的成员函数render_view_host可以获得一个RenderViewHostImpl对象。这个RenderViewHostImpl对象是在前面分析的RenderFrameHostManager类的成员函数CreateRenderFrameHost中创建的。有了这个RenderViewHostImpl对象之后,就可以调用它的成员函数IsRenderViewLive判断它是否关联有一个Render View控件。这个Render View控件是一个由平台实现的控件,描述的是用来显示网页的一个区域。
在两种情况下,一个RenderViewHostImpl对象没有关联一个Render View控件。第一种情况是这个RenderViewHostImpl对象还没有加载过URL。第二种情况下是这个RenderViewHostImpl对象加载过URL,但是由于某种原因,负责加载该URL的Render进程崩溃了。在第二种情况下,一个RenderViewHostImpl对象关联的Render View控件会被销毁,所以会导致它没有关联Render View控件。无论是上述两种情况的哪一种,RenderFrameHostManager类的成员函数Navigate都会调用另外一个成员函数InitRenderView为其关联一个Render View控件。
接下来,我们就分别分析RenderFrameHostManager类的成员函数UpdateStateForNavigate和InitRenderView的实现。
RenderFrameHostManager类的成员函数UpdateStateForNavigate的实现如下所示:
RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate(
const NavigationEntryImpl& entry) {
......
SiteInstance* current_instance = render_frame_host_->GetSiteInstance();
SiteInstance* new_instance = current_instance;
......
const NavigationEntry* current_entry =
delegate_->GetLastCommittedNavigationEntryForRenderManager();
bool force_swap = !is_guest_scheme &&
ShouldSwapBrowsingInstancesForNavigation(current_entry, &entry);
if (!is_guest_scheme && (ShouldTransitionCrossSite() || force_swap))
new_instance = GetSiteInstanceForEntry(entry, current_instance, force_swap);
......
if (new_instance != current_instance) {
......
return pending_render_frame_host_.get();
}
......
return render_frame_host_.get();
}
这个函数定义在文件external/chromium_org/content/browser/frame_host/render_frame_host_manager.cc中。
RenderFrameHostManager类的成员变量render_frame_host_描述的是一个RenderFrameHostImpl对象。这个RenderFrameHostImpl对象是在前面分析的RenderFrameHostFactory类的静态成员函数Create中创建的,与前面分析的NavigatorImpl类的成员函数NavigateToEntry的参数render_frame_host描述的RenderFrameHostImpl对象是相同的。
RenderFrameHostManager类的成员函数UpdateStateForNavigate主要做的事情就是检查即将要加载的URL,即参数entry描述的一个URL,与当前已经加载的URL,是否属于相同的站点。如果是不相同的站点,那么RenderFrameHostManager类的成员变量pending_render_frame_host_会指向另外一个RenderFrameHostImpl对象。这个RenderFrameHostImpl对象负责加载参数entry描述的URL。因此,这个RenderFrameHostImpl对象会返回给调用者。
以上是关于Chromium网页Frame Tree创建过程分析的主要内容,如果未能解决你的问题,请参考以下文章
Chromium网页Graphics Layer Tree创建过程分析
Chromium网页Pending Layer Tree激活为Active Layer Tree的过程分析