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/instant_service.h"
17 #include "chrome/browser/search/instant_service_factory.h"
18 #include "chrome/browser/search/search.h"
19 #include "chrome/browser/tab_contents/tab_util.h"
20 #include "chrome/browser/task_manager/renderer_resource.h"
21 #include "chrome/browser/task_manager/resource_provider.h"
22 #include "chrome/browser/task_manager/task_manager.h"
23 #include "chrome/browser/task_manager/task_manager_util.h"
24 #include "chrome/browser/ui/browser.h"
25 #include "chrome/browser/ui/browser_finder.h"
26 #include "chrome/browser/ui/browser_iterator.h"
27 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
28 #include "content/public/browser/notification_service.h"
29 #include "content/public/browser/render_process_host.h"
30 #include "content/public/browser/web_contents.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 string16 GetTitle() const OVERRIDE;
79 virtual 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_;
93 DISALLOW_COPY_AND_ASSIGN(TabContentsResource);
96 gfx::ImageSkia* TabContentsResource::prerender_icon_ = NULL;
98 TabContentsResource::TabContentsResource(
99 WebContents* web_contents)
100 : RendererResource(web_contents->GetRenderProcessHost()->GetHandle(),
101 web_contents->GetRenderViewHost()),
102 web_contents_(web_contents),
103 profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())),
104 is_instant_ntp_(chrome::IsPreloadedInstantExtendedNTP(web_contents)) {
105 if (!prerender_icon_) {
106 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
107 prerender_icon_ = rb.GetImageSkiaNamed(IDR_PRERENDER);
111 TabContentsResource::~TabContentsResource() {
114 bool TabContentsResource::HostsExtension() const {
115 return web_contents_->GetURL().SchemeIs(extensions::kExtensionScheme);
118 Resource::Type TabContentsResource::GetType() const {
119 return HostsExtension() ? EXTENSION : RENDERER;
122 string16 TabContentsResource::GetTitle() const {
123 // Fall back on the URL if there's no title.
124 GURL url = web_contents_->GetURL();
125 string16 tab_title = util::GetTitleFromWebContents(web_contents_);
127 // Only classify as an app if the URL is an app and the tab is hosting an
128 // extension process. (It's possible to be showing the URL from before it
129 // was installed as an app.)
130 ExtensionService* extension_service = profile_->GetExtensionService();
131 extensions::ProcessMap* process_map = extension_service->process_map();
132 bool is_app = extension_service->IsInstalledApp(url) &&
133 process_map->Contains(web_contents_->GetRenderProcessHost()->GetID());
135 int message_id = util::GetMessagePrefixID(
138 profile_->IsOffTheRecord(),
139 IsContentsPrerendering(web_contents_),
141 false); // is_background
142 return l10n_util::GetStringFUTF16(message_id, tab_title);
145 string16 TabContentsResource::GetProfileName() const {
146 return util::GetProfileNameFromInfoCache(profile_);
149 gfx::ImageSkia TabContentsResource::GetIcon() const {
150 if (IsContentsPrerendering(web_contents_))
151 return *prerender_icon_;
152 FaviconTabHelper::CreateForWebContents(web_contents_);
153 return FaviconTabHelper::FromWebContents(web_contents_)->
154 GetFavicon().AsImageSkia();
157 WebContents* TabContentsResource::GetWebContents() const {
158 return web_contents_;
161 const Extension* TabContentsResource::GetExtension() const {
162 if (HostsExtension()) {
163 ExtensionService* extension_service = profile_->GetExtensionService();
164 return extension_service->extensions()->GetByID(
165 web_contents_->GetURL().host());
171 ////////////////////////////////////////////////////////////////////////////////
172 // TabContentsResourceProvider class
173 ////////////////////////////////////////////////////////////////////////////////
175 TabContentsResourceProvider::
176 TabContentsResourceProvider(TaskManager* task_manager)
178 task_manager_(task_manager) {
181 TabContentsResourceProvider::~TabContentsResourceProvider() {
184 Resource* TabContentsResourceProvider::GetResource(
186 int render_process_host_id,
188 WebContents* web_contents =
189 tab_util::GetWebContentsByID(render_process_host_id, routing_id);
190 if (!web_contents) // Not one of our resource.
193 // If an origin PID was specified then the request originated in a plugin
194 // working on the WebContents's behalf, so ignore it.
198 std::map<WebContents*, TabContentsResource*>::iterator
199 res_iter = resources_.find(web_contents);
200 if (res_iter == resources_.end()) {
201 // Can happen if the tab was closed while a network request was being
205 return res_iter->second;
208 void TabContentsResourceProvider::StartUpdating() {
212 // The contents that are tracked by this resource provider are those that
213 // are tab contents (WebContents serving as a tab in a Browser), Instant
214 // pages, prerender pages, and background printed pages.
216 // Add all the existing WebContentses.
217 for (TabContentsIterator iterator; !iterator.done(); iterator.Next()) {
219 DevToolsWindow* docked =
220 DevToolsWindow::GetDockedInstanceForInspectedTab(*iterator);
222 Add(docked->web_contents());
225 // Add all the prerender pages.
226 std::vector<Profile*> profiles(
227 g_browser_process->profile_manager()->GetLoadedProfiles());
228 for (size_t i = 0; i < profiles.size(); ++i) {
229 prerender::PrerenderManager* prerender_manager =
230 prerender::PrerenderManagerFactory::GetForProfile(profiles[i]);
231 if (prerender_manager) {
232 const std::vector<content::WebContents*> contentses =
233 prerender_manager->GetAllPrerenderingContents();
234 for (size_t j = 0; j < contentses.size(); ++j)
239 // Add all the Instant Extended prerendered NTPs.
240 for (size_t i = 0; i < profiles.size(); ++i) {
241 const InstantService* instant_service =
242 InstantServiceFactory::GetForProfile(profiles[i]);
243 if (instant_service && instant_service->GetNTPContents())
244 Add(instant_service->GetNTPContents());
247 #if defined(ENABLE_FULL_PRINTING)
248 // Add all the pages being background printed.
249 printing::BackgroundPrintingManager* printing_manager =
250 g_browser_process->background_printing_manager();
251 for (printing::BackgroundPrintingManager::WebContentsSet::iterator i =
252 printing_manager->begin();
253 i != printing_manager->end(); ++i) {
258 // Then we register for notifications to get new web contents.
259 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_CONNECTED,
260 content::NotificationService::AllBrowserContextsAndSources());
261 registrar_.Add(this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
262 content::NotificationService::AllBrowserContextsAndSources());
263 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
264 content::NotificationService::AllBrowserContextsAndSources());
267 void TabContentsResourceProvider::StopUpdating() {
271 // Then we unregister for notifications to get new web contents.
272 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_CONNECTED,
273 content::NotificationService::AllBrowserContextsAndSources());
274 registrar_.Remove(this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
275 content::NotificationService::AllBrowserContextsAndSources());
276 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
277 content::NotificationService::AllBrowserContextsAndSources());
279 // Delete all the resources.
280 STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
285 void TabContentsResourceProvider::AddToTaskManager(WebContents* web_contents) {
286 TabContentsResource* resource = new TabContentsResource(web_contents);
287 resources_[web_contents] = resource;
288 task_manager_->AddResource(resource);
291 void TabContentsResourceProvider::Add(WebContents* web_contents) {
295 // The contents that are tracked by this resource provider are those that
296 // are tab contents (WebContents serving as a tab in a Browser), Instant
297 // pages, prerender pages, and background printed pages.
298 if (!chrome::FindBrowserWithWebContents(web_contents) &&
299 !IsContentsPrerendering(web_contents) &&
300 !chrome::IsPreloadedInstantExtendedNTP(web_contents) &&
301 !IsContentsBackgroundPrinted(web_contents) &&
302 !DevToolsWindow::IsDevToolsWindow(web_contents->GetRenderViewHost())) {
306 // Don't add dead tabs or tabs that haven't yet connected.
307 if (!web_contents->GetRenderProcessHost()->GetHandle() ||
308 !web_contents->WillNotifyDisconnection()) {
312 if (resources_.count(web_contents)) {
313 // The case may happen that we have added a WebContents as part of the
314 // iteration performed during StartUpdating() call but the notification that
315 // it has connected was not fired yet. So when the notification happens, we
316 // already know about this tab and just ignore it.
319 AddToTaskManager(web_contents);
322 void TabContentsResourceProvider::Remove(WebContents* web_contents) {
325 std::map<WebContents*, TabContentsResource*>::iterator
326 iter = resources_.find(web_contents);
327 if (iter == resources_.end()) {
328 // Since WebContents are destroyed asynchronously (see TabContentsCollector
329 // in navigation_controller.cc), we can be notified of a tab being removed
330 // that we don't know. This can happen if the user closes a tab and quickly
331 // opens the task manager, before the tab is actually destroyed.
335 // Remove the resource from the Task Manager.
336 TabContentsResource* resource = iter->second;
337 task_manager_->RemoveResource(resource);
338 // And from the provider.
339 resources_.erase(iter);
340 // Finally, delete the resource.
344 void TabContentsResourceProvider::Observe(
346 const content::NotificationSource& source,
347 const content::NotificationDetails& details) {
348 WebContents* web_contents = content::Source<WebContents>(source).ptr();
351 case content::NOTIFICATION_WEB_CONTENTS_CONNECTED:
354 case content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED:
355 Remove(web_contents);
358 case content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED:
359 Remove(web_contents);
362 NOTREACHED() << "Unexpected notification.";
367 } // namespace task_manager