[Chrome源码阅读]Chrome增加一个New Tab时都干了些什么

http://blog.csdn.net/zero_lee/article/details/7896856?reload

当我们通过TAB栏上的"+"标签增加一个新的空TAB时,Chrome内部的代码是怎么样的呢?这篇文章将会介绍它内部的流程。

首先用一个callstack截图来看下它的前一段处理流程:


TAB旁边的那个“+”(注意不是"New Tab (Ctrl+T)")菜单,在Chrome中是一个button。这个button是放置在TabStrip 视图类中的。TabStrip类捕捉到了这个button pressed事件,立即响应,调用TabStripModel实例的AddBlankTab函数(前面文章讲到过TabStrip维护一个TabStripModel的指针,同时TabStrip视图也是TabStripModel数据类的观察者)。看上去很简单。

TabStripModel::AddBlankTab函数实现也很简单,创建一个TabContents实例,然后将其添加到TabContentsData列表中进行管理。

  1. TabContents* TabStripModel::AddBlankTab(bool foreground) {  
  2.   TabContents* contents = delegate_->CreateTabContentsForURL(  
  3.       delegate_->GetBlankTabURL(), GURL(), profile_, PageTransition::TYPED,  
  4.       false, NULL);  
  5.   AddTabContents(contents, -1, PageTransition::TYPED, foreground);  
  6.   return contents;  
  7. }  
上面的delegate_是Browser实例。Browser才是真正干活的人。根据content类型(Web/DOMUI/,etc)创建一个具体的TabContents实例。注意此时传入的instance为NULL,表明这是个空的site instance,不会进行导航。而且def_load为false。

  1. TabContents* contents = TabContents::CreateWithType(type, profile, instance);  
  2. contents->SetupController(profile);  
  3.   
  4. if (!defer_load) {  
  5.   // Load the initial URL before adding the new tab contents to the tab strip  
  6.   // so that the tab contents has navigation state.  
  7.   contents->controller()->LoadURL(url, referrer, transition);  
  8. }  
TabContents::CreateWithType做了很多很多的事情。因为WebContents是一个很复杂的类,看看它的构造函数就知道了。

  1. WebContents::WebContents(Profile* profile,  
  2.                          SiteInstance* site_instance,  
  3.                          RenderViewHostFactory* render_view_factory,  
  4.                          int routing_id,  
  5.                          base::WaitableEvent* modal_dialog_event)  
  6.     : TabContents(TAB_CONTENTS_WEB),  
  7.       view_(WebContentsView::Create(this)),  
  8.       ALLOW_THIS_IN_INITIALIZER_LIST(  
  9.           render_manager_(render_view_factory, thisthis)),  
  10.       render_view_factory_(render_view_factory),  
  11.       printing_(*this),  
  12.       notify_disconnection_(false),  
  13.       received_page_title_(false),  
  14.       is_starred_(false),  
  15. #if defined(OS_WIN)  
  16.       message_box_active_(CreateEvent(NULL, TRUE, FALSE, NULL)),  
  17. #endif  
  18.       ALLOW_THIS_IN_INITIALIZER_LIST(fav_icon_helper_(this)),  
  19.       suppress_javascript_messages_(false),  
  20.       load_state_(net::LOAD_STATE_IDLE),  
  21.       find_ui_active_(false),  
  22.       find_op_aborted_(false),  
  23.       current_find_request_id_(find_request_id_counter_++) {  
  24.   pending_install_.page_id = 0;  
  25.   pending_install_.callback_functor = NULL;  
  26.   
  27.   render_manager_.Init(profile, site_instance, routing_id, modal_dialog_event);  
  28.   
  29.   // Register for notifications about all interested prefs change.  
  30.   PrefService* prefs = profile->GetPrefs();  
  31.   if (prefs) {  
  32.     for (int i = 0; i < kPrefsToObserveLength; ++i)  
  33.       prefs->AddPrefObserver(kPrefsToObserve[i], this);  
  34.   }  
  35.   
  36.   // Register for notifications about URL starredness changing on any profile.  
  37.   NotificationService::current()->AddObserver(  
  38.       this, NotificationType::URLS_STARRED, NotificationService::AllSources());  
  39.   NotificationService::current()->AddObserver(  
  40.       this, NotificationType::BOOKMARK_MODEL_LOADED,  
  41.       NotificationService::AllSources());  
  42.   NotificationService::current()->AddObserver(  
  43.       this, NotificationType::RENDER_WIDGET_HOST_DESTROYED,  
  44.       NotificationService::AllSources());  
  45. }  
构造函数首先构造基类TabContents,它的构造仅仅是初始化一些变量而已,没多少事情可以做。但是WebContents实现了很多接口:RenderViewHostManager::Delegate,RenderViewHostDelegate。它维护着一个RenderViewHostManager,所以需要初始化。RenderViewHostManager::Init函数会实例化一个RenderViewHost,要知道RenderViewHost继承自RenderWidgetHost,实例化RenderWidgetHost时需要RenderProcessHost实例的,也就是说实例化一个RenderViewHost就会实例化一个RenderProcessHost,由SiteInstance进行管理。

创建完WebContents之后,就要Setup一个Navigation Controller,用profile来实例化一个Navigation Controller。

总体来说,实例化一个WebContents时,就需要顺带着实例化RenderViewHost/RenderProcessHost,和NavigationController。当然在某些情况下会重用已经存在的RenderViewHost/RenderProcessHost。

调用NavigationController的LoadURL函数来导航到新的URL地址。这里面还有更多内容。继续跟踪代码:


我们通常叫这个新的Site为pending状态,所以就是NavigateToPendingEntry。每个NavigationController会维护这个一个Entry列表,代表这个TAB页面导航多的site历史。

  1. bool WebContents::NavigateToPendingEntry(bool reload) {  
  2.   NavigationEntry* entry = controller()->GetPendingEntry();  
  3.   RenderViewHost* dest_render_view_host = render_manager_.Navigate(*entry);  
  4.   if (!dest_render_view_host)  
  5.     return false;  // Unable to create the desired render view host.  
  6.   
  7.   // Used for page load time metrics.  
  8.   current_load_start_ = TimeTicks::Now();  
  9.   
  10.   // Navigate in the desired RenderViewHost.  
  11.   dest_render_view_host->NavigateToEntry(*entry, reload);  
请注意,之前在实例化一个TabContents时,实例化一个RenderViewHost,那时的SiteInstance表示为空。但是Navigation时,SiteInstance不可能为空,也就是这是的entry需要另外一个RenderViewHost,也就是因为这个Navigate进行了复杂的处理。

RenderViewHostManager维护2个RenderViewHost,一个是Pending render view host,另一个是Active render view host。当初始化Render View Host Manager时,那时初始化的render view host就是active render view host。现在导航是需要的render view host,就是pending render view host。所以render_manager_.Navigate函数将会创建一个新的render view host。而且更重要的是此时会创建一个RenderView与pending RenderViewHost对应。WebContents::CreatePendingRenderView函数将这2件事都做了。

  1. // Create a pending RVH and navigate it.  
  2.     bool success = CreatePendingRenderView(new_instance);  
  3.     if (!success)  
  4.       return NULL;  
  5.   
  6.     // Check if our current RVH is live before we set up a transition.  
  7.     if (!render_view_host_->IsRenderViewLive()) {  
  8.       if (!cross_navigation_pending_) {  
  9.         // The current RVH is not live.  There's no reason to sit around with a  
  10.         // sad tab or a newly created RVH while we wait for the pending RVH to  
  11.         // navigate.  Just switch to the pending RVH now and go back to non  
  12.         // cross-navigating (Note that we don't care about on{before}unload  
  13.         // handlers if the current RVH isn't live.)  
  14.         SwapToRenderView(&pending_render_view_host_, true);  
  15.         return render_view_host_;  
CreatePendingRenderView函数实现:
  1. pending_render_view_host_ =  
  2.     CreateRenderViewHost(instance, MSG_ROUTING_NONE, NULL);  
  3.   
  4. bool success = delegate_->CreateRenderViewForRenderManager(  
  5.     pending_render_view_host_);  

所以在创建一个新的RenderView时,就需要启动一个新的RenderView进程了


注意,在创建一个pending render view host之后,就需要将这个render view host与之前的active render view host进行交换,此时的pending就变成了active render view了。销毁之前的render view host。


有一个全局的RenderProcessHost列表,仅仅是维护一个RenderProcessHost指针。

  1. // the global list of all renderer processes  
  2. IDMap<RenderProcessHost> all_hosts;  

注意,销毁每个RenderViewHost时会调用RenderProcessHost的Release函数,这个函数里可能会delete自己,根据当前监听的对象个数。RenderProcessHost维护一个监听者列表,以ID为key,其实就是RenderViewHost对象,因为它继承于IPC::Channel::Listener,而且多个RenderViewHost可共享同一个RenderProcessHost,比如在--process-per-site-instance进程模式下,由同一个网址链接打开的所有的网址/TAB。在构造每个RenderViewHost时,都会将自己添加到RenderProcessHost的这个listeners_列表中建立连接,一旦连接的所有的RenderViewHost都销毁了,RenderProcessHost才销毁。

  1. void RenderProcessHost::Release(int listener_id) {  
  2.   DCHECK(listeners_.Lookup(listener_id) != NULL);  
  3.   listeners_.Remove(listener_id);  
  4.   
  5.   // Make sure that all associated resource requests are stopped.  
  6.   CancelResourceRequests(listener_id);  
  7.   
  8.   // When no other owners of this object, we can delete ourselves  
  9.   if (listeners_.IsEmpty()) {  
  10.     if (!notified_termination_) {  
  11.       bool close_expected = true;  
  12.       NotificationService::current()->Notify(  
  13.           NotificationType::RENDERER_PROCESS_TERMINATED,  
  14.           Source<RenderProcessHost>(this),  
  15.           Details<bool>(&close_expected));  
  16.       notified_termination_ = true;  
  17.     }  
  18.     Unregister();  
  19.     MessageLoop::current()->DeleteSoon(FROM_HERE, this);  
  20.   }  
  21. }  

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值