Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / task_manager / web_contents_resource_provider.cc
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 "base/strings/utf_string_conversions.h"
10 #include "chrome/browser/browser_process.h"
11 #include "chrome/browser/prerender/prerender_manager.h"
12 #include "chrome/browser/prerender/prerender_manager_factory.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/profiles/profile_manager.h"
15 #include "chrome/browser/task_manager/renderer_resource.h"
16 #include "chrome/browser/task_manager/task_manager.h"
17 #include "chrome/browser/task_manager/task_manager_util.h"
18 #include "chrome/browser/task_manager/web_contents_information.h"
19 #include "chrome/grit/generated_resources.h"
20 #include "content/public/browser/render_frame_host.h"
21 #include "content/public/browser/render_process_host.h"
22 #include "content/public/browser/render_view_host.h"
23 #include "content/public/browser/render_widget_host_iterator.h"
24 #include "content/public/browser/site_instance.h"
25 #include "content/public/browser/web_contents.h"
26 #include "content/public/browser/web_contents_observer.h"
27 #include "ui/base/l10n/l10n_util.h"
28 #include "ui/gfx/image/image_skia.h"
29
30 using content::RenderViewHost;
31 using content::RenderFrameHost;
32 using content::SiteInstance;
33 using content::WebContents;
34
35 namespace task_manager {
36
37 // A resource for a process hosting out-of-process iframes.
38 class SubframeResource : public RendererResource {
39  public:
40   explicit SubframeResource(WebContents* web_contents,
41                             SiteInstance* site_instance,
42                             RenderFrameHost* example_rfh);
43   virtual ~SubframeResource() {}
44
45   // Resource methods:
46   virtual Type GetType() const OVERRIDE;
47   virtual base::string16 GetTitle() const OVERRIDE;
48   virtual gfx::ImageSkia GetIcon() const OVERRIDE;
49   virtual WebContents* GetWebContents() const OVERRIDE;
50
51  private:
52   WebContents* web_contents_;
53   base::string16 title_;
54   DISALLOW_COPY_AND_ASSIGN(SubframeResource);
55 };
56
57 SubframeResource::SubframeResource(WebContents* web_contents,
58                                    SiteInstance* subframe_site_instance,
59                                    RenderFrameHost* example_rfh)
60     : RendererResource(subframe_site_instance->GetProcess()->GetHandle(),
61                        example_rfh->GetRenderViewHost()),
62       web_contents_(web_contents) {
63   int message_id = subframe_site_instance->GetBrowserContext()->IsOffTheRecord()
64                        ? IDS_TASK_MANAGER_SUBFRAME_INCOGNITO_PREFIX
65                        : IDS_TASK_MANAGER_SUBFRAME_PREFIX;
66   title_ = l10n_util::GetStringFUTF16(
67       message_id,
68       base::UTF8ToUTF16(subframe_site_instance->GetSiteURL().spec()));
69 }
70
71 Resource::Type SubframeResource::GetType() const {
72   return RENDERER;
73 }
74
75 base::string16 SubframeResource::GetTitle() const {
76   return title_;
77 }
78
79 gfx::ImageSkia SubframeResource::GetIcon() const {
80   return gfx::ImageSkia();
81 }
82
83 WebContents* SubframeResource::GetWebContents() const {
84   return web_contents_;
85 }
86
87 // Tracks changes to one WebContents, and manages task manager resources for
88 // that WebContents, on behalf of a WebContentsResourceProvider.
89 class TaskManagerWebContentsEntry : public content::WebContentsObserver {
90  public:
91   typedef std::multimap<SiteInstance*, RendererResource*> ResourceMap;
92   typedef std::pair<ResourceMap::iterator, ResourceMap::iterator> ResourceRange;
93
94   TaskManagerWebContentsEntry(WebContents* web_contents,
95                               WebContentsResourceProvider* provider)
96       : content::WebContentsObserver(web_contents),
97         provider_(provider),
98         main_frame_site_instance_(NULL) {}
99
100   virtual ~TaskManagerWebContentsEntry() {
101     for (ResourceMap::iterator j = resources_by_site_instance_.begin();
102          j != resources_by_site_instance_.end();) {
103       RendererResource* resource = j->second;
104
105       // Advance to next non-duplicate entry.
106       do {
107         ++j;
108       } while (j != resources_by_site_instance_.end() && resource == j->second);
109
110       delete resource;
111     }
112   }
113
114   // content::WebContentsObserver implementation.
115   virtual void RenderFrameDeleted(RenderFrameHost* render_frame_host) OVERRIDE {
116     ClearResourceForFrame(render_frame_host);
117   }
118
119   virtual void RenderFrameHostChanged(RenderFrameHost* old_host,
120                                       RenderFrameHost* new_host) OVERRIDE {
121     if (old_host)
122       ClearResourceForFrame(old_host);
123     CreateResourceForFrame(new_host);
124   }
125
126   virtual void RenderViewReady() OVERRIDE {
127     ClearAllResources();
128     CreateAllResources();
129   }
130
131   virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE {
132     ClearAllResources();
133   }
134
135   virtual void WebContentsDestroyed() OVERRIDE {
136     ClearAllResources();
137     provider_->DeleteEntry(web_contents(), this);  // Deletes |this|.
138   }
139
140   // Called by WebContentsResourceProvider.
141   RendererResource* GetResourceForSiteInstance(SiteInstance* site_instance) {
142     ResourceMap::iterator i = resources_by_site_instance_.find(site_instance);
143     if (i == resources_by_site_instance_.end())
144       return NULL;
145     return i->second;
146   }
147
148   void CreateAllResources() {
149     // We'll show one row per SiteInstance in the task manager.
150     DCHECK(web_contents()->GetMainFrame() != NULL);
151     web_contents()->ForEachFrame(
152         base::Bind(&TaskManagerWebContentsEntry::CreateResourceForFrame,
153                    base::Unretained(this)));
154   }
155
156   void ClearAllResources() {
157     for (ResourceMap::iterator j = resources_by_site_instance_.begin();
158          j != resources_by_site_instance_.end();) {
159       RendererResource* resource = j->second;
160
161       // Advance to next non-duplicate entry.
162       do {
163         ++j;
164       } while (j != resources_by_site_instance_.end() && resource == j->second);
165
166       // Remove the resource from the Task Manager.
167       task_manager()->RemoveResource(resource);
168       delete resource;
169     }
170     resources_by_site_instance_.clear();
171     tracked_frame_hosts_.clear();
172   }
173
174   void ClearResourceForFrame(RenderFrameHost* render_frame_host) {
175     SiteInstance* site_instance = render_frame_host->GetSiteInstance();
176     std::set<RenderFrameHost*>::iterator frame_set_iterator =
177         tracked_frame_hosts_.find(render_frame_host);
178     if (frame_set_iterator == tracked_frame_hosts_.end()) {
179       // We weren't tracking this RenderFrameHost.
180       return;
181     }
182     tracked_frame_hosts_.erase(frame_set_iterator);
183     ResourceRange resource_range =
184         resources_by_site_instance_.equal_range(site_instance);
185     if (resource_range.first == resource_range.second) {
186       NOTREACHED();
187       return;
188     }
189     RendererResource* resource = resource_range.first->second;
190     resources_by_site_instance_.erase(resource_range.first++);
191     if (resource_range.first == resource_range.second) {
192       // The removed entry was the sole remaining reference to that resource, so
193       // actually destroy it.
194       task_manager()->RemoveResource(resource);
195       delete resource;
196       if (site_instance == main_frame_site_instance_) {
197         main_frame_site_instance_ = NULL;
198       }
199     }
200   }
201
202   void CreateResourceForFrame(RenderFrameHost* render_frame_host) {
203     SiteInstance* site_instance = render_frame_host->GetSiteInstance();
204
205     DCHECK_EQ(0u, tracked_frame_hosts_.count(render_frame_host));
206     tracked_frame_hosts_.insert(render_frame_host);
207
208     ResourceRange existing_resource_range =
209         resources_by_site_instance_.equal_range(site_instance);
210     bool existing_resource =
211         (existing_resource_range.first != existing_resource_range.second);
212     bool is_main_frame = (render_frame_host == web_contents()->GetMainFrame());
213     bool site_instance_is_main = (site_instance == main_frame_site_instance_);
214     scoped_ptr<RendererResource> new_resource;
215     if (!existing_resource || (is_main_frame && !site_instance_is_main)) {
216       if (is_main_frame) {
217         new_resource = info()->MakeResource(web_contents());
218         main_frame_site_instance_ = site_instance;
219       } else {
220         new_resource.reset(new SubframeResource(
221             web_contents(), site_instance, render_frame_host));
222       }
223     }
224
225     if (existing_resource) {
226       RendererResource* old_resource = existing_resource_range.first->second;
227       if (!new_resource) {
228         resources_by_site_instance_.insert(
229             std::make_pair(site_instance, old_resource));
230       } else {
231         for (ResourceMap::iterator it = existing_resource_range.first;
232              it != existing_resource_range.second;
233              ++it) {
234           it->second = new_resource.get();
235         }
236         task_manager()->RemoveResource(old_resource);
237         delete old_resource;
238       }
239     }
240
241     if (new_resource) {
242       task_manager()->AddResource(new_resource.get());
243       resources_by_site_instance_.insert(
244           std::make_pair(site_instance, new_resource.release()));
245     }
246   }
247
248  private:
249   TaskManager* task_manager() { return provider_->task_manager(); }
250
251   WebContentsInformation* info() { return provider_->info(); }
252
253   WebContentsResourceProvider* const provider_;
254   std::set<RenderFrameHost*> tracked_frame_hosts_;
255   ResourceMap resources_by_site_instance_;
256   SiteInstance* main_frame_site_instance_;
257 };
258
259 ////////////////////////////////////////////////////////////////////////////////
260 // WebContentsResourceProvider class
261 ////////////////////////////////////////////////////////////////////////////////
262
263 WebContentsResourceProvider::WebContentsResourceProvider(
264     TaskManager* task_manager,
265     scoped_ptr<WebContentsInformation> info)
266     : task_manager_(task_manager), info_(info.Pass()) {
267 }
268
269 WebContentsResourceProvider::~WebContentsResourceProvider() {}
270
271 RendererResource* WebContentsResourceProvider::GetResource(int origin_pid,
272                                                            int child_id,
273                                                            int route_id) {
274   RenderFrameHost* rfh = RenderFrameHost::FromID(child_id, route_id);
275   WebContents* web_contents = WebContents::FromRenderFrameHost(rfh);
276
277   // If an origin PID was specified then the request originated in a plugin
278   // working on the WebContents's behalf, so ignore it.
279   if (origin_pid)
280     return NULL;
281
282   EntryMap::const_iterator web_contents_it = entries_.find(web_contents);
283
284   if (web_contents_it == entries_.end()) {
285     // Can happen if the tab was closed while a network request was being
286     // performed.
287     return NULL;
288   }
289
290   return web_contents_it->second->GetResourceForSiteInstance(
291       rfh->GetSiteInstance());
292 }
293
294 void WebContentsResourceProvider::StartUpdating() {
295   WebContentsInformation::NewWebContentsCallback new_web_contents_callback =
296       base::Bind(&WebContentsResourceProvider::OnWebContentsCreated, this);
297   info_->GetAll(new_web_contents_callback);
298   info_->StartObservingCreation(new_web_contents_callback);
299 }
300
301 void WebContentsResourceProvider::StopUpdating() {
302   info_->StopObservingCreation();
303
304   // Delete all entries; this dissassociates them from the WebContents too.
305   STLDeleteValues(&entries_);
306 }
307
308 void WebContentsResourceProvider::OnWebContentsCreated(
309     WebContents* web_contents) {
310   // Don't add dead tabs or tabs that haven't yet connected.
311   if (!web_contents->GetRenderProcessHost()->GetHandle() ||
312       !web_contents->WillNotifyDisconnection()) {
313     return;
314   }
315
316   DCHECK(info_->CheckOwnership(web_contents));
317   if (entries_.count(web_contents)) {
318     // The case may happen that we have added a WebContents as part of the
319     // iteration performed during StartUpdating() call but the notification that
320     // it has connected was not fired yet. So when the notification happens, we
321     // are already observing this WebContents and just ignore it.
322     return;
323   }
324   scoped_ptr<TaskManagerWebContentsEntry> entry(
325       new TaskManagerWebContentsEntry(web_contents, this));
326   entry->CreateAllResources();
327   entries_[web_contents] = entry.release();
328 }
329
330 void WebContentsResourceProvider::DeleteEntry(
331     WebContents* web_contents,
332     TaskManagerWebContentsEntry* entry) {
333   if (!entries_.erase(web_contents)) {
334     NOTREACHED();
335     return;
336   }
337   delete entry;  // Typically, this is our caller. Deletion is okay.
338 }
339
340 }  // namespace task_manager