Fix infinite recursion on hiding panel when created during fullscreen mode.
[chromium-blink-merge.git] / chrome / browser / task_manager / web_contents_resource_provider.cc
blob4b19090e2a775cb30636c2b1e538ec3393013c8a
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.
5 #include "chrome/browser/task_manager/web_contents_resource_provider.h"
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"
25 using content::WebContents;
26 using content::RenderViewHost;
28 namespace task_manager {
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) {}
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());
45 virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE {
46 provider_->RemoveFromTaskManager(web_contents);
47 provider_->DeleteObserver(this); // Deletes |this|.
50 private:
51 WebContentsResourceProvider* provider_;
54 ////////////////////////////////////////////////////////////////////////////////
55 // WebContentsResourceProvider class
56 ////////////////////////////////////////////////////////////////////////////////
58 WebContentsResourceProvider::WebContentsResourceProvider(
59 TaskManager* task_manager,
60 scoped_ptr<WebContentsInformation> info)
61 : updating_(false), task_manager_(task_manager), info_(info.Pass()) {}
63 WebContentsResourceProvider::~WebContentsResourceProvider() {}
65 RendererResource* WebContentsResourceProvider::GetResource(int origin_pid,
66 int child_id,
67 int route_id) {
68 content::RenderFrameHost* rfh =
69 content::RenderFrameHost::FromID(child_id, route_id);
70 content::WebContents* web_contents =
71 content::WebContents::FromRenderFrameHost(rfh);
73 // If an origin PID was specified then the request originated in a plugin
74 // working on the WebContents's behalf, so ignore it.
75 if (origin_pid)
76 return NULL;
78 std::map<WebContents*, RendererResource*>::iterator res_iter =
79 resources_.find(web_contents);
81 if (res_iter == resources_.end()) {
82 // Can happen if the tab was closed while a network request was being
83 // performed.
84 return NULL;
86 return res_iter->second;
89 void WebContentsResourceProvider::StartUpdating() {
90 DCHECK(!updating_);
91 updating_ = true;
93 WebContentsInformation::NewWebContentsCallback new_web_contents_callback =
94 base::Bind(&WebContentsResourceProvider::OnWebContentsCreated, this);
95 info_->GetAll(new_web_contents_callback);
96 info_->StartObservingCreation(new_web_contents_callback);
99 void WebContentsResourceProvider::StopUpdating() {
100 DCHECK(updating_);
101 updating_ = false;
103 info_->StopObservingCreation();
105 // Delete all observers; this dissassociates them from the WebContents too.
106 STLDeleteElements(&web_contents_observers_);
107 web_contents_observers_.clear();
109 // Delete all resources. We don't need to remove them from the TaskManager,
110 // because it's the TaskManager that's asking us to StopUpdating().
111 STLDeleteValues(&resources_);
112 resources_.clear();
115 void WebContentsResourceProvider::OnWebContentsCreated(
116 WebContents* web_contents) {
117 // Don't add dead tabs or tabs that haven't yet connected.
118 if (!web_contents->GetRenderProcessHost()->GetHandle() ||
119 !web_contents->WillNotifyDisconnection()) {
120 return;
123 DCHECK(info_->CheckOwnership(web_contents));
124 if (AddToTaskManager(web_contents)) {
125 web_contents_observers_.insert(
126 new TaskManagerWebContentsObserver(web_contents, this));
130 bool WebContentsResourceProvider::AddToTaskManager(WebContents* web_contents) {
131 if (!updating_)
132 return false;
134 if (resources_.count(web_contents)) {
135 // The case may happen that we have added a WebContents as part of the
136 // iteration performed during StartUpdating() call but the notification that
137 // it has connected was not fired yet. So when the notification happens, we
138 // are already observing this WebContents and just ignore it.
139 return false;
142 // TODO(nick): If the RenderView is not live, then do we still want to install
143 // the WebContentsObserver? Only some of the original ResourceProviders
144 // had that check.
145 scoped_ptr<RendererResource> resource = info_->MakeResource(web_contents);
146 if (!resource)
147 return false;
149 task_manager_->AddResource(resource.get());
150 resources_[web_contents] = resource.release();
151 return true;
154 void WebContentsResourceProvider::RemoveFromTaskManager(
155 WebContents* web_contents) {
156 if (!updating_)
157 return;
159 std::map<WebContents*, RendererResource*>::iterator resource_iter =
160 resources_.find(web_contents);
162 if (resource_iter == resources_.end()) {
163 return;
166 RendererResource* resource = resource_iter->second;
167 task_manager_->RemoveResource(resource);
169 // Remove the resource from the Task Manager.
170 // And from the provider.
171 resources_.erase(resource_iter);
173 // Finally, delete the resource.
174 delete resource;
177 void WebContentsResourceProvider::DeleteObserver(
178 TaskManagerWebContentsObserver* observer) {
179 if (!web_contents_observers_.erase(observer)) {
180 NOTREACHED();
181 return;
183 delete observer; // Typically, this is our caller. Deletion is okay.
186 } // namespace task_manager