1 // Copyright 2012 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/tab_contents_resource_provider.h"
7 #include "chrome/browser/browser_process.h"
8 #include "chrome/browser/chrome_notification_types.h"
9 #include "chrome/browser/devtools/devtools_window.h"
10 #include "chrome/browser/extensions/extension_service.h"
11 #include "chrome/browser/favicon/favicon_tab_helper.h"
12 #include "chrome/browser/prerender/prerender_manager.h"
13 #include "chrome/browser/prerender/prerender_manager_factory.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/profiles/profile_manager.h"
16 #include "chrome/browser/search/search.h"
17 #include "chrome/browser/tab_contents/tab_util.h"
18 #include "chrome/browser/task_manager/renderer_resource.h"
19 #include "chrome/browser/task_manager/resource_provider.h"
20 #include "chrome/browser/task_manager/task_manager.h"
21 #include "chrome/browser/task_manager/task_manager_util.h"
22 #include "chrome/browser/ui/browser.h"
23 #include "chrome/browser/ui/browser_finder.h"
24 #include "chrome/browser/ui/browser_iterator.h"
25 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
26 #include "content/public/browser/notification_service.h"
27 #include "content/public/browser/render_frame_host.h"
28 #include "content/public/browser/render_process_host.h"
29 #include "content/public/browser/web_contents.h"
30 #include "extensions/browser/process_map.h"
31 #include "extensions/common/constants.h"
32 #include "grit/theme_resources.h"
33 #include "ui/base/l10n/l10n_util.h"
34 #include "ui/base/resource/resource_bundle.h"
35 #include "ui/gfx/image/image_skia.h"
37 #if defined(ENABLE_FULL_PRINTING)
38 #include "chrome/browser/printing/background_printing_manager.h"
41 using content::WebContents
;
42 using extensions::Extension
;
46 bool IsContentsPrerendering(WebContents
* web_contents
) {
48 Profile::FromBrowserContext(web_contents
->GetBrowserContext());
49 prerender::PrerenderManager
* prerender_manager
=
50 prerender::PrerenderManagerFactory::GetForProfile(profile
);
51 return prerender_manager
&&
52 prerender_manager
->IsWebContentsPrerendering(web_contents
, NULL
);
55 bool IsContentsBackgroundPrinted(WebContents
* web_contents
) {
56 #if defined(ENABLE_FULL_PRINTING)
57 printing::BackgroundPrintingManager
* printing_manager
=
58 g_browser_process
->background_printing_manager();
59 return printing_manager
->HasPrintPreviewDialog(web_contents
);
67 namespace task_manager
{
69 // Tracks a single tab contents, prerendered page, Instant page, or background
71 class TabContentsResource
: public RendererResource
{
73 explicit TabContentsResource(content::WebContents
* web_contents
);
74 virtual ~TabContentsResource();
77 virtual Type
GetType() const OVERRIDE
;
78 virtual base::string16
GetTitle() const OVERRIDE
;
79 virtual base::string16
GetProfileName() const OVERRIDE
;
80 virtual gfx::ImageSkia
GetIcon() const OVERRIDE
;
81 virtual content::WebContents
* GetWebContents() const OVERRIDE
;
82 virtual const extensions::Extension
* GetExtension() const OVERRIDE
;
85 // Returns true if contains content rendered by an extension.
86 bool HostsExtension() const;
88 static gfx::ImageSkia
* prerender_icon_
;
89 content::WebContents
* web_contents_
;
92 DISALLOW_COPY_AND_ASSIGN(TabContentsResource
);
95 gfx::ImageSkia
* TabContentsResource::prerender_icon_
= NULL
;
97 TabContentsResource::TabContentsResource(
98 WebContents
* web_contents
)
99 : RendererResource(web_contents
->GetRenderProcessHost()->GetHandle(),
100 web_contents
->GetRenderViewHost()),
101 web_contents_(web_contents
),
102 profile_(Profile::FromBrowserContext(web_contents
->GetBrowserContext())) {
103 if (!prerender_icon_
) {
104 ResourceBundle
& rb
= ResourceBundle::GetSharedInstance();
105 prerender_icon_
= rb
.GetImageSkiaNamed(IDR_PRERENDER
);
109 TabContentsResource::~TabContentsResource() {
112 bool TabContentsResource::HostsExtension() const {
113 return web_contents_
->GetURL().SchemeIs(extensions::kExtensionScheme
);
116 Resource::Type
TabContentsResource::GetType() const {
117 return HostsExtension() ? EXTENSION
: RENDERER
;
120 base::string16
TabContentsResource::GetTitle() const {
121 // Fall back on the URL if there's no title.
122 GURL url
= web_contents_
->GetURL();
123 base::string16 tab_title
= util::GetTitleFromWebContents(web_contents_
);
125 // Only classify as an app if the URL is an app and the tab is hosting an
126 // extension process. (It's possible to be showing the URL from before it
127 // was installed as an app.)
128 ExtensionService
* extension_service
= profile_
->GetExtensionService();
129 extensions::ProcessMap
* process_map
= extensions::ProcessMap::Get(profile_
);
130 bool is_app
= extension_service
->IsInstalledApp(url
) &&
131 process_map
->Contains(web_contents_
->GetRenderProcessHost()->GetID());
133 int message_id
= util::GetMessagePrefixID(
136 profile_
->IsOffTheRecord(),
137 IsContentsPrerendering(web_contents_
),
138 false); // is_background
139 return l10n_util::GetStringFUTF16(message_id
, tab_title
);
142 base::string16
TabContentsResource::GetProfileName() const {
143 return util::GetProfileNameFromInfoCache(profile_
);
146 gfx::ImageSkia
TabContentsResource::GetIcon() const {
147 if (IsContentsPrerendering(web_contents_
))
148 return *prerender_icon_
;
149 FaviconTabHelper::CreateForWebContents(web_contents_
);
150 return FaviconTabHelper::FromWebContents(web_contents_
)->
151 GetFavicon().AsImageSkia();
154 WebContents
* TabContentsResource::GetWebContents() const {
155 return web_contents_
;
158 const Extension
* TabContentsResource::GetExtension() const {
159 if (HostsExtension()) {
160 ExtensionService
* extension_service
= profile_
->GetExtensionService();
161 return extension_service
->extensions()->GetByID(
162 web_contents_
->GetURL().host());
168 ////////////////////////////////////////////////////////////////////////////////
169 // TabContentsResourceProvider class
170 ////////////////////////////////////////////////////////////////////////////////
172 TabContentsResourceProvider::
173 TabContentsResourceProvider(TaskManager
* task_manager
)
175 task_manager_(task_manager
) {
178 TabContentsResourceProvider::~TabContentsResourceProvider() {
181 Resource
* TabContentsResourceProvider::GetResource(
185 content::RenderFrameHost
* rfh
=
186 content::RenderFrameHost::FromID(child_id
, route_id
);
187 content::WebContents
* web_contents
=
188 content::WebContents::FromRenderFrameHost(rfh
);
190 // If an origin PID was specified then the request originated in a plugin
191 // working on the WebContents's behalf, so ignore it.
195 std::map
<WebContents
*, TabContentsResource
*>::iterator
196 res_iter
= resources_
.find(web_contents
);
197 if (res_iter
== resources_
.end()) {
198 // Can happen if the tab was closed while a network request was being
202 return res_iter
->second
;
205 void TabContentsResourceProvider::StartUpdating() {
209 // The contents that are tracked by this resource provider are those that
210 // are tab contents (WebContents serving as a tab in a Browser), Instant
211 // pages, prerender pages, and background printed pages.
213 // Add all the existing WebContentses.
214 for (TabContentsIterator iterator
; !iterator
.done(); iterator
.Next()) {
216 DevToolsWindow
* docked
=
217 DevToolsWindow::GetDockedInstanceForInspectedTab(*iterator
);
219 Add(docked
->web_contents());
222 // Add all the prerender pages.
223 std::vector
<Profile
*> profiles(
224 g_browser_process
->profile_manager()->GetLoadedProfiles());
225 for (size_t i
= 0; i
< profiles
.size(); ++i
) {
226 prerender::PrerenderManager
* prerender_manager
=
227 prerender::PrerenderManagerFactory::GetForProfile(profiles
[i
]);
228 if (prerender_manager
) {
229 const std::vector
<content::WebContents
*> contentses
=
230 prerender_manager
->GetAllPrerenderingContents();
231 for (size_t j
= 0; j
< contentses
.size(); ++j
)
236 #if defined(ENABLE_FULL_PRINTING)
237 // Add all the pages being background printed.
238 printing::BackgroundPrintingManager
* printing_manager
=
239 g_browser_process
->background_printing_manager();
240 std::set
<content::WebContents
*> printing_contents
=
241 printing_manager
->CurrentContentSet();
242 for (std::set
<content::WebContents
*>::iterator i
=
243 printing_contents
.begin();
244 i
!= printing_contents
.end(); ++i
) {
249 // Then we register for notifications to get new web contents.
250 registrar_
.Add(this, content::NOTIFICATION_WEB_CONTENTS_CONNECTED
,
251 content::NotificationService::AllBrowserContextsAndSources());
252 registrar_
.Add(this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED
,
253 content::NotificationService::AllBrowserContextsAndSources());
254 registrar_
.Add(this, content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED
,
255 content::NotificationService::AllBrowserContextsAndSources());
258 void TabContentsResourceProvider::StopUpdating() {
262 // Then we unregister for notifications to get new web contents.
263 registrar_
.Remove(this, content::NOTIFICATION_WEB_CONTENTS_CONNECTED
,
264 content::NotificationService::AllBrowserContextsAndSources());
265 registrar_
.Remove(this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED
,
266 content::NotificationService::AllBrowserContextsAndSources());
267 registrar_
.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED
,
268 content::NotificationService::AllBrowserContextsAndSources());
270 // Delete all the resources.
271 STLDeleteContainerPairSecondPointers(resources_
.begin(), resources_
.end());
276 void TabContentsResourceProvider::AddToTaskManager(WebContents
* web_contents
) {
277 TabContentsResource
* resource
= new TabContentsResource(web_contents
);
278 resources_
[web_contents
] = resource
;
279 task_manager_
->AddResource(resource
);
282 void TabContentsResourceProvider::Add(WebContents
* web_contents
) {
286 // The contents that are tracked by this resource provider are those that
287 // are tab contents (WebContents serving as a tab in a Browser), Instant
288 // pages, prerender pages, and background printed pages.
289 if (!chrome::FindBrowserWithWebContents(web_contents
) &&
290 !IsContentsPrerendering(web_contents
) &&
291 !IsContentsBackgroundPrinted(web_contents
) &&
292 !DevToolsWindow::IsDevToolsWindow(web_contents
->GetRenderViewHost())) {
296 // Don't add dead tabs or tabs that haven't yet connected.
297 if (!web_contents
->GetRenderProcessHost()->GetHandle() ||
298 !web_contents
->WillNotifyDisconnection()) {
302 if (resources_
.count(web_contents
)) {
303 // The case may happen that we have added a WebContents as part of the
304 // iteration performed during StartUpdating() call but the notification that
305 // it has connected was not fired yet. So when the notification happens, we
306 // already know about this tab and just ignore it.
309 AddToTaskManager(web_contents
);
312 void TabContentsResourceProvider::Remove(WebContents
* web_contents
) {
315 std::map
<WebContents
*, TabContentsResource
*>::iterator
316 iter
= resources_
.find(web_contents
);
317 if (iter
== resources_
.end()) {
318 // Since WebContents are destroyed asynchronously (see TabContentsCollector
319 // in navigation_controller.cc), we can be notified of a tab being removed
320 // that we don't know. This can happen if the user closes a tab and quickly
321 // opens the task manager, before the tab is actually destroyed.
325 // Remove the resource from the Task Manager.
326 TabContentsResource
* resource
= iter
->second
;
327 task_manager_
->RemoveResource(resource
);
328 // And from the provider.
329 resources_
.erase(iter
);
330 // Finally, delete the resource.
334 void TabContentsResourceProvider::Observe(
336 const content::NotificationSource
& source
,
337 const content::NotificationDetails
& details
) {
338 WebContents
* web_contents
= content::Source
<WebContents
>(source
).ptr();
341 case content::NOTIFICATION_WEB_CONTENTS_CONNECTED
:
344 case content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED
:
345 Remove(web_contents
);
348 case content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED
:
349 Remove(web_contents
);
352 NOTREACHED() << "Unexpected notification.";
357 } // namespace task_manager