Home | History | Annotate | Download | only in task_manager
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/task_manager/web_contents_resource_provider.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/bind_helpers.h"
      9 #include "chrome/browser/browser_process.h"
     10 #include "chrome/browser/prerender/prerender_manager.h"
     11 #include "chrome/browser/prerender/prerender_manager_factory.h"
     12 #include "chrome/browser/profiles/profile.h"
     13 #include "chrome/browser/profiles/profile_manager.h"
     14 #include "chrome/browser/task_manager/renderer_resource.h"
     15 #include "chrome/browser/task_manager/task_manager.h"
     16 #include "chrome/browser/task_manager/task_manager_util.h"
     17 #include "chrome/browser/task_manager/web_contents_information.h"
     18 #include "content/public/browser/render_frame_host.h"
     19 #include "content/public/browser/render_process_host.h"
     20 #include "content/public/browser/render_view_host.h"
     21 #include "content/public/browser/render_widget_host_iterator.h"
     22 #include "content/public/browser/web_contents.h"
     23 #include "content/public/browser/web_contents_observer.h"
     24 
     25 using content::WebContents;
     26 using content::RenderViewHost;
     27 
     28 namespace task_manager {
     29 
     30 // A WebContentsObserver that tracks changes to a WebContents on behalf of
     31 // a WebContentsResourceProvider.
     32 class TaskManagerWebContentsObserver : public content::WebContentsObserver {
     33  public:
     34   TaskManagerWebContentsObserver(WebContents* web_contents,
     35                                  WebContentsResourceProvider* provider)
     36       : content::WebContentsObserver(web_contents), provider_(provider) {}
     37 
     38   // content::WebContentsObserver implementation.
     39   virtual void RenderViewHostChanged(RenderViewHost* old_host,
     40                                      RenderViewHost* new_host) OVERRIDE {
     41     provider_->RemoveFromTaskManager(web_contents());
     42     provider_->AddToTaskManager(web_contents());
     43   }
     44 
     45   virtual void RenderViewReady() OVERRIDE {
     46     provider_->RemoveFromTaskManager(web_contents());
     47     provider_->AddToTaskManager(web_contents());
     48   }
     49 
     50   virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE {
     51     provider_->RemoveFromTaskManager(web_contents());
     52   }
     53 
     54   virtual void WebContentsDestroyed() OVERRIDE {
     55     provider_->RemoveFromTaskManager(web_contents());
     56     provider_->DeleteObserver(this);  // Deletes |this|.
     57   }
     58 
     59  private:
     60   WebContentsResourceProvider* provider_;
     61 };
     62 
     63 ////////////////////////////////////////////////////////////////////////////////
     64 // WebContentsResourceProvider class
     65 ////////////////////////////////////////////////////////////////////////////////
     66 
     67 WebContentsResourceProvider::WebContentsResourceProvider(
     68     TaskManager* task_manager,
     69     scoped_ptr<WebContentsInformation> info)
     70     : updating_(false), task_manager_(task_manager), info_(info.Pass()) {}
     71 
     72 WebContentsResourceProvider::~WebContentsResourceProvider() {}
     73 
     74 RendererResource* WebContentsResourceProvider::GetResource(int origin_pid,
     75                                                            int child_id,
     76                                                            int route_id) {
     77   content::RenderFrameHost* rfh =
     78       content::RenderFrameHost::FromID(child_id, route_id);
     79   content::WebContents* web_contents =
     80       content::WebContents::FromRenderFrameHost(rfh);
     81 
     82   // If an origin PID was specified then the request originated in a plugin
     83   // working on the WebContents's behalf, so ignore it.
     84   if (origin_pid)
     85     return NULL;
     86 
     87   std::map<WebContents*, RendererResource*>::iterator res_iter =
     88       resources_.find(web_contents);
     89 
     90   if (res_iter == resources_.end()) {
     91     // Can happen if the tab was closed while a network request was being
     92     // performed.
     93     return NULL;
     94   }
     95   return res_iter->second;
     96 }
     97 
     98 void WebContentsResourceProvider::StartUpdating() {
     99   DCHECK(!updating_);
    100   updating_ = true;
    101 
    102   WebContentsInformation::NewWebContentsCallback new_web_contents_callback =
    103       base::Bind(&WebContentsResourceProvider::OnWebContentsCreated, this);
    104   info_->GetAll(new_web_contents_callback);
    105   info_->StartObservingCreation(new_web_contents_callback);
    106 }
    107 
    108 void WebContentsResourceProvider::StopUpdating() {
    109   DCHECK(updating_);
    110   updating_ = false;
    111 
    112   info_->StopObservingCreation();
    113 
    114   // Delete all observers; this dissassociates them from the WebContents too.
    115   STLDeleteElements(&web_contents_observers_);
    116   web_contents_observers_.clear();
    117 
    118   // Delete all resources. We don't need to remove them from the TaskManager,
    119   // because it's the TaskManager that's asking us to StopUpdating().
    120   STLDeleteValues(&resources_);
    121   resources_.clear();
    122 }
    123 
    124 void WebContentsResourceProvider::OnWebContentsCreated(
    125     WebContents* web_contents) {
    126   // Don't add dead tabs or tabs that haven't yet connected.
    127   if (!web_contents->GetRenderProcessHost()->GetHandle() ||
    128       !web_contents->WillNotifyDisconnection()) {
    129     return;
    130   }
    131 
    132   DCHECK(info_->CheckOwnership(web_contents));
    133   if (AddToTaskManager(web_contents)) {
    134     web_contents_observers_.insert(
    135         new TaskManagerWebContentsObserver(web_contents, this));
    136   }
    137 }
    138 
    139 bool WebContentsResourceProvider::AddToTaskManager(WebContents* web_contents) {
    140   if (!updating_)
    141     return false;
    142 
    143   if (resources_.count(web_contents)) {
    144     // The case may happen that we have added a WebContents as part of the
    145     // iteration performed during StartUpdating() call but the notification that
    146     // it has connected was not fired yet. So when the notification happens, we
    147     // are already observing this WebContents and just ignore it.
    148     return false;
    149   }
    150 
    151   // TODO(nick): If the RenderView is not live, then do we still want to install
    152   // the WebContentsObserver? Only some of the original ResourceProviders
    153   // had that check.
    154   scoped_ptr<RendererResource> resource = info_->MakeResource(web_contents);
    155   if (!resource)
    156     return false;
    157 
    158   task_manager_->AddResource(resource.get());
    159   resources_[web_contents] = resource.release();
    160   return true;
    161 }
    162 
    163 void WebContentsResourceProvider::RemoveFromTaskManager(
    164     WebContents* web_contents) {
    165   if (!updating_)
    166     return;
    167 
    168   std::map<WebContents*, RendererResource*>::iterator resource_iter =
    169       resources_.find(web_contents);
    170 
    171   if (resource_iter == resources_.end()) {
    172     return;
    173   }
    174 
    175   RendererResource* resource = resource_iter->second;
    176   task_manager_->RemoveResource(resource);
    177 
    178   // Remove the resource from the Task Manager.
    179   // And from the provider.
    180   resources_.erase(resource_iter);
    181 
    182   // Finally, delete the resource.
    183   delete resource;
    184 }
    185 
    186 void WebContentsResourceProvider::DeleteObserver(
    187     TaskManagerWebContentsObserver* observer) {
    188   if (!web_contents_observers_.erase(observer)) {
    189     NOTREACHED();
    190     return;
    191   }
    192   delete observer;  // Typically, this is our caller. Deletion is okay.
    193 }
    194 
    195 }  // namespace task_manager
    196