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