| 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 |