OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "chrome/browser/task_manager/task_manager_tab_contents_resource_provide
r.h" | |
6 | |
7 #include "chrome/browser/browser_process.h" | |
8 #include "chrome/browser/extensions/extension_service.h" | |
9 #include "chrome/browser/favicon/favicon_tab_helper.h" | |
10 #include "chrome/browser/prerender/prerender_manager.h" | |
11 #include "chrome/browser/prerender/prerender_manager_factory.h" | |
12 #include "chrome/browser/printing/background_printing_manager.h" | |
13 #include "chrome/browser/profiles/profile.h" | |
14 #include "chrome/browser/profiles/profile_manager.h" | |
15 #include "chrome/browser/tab_contents/tab_util.h" | |
16 #include "chrome/browser/task_manager/task_manager_render_resource.h" | |
17 #include "chrome/browser/task_manager/task_manager_resource_util.h" | |
18 #include "chrome/browser/ui/browser.h" | |
19 #include "chrome/browser/ui/browser_finder.h" | |
20 #include "chrome/browser/ui/browser_instant_controller.h" | |
21 #include "chrome/browser/ui/browser_iterator.h" | |
22 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h" | |
23 #include "chrome/common/chrome_notification_types.h" | |
24 #include "content/public/browser/notification_service.h" | |
25 #include "content/public/browser/render_process_host.h" | |
26 #include "content/public/browser/web_contents.h" | |
27 #include "extensions/common/constants.h" | |
28 #include "grit/theme_resources.h" | |
29 #include "ui/base/l10n/l10n_util.h" | |
30 #include "ui/base/resource/resource_bundle.h" | |
31 #include "ui/gfx/image/image_skia.h" | |
32 | |
33 using content::WebContents; | |
34 using extensions::Extension; | |
35 | |
36 | |
37 namespace { | |
38 | |
39 bool IsContentsPrerendering(WebContents* web_contents) { | |
40 Profile* profile = | |
41 Profile::FromBrowserContext(web_contents->GetBrowserContext()); | |
42 prerender::PrerenderManager* prerender_manager = | |
43 prerender::PrerenderManagerFactory::GetForProfile(profile); | |
44 return prerender_manager && | |
45 prerender_manager->IsWebContentsPrerendering(web_contents, NULL); | |
46 } | |
47 | |
48 bool IsContentsInstant(WebContents* web_contents) { | |
49 for (chrome::BrowserIterator it; !it.done(); it.Next()) { | |
50 if (it->instant_controller() && | |
51 it->instant_controller()->instant()-> | |
52 GetOverlayContents() == web_contents) { | |
53 return true; | |
54 } | |
55 } | |
56 | |
57 return false; | |
58 } | |
59 | |
60 bool IsContentsBackgroundPrinted(WebContents* web_contents) { | |
61 printing::BackgroundPrintingManager* printing_manager = | |
62 g_browser_process->background_printing_manager(); | |
63 return printing_manager->HasPrintPreviewDialog(web_contents); | |
64 } | |
65 | |
66 } // namespace | |
67 | |
68 // Tracks a single tab contents, prerendered page, Instant page, or background | |
69 // printing page. | |
70 class TaskManagerTabContentsResource : public TaskManagerRendererResource { | |
71 public: | |
72 explicit TaskManagerTabContentsResource(content::WebContents* web_contents); | |
73 virtual ~TaskManagerTabContentsResource(); | |
74 | |
75 // Called when the underlying web_contents has been committed and is no | |
76 // longer an Instant overlay. | |
77 void InstantCommitted(); | |
78 | |
79 // TaskManager::Resource methods: | |
80 virtual Type GetType() const OVERRIDE; | |
81 virtual string16 GetTitle() const OVERRIDE; | |
82 virtual string16 GetProfileName() const OVERRIDE; | |
83 virtual gfx::ImageSkia GetIcon() const OVERRIDE; | |
84 virtual content::WebContents* GetWebContents() const OVERRIDE; | |
85 virtual const extensions::Extension* GetExtension() const OVERRIDE; | |
86 | |
87 private: | |
88 // Returns true if contains content rendered by an extension. | |
89 bool HostsExtension() const; | |
90 | |
91 static gfx::ImageSkia* prerender_icon_; | |
92 content::WebContents* web_contents_; | |
93 Profile* profile_; | |
94 bool is_instant_overlay_; | |
95 | |
96 DISALLOW_COPY_AND_ASSIGN(TaskManagerTabContentsResource); | |
97 }; | |
98 | |
99 gfx::ImageSkia* TaskManagerTabContentsResource::prerender_icon_ = NULL; | |
100 | |
101 TaskManagerTabContentsResource::TaskManagerTabContentsResource( | |
102 WebContents* web_contents) | |
103 : TaskManagerRendererResource( | |
104 web_contents->GetRenderProcessHost()->GetHandle(), | |
105 web_contents->GetRenderViewHost()), | |
106 web_contents_(web_contents), | |
107 profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())), | |
108 is_instant_overlay_(IsContentsInstant(web_contents)) { | |
109 if (!prerender_icon_) { | |
110 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
111 prerender_icon_ = rb.GetImageSkiaNamed(IDR_PRERENDER); | |
112 } | |
113 } | |
114 | |
115 TaskManagerTabContentsResource::~TaskManagerTabContentsResource() { | |
116 } | |
117 | |
118 void TaskManagerTabContentsResource::InstantCommitted() { | |
119 DCHECK(is_instant_overlay_); | |
120 is_instant_overlay_ = false; | |
121 } | |
122 | |
123 bool TaskManagerTabContentsResource::HostsExtension() const { | |
124 return web_contents_->GetURL().SchemeIs(extensions::kExtensionScheme); | |
125 } | |
126 | |
127 TaskManager::Resource::Type TaskManagerTabContentsResource::GetType() const { | |
128 return HostsExtension() ? EXTENSION : RENDERER; | |
129 } | |
130 | |
131 string16 TaskManagerTabContentsResource::GetTitle() const { | |
132 // Fall back on the URL if there's no title. | |
133 GURL url = web_contents_->GetURL(); | |
134 string16 tab_title = | |
135 TaskManagerResourceUtil::GetTitleFromWebContents(web_contents_); | |
136 | |
137 // Only classify as an app if the URL is an app and the tab is hosting an | |
138 // extension process. (It's possible to be showing the URL from before it | |
139 // was installed as an app.) | |
140 ExtensionService* extension_service = profile_->GetExtensionService(); | |
141 extensions::ProcessMap* process_map = extension_service->process_map(); | |
142 bool is_app = extension_service->IsInstalledApp(url) && | |
143 process_map->Contains(web_contents_->GetRenderProcessHost()->GetID()); | |
144 | |
145 int message_id = TaskManagerResourceUtil::GetMessagePrefixID( | |
146 is_app, | |
147 HostsExtension(), | |
148 profile_->IsOffTheRecord(), | |
149 IsContentsPrerendering(web_contents_), | |
150 is_instant_overlay_, | |
151 false); // is_background | |
152 return l10n_util::GetStringFUTF16(message_id, tab_title); | |
153 } | |
154 | |
155 string16 TaskManagerTabContentsResource::GetProfileName() const { | |
156 return TaskManagerResourceUtil::GetProfileNameFromInfoCache(profile_); | |
157 } | |
158 | |
159 gfx::ImageSkia TaskManagerTabContentsResource::GetIcon() const { | |
160 if (IsContentsPrerendering(web_contents_)) | |
161 return *prerender_icon_; | |
162 return FaviconTabHelper::FromWebContents(web_contents_)-> | |
163 GetFavicon().AsImageSkia(); | |
164 } | |
165 | |
166 WebContents* TaskManagerTabContentsResource::GetWebContents() const { | |
167 return web_contents_; | |
168 } | |
169 | |
170 const Extension* TaskManagerTabContentsResource::GetExtension() const { | |
171 if (HostsExtension()) { | |
172 ExtensionService* extension_service = profile_->GetExtensionService(); | |
173 return extension_service->extensions()->GetByID( | |
174 web_contents_->GetURL().host()); | |
175 } | |
176 | |
177 return NULL; | |
178 } | |
179 | |
180 //////////////////////////////////////////////////////////////////////////////// | |
181 // TaskManagerTabContentsResourceProvider class | |
182 //////////////////////////////////////////////////////////////////////////////// | |
183 | |
184 TaskManagerTabContentsResourceProvider:: | |
185 TaskManagerTabContentsResourceProvider(TaskManager* task_manager) | |
186 : updating_(false), | |
187 task_manager_(task_manager) { | |
188 } | |
189 | |
190 TaskManagerTabContentsResourceProvider:: | |
191 ~TaskManagerTabContentsResourceProvider() { | |
192 } | |
193 | |
194 TaskManager::Resource* TaskManagerTabContentsResourceProvider::GetResource( | |
195 int origin_pid, | |
196 int render_process_host_id, | |
197 int routing_id) { | |
198 WebContents* web_contents = | |
199 tab_util::GetWebContentsByID(render_process_host_id, routing_id); | |
200 if (!web_contents) // Not one of our resource. | |
201 return NULL; | |
202 | |
203 // If an origin PID was specified then the request originated in a plugin | |
204 // working on the WebContents's behalf, so ignore it. | |
205 if (origin_pid) | |
206 return NULL; | |
207 | |
208 std::map<WebContents*, TaskManagerTabContentsResource*>::iterator | |
209 res_iter = resources_.find(web_contents); | |
210 if (res_iter == resources_.end()) { | |
211 // Can happen if the tab was closed while a network request was being | |
212 // performed. | |
213 return NULL; | |
214 } | |
215 return res_iter->second; | |
216 } | |
217 | |
218 void TaskManagerTabContentsResourceProvider::StartUpdating() { | |
219 DCHECK(!updating_); | |
220 updating_ = true; | |
221 | |
222 // The contents that are tracked by this resource provider are those that | |
223 // are tab contents (WebContents serving as a tab in a Browser), Instant | |
224 // pages, prerender pages, and background printed pages. | |
225 | |
226 // Add all the existing WebContentses. | |
227 for (TabContentsIterator iterator; !iterator.done(); iterator.Next()) | |
228 Add(*iterator); | |
229 | |
230 // Add all the Instant pages. | |
231 for (chrome::BrowserIterator it; !it.done(); it.Next()) { | |
232 if (it->instant_controller() && | |
233 it->instant_controller()->instant()->GetOverlayContents()) { | |
234 Add(it->instant_controller()->instant()->GetOverlayContents()); | |
235 } | |
236 } | |
237 | |
238 // Add all the prerender pages. | |
239 std::vector<Profile*> profiles( | |
240 g_browser_process->profile_manager()->GetLoadedProfiles()); | |
241 for (size_t i = 0; i < profiles.size(); ++i) { | |
242 prerender::PrerenderManager* prerender_manager = | |
243 prerender::PrerenderManagerFactory::GetForProfile(profiles[i]); | |
244 if (prerender_manager) { | |
245 const std::vector<content::WebContents*> contentses = | |
246 prerender_manager->GetAllPrerenderingContents(); | |
247 for (size_t j = 0; j < contentses.size(); ++j) | |
248 Add(contentses[j]); | |
249 } | |
250 } | |
251 | |
252 // Add all the pages being background printed. | |
253 printing::BackgroundPrintingManager* printing_manager = | |
254 g_browser_process->background_printing_manager(); | |
255 for (printing::BackgroundPrintingManager::WebContentsSet::iterator i = | |
256 printing_manager->begin(); | |
257 i != printing_manager->end(); ++i) { | |
258 Add(*i); | |
259 } | |
260 | |
261 // Then we register for notifications to get new web contents. | |
262 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_CONNECTED, | |
263 content::NotificationService::AllBrowserContextsAndSources()); | |
264 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_SWAPPED, | |
265 content::NotificationService::AllBrowserContextsAndSources()); | |
266 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, | |
267 content::NotificationService::AllBrowserContextsAndSources()); | |
268 registrar_.Add(this, chrome::NOTIFICATION_INSTANT_COMMITTED, | |
269 content::NotificationService::AllBrowserContextsAndSources()); | |
270 } | |
271 | |
272 void TaskManagerTabContentsResourceProvider::StopUpdating() { | |
273 DCHECK(updating_); | |
274 updating_ = false; | |
275 | |
276 // Then we unregister for notifications to get new web contents. | |
277 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_CONNECTED, | |
278 content::NotificationService::AllBrowserContextsAndSources()); | |
279 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_SWAPPED, | |
280 content::NotificationService::AllBrowserContextsAndSources()); | |
281 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, | |
282 content::NotificationService::AllBrowserContextsAndSources()); | |
283 registrar_.Remove(this, chrome::NOTIFICATION_INSTANT_COMMITTED, | |
284 content::NotificationService::AllBrowserContextsAndSources()); | |
285 | |
286 // Delete all the resources. | |
287 STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end()); | |
288 | |
289 resources_.clear(); | |
290 } | |
291 | |
292 void TaskManagerTabContentsResourceProvider::AddToTaskManager( | |
293 WebContents* web_contents) { | |
294 TaskManagerTabContentsResource* resource = | |
295 new TaskManagerTabContentsResource(web_contents); | |
296 resources_[web_contents] = resource; | |
297 task_manager_->AddResource(resource); | |
298 } | |
299 | |
300 void TaskManagerTabContentsResourceProvider::Add(WebContents* web_contents) { | |
301 if (!updating_) | |
302 return; | |
303 | |
304 // The contents that are tracked by this resource provider are those that | |
305 // are tab contents (WebContents serving as a tab in a Browser), Instant | |
306 // pages, prerender pages, and background printed pages. | |
307 if (!chrome::FindBrowserWithWebContents(web_contents) && | |
308 !IsContentsPrerendering(web_contents) && | |
309 !IsContentsInstant(web_contents) && | |
310 !IsContentsBackgroundPrinted(web_contents)) { | |
311 return; | |
312 } | |
313 | |
314 // Don't add dead tabs or tabs that haven't yet connected. | |
315 if (!web_contents->GetRenderProcessHost()->GetHandle() || | |
316 !web_contents->WillNotifyDisconnection()) { | |
317 return; | |
318 } | |
319 | |
320 if (resources_.count(web_contents)) { | |
321 // The case may happen that we have added a WebContents as part of the | |
322 // iteration performed during StartUpdating() call but the notification that | |
323 // it has connected was not fired yet. So when the notification happens, we | |
324 // already know about this tab and just ignore it. | |
325 return; | |
326 } | |
327 AddToTaskManager(web_contents); | |
328 } | |
329 | |
330 void TaskManagerTabContentsResourceProvider::Remove(WebContents* web_contents) { | |
331 if (!updating_) | |
332 return; | |
333 std::map<WebContents*, TaskManagerTabContentsResource*>::iterator | |
334 iter = resources_.find(web_contents); | |
335 if (iter == resources_.end()) { | |
336 // Since WebContents are destroyed asynchronously (see TabContentsCollector | |
337 // in navigation_controller.cc), we can be notified of a tab being removed | |
338 // that we don't know. This can happen if the user closes a tab and quickly | |
339 // opens the task manager, before the tab is actually destroyed. | |
340 return; | |
341 } | |
342 | |
343 // Remove the resource from the Task Manager. | |
344 TaskManagerTabContentsResource* resource = iter->second; | |
345 task_manager_->RemoveResource(resource); | |
346 // And from the provider. | |
347 resources_.erase(iter); | |
348 // Finally, delete the resource. | |
349 delete resource; | |
350 } | |
351 | |
352 void TaskManagerTabContentsResourceProvider::InstantCommitted( | |
353 WebContents* web_contents) { | |
354 if (!updating_) | |
355 return; | |
356 std::map<WebContents*, TaskManagerTabContentsResource*>::iterator | |
357 iter = resources_.find(web_contents); | |
358 DCHECK(iter != resources_.end()); | |
359 if (iter != resources_.end()) | |
360 iter->second->InstantCommitted(); | |
361 } | |
362 | |
363 void TaskManagerTabContentsResourceProvider::Observe( | |
364 int type, | |
365 const content::NotificationSource& source, | |
366 const content::NotificationDetails& details) { | |
367 WebContents* web_contents = content::Source<WebContents>(source).ptr(); | |
368 | |
369 switch (type) { | |
370 case content::NOTIFICATION_WEB_CONTENTS_CONNECTED: | |
371 Add(web_contents); | |
372 break; | |
373 case content::NOTIFICATION_WEB_CONTENTS_SWAPPED: | |
374 Remove(web_contents); | |
375 Add(web_contents); | |
376 break; | |
377 case content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED: | |
378 Remove(web_contents); | |
379 break; | |
380 case chrome::NOTIFICATION_INSTANT_COMMITTED: | |
381 InstantCommitted(web_contents); | |
382 break; | |
383 default: | |
384 NOTREACHED() << "Unexpected notification."; | |
385 return; | |
386 } | |
387 } | |
OLD | NEW |