| OLD | NEW |
| (Empty) |
| 1 // Copyright 2013 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_background_resource_provider.
h" | |
| 6 | |
| 7 #include "base/i18n/rtl.h" | |
| 8 #include "base/string16.h" | |
| 9 #include "base/utf_string_conversions.h" | |
| 10 #include "chrome/browser/background/background_contents_service.h" | |
| 11 #include "chrome/browser/background/background_contents_service_factory.h" | |
| 12 #include "chrome/browser/browser_process.h" | |
| 13 #include "chrome/browser/extensions/extension_service.h" | |
| 14 #include "chrome/browser/profiles/profile.h" | |
| 15 #include "chrome/browser/profiles/profile_manager.h" | |
| 16 #include "chrome/browser/tab_contents/background_contents.h" | |
| 17 #include "chrome/browser/task_manager/task_manager_render_resource.h" | |
| 18 #include "chrome/common/chrome_notification_types.h" | |
| 19 #include "chrome/common/extensions/extension.h" | |
| 20 #include "content/public/browser/notification_service.h" | |
| 21 #include "content/public/browser/render_process_host.h" | |
| 22 #include "content/public/browser/render_view_host.h" | |
| 23 #include "content/public/browser/web_contents.h" | |
| 24 #include "grit/generated_resources.h" | |
| 25 #include "grit/theme_resources.h" | |
| 26 #include "ui/base/l10n/l10n_util.h" | |
| 27 #include "ui/base/resource/resource_bundle.h" | |
| 28 #include "ui/gfx/image/image_skia.h" | |
| 29 | |
| 30 using content::RenderProcessHost; | |
| 31 using content::RenderViewHost; | |
| 32 using content::WebContents; | |
| 33 using extensions::Extension; | |
| 34 | |
| 35 class TaskManagerBackgroundContentsResource | |
| 36 : public TaskManagerRendererResource { | |
| 37 public: | |
| 38 TaskManagerBackgroundContentsResource( | |
| 39 BackgroundContents* background_contents, | |
| 40 const string16& application_name); | |
| 41 virtual ~TaskManagerBackgroundContentsResource(); | |
| 42 | |
| 43 // TaskManager::Resource methods: | |
| 44 virtual string16 GetTitle() const OVERRIDE; | |
| 45 virtual string16 GetProfileName() const OVERRIDE; | |
| 46 virtual gfx::ImageSkia GetIcon() const OVERRIDE; | |
| 47 virtual bool IsBackground() const OVERRIDE; | |
| 48 | |
| 49 const string16& application_name() const { return application_name_; } | |
| 50 private: | |
| 51 BackgroundContents* background_contents_; | |
| 52 | |
| 53 string16 application_name_; | |
| 54 | |
| 55 // The icon painted for BackgroundContents. | |
| 56 // TODO(atwilson): Use the favicon when there's a way to get the favicon for | |
| 57 // BackgroundContents. | |
| 58 static gfx::ImageSkia* default_icon_; | |
| 59 | |
| 60 DISALLOW_COPY_AND_ASSIGN(TaskManagerBackgroundContentsResource); | |
| 61 }; | |
| 62 | |
| 63 gfx::ImageSkia* TaskManagerBackgroundContentsResource::default_icon_ = NULL; | |
| 64 | |
| 65 // TODO(atwilson): http://crbug.com/116893 | |
| 66 // HACK: if the process handle is invalid, we use the current process's handle. | |
| 67 // This preserves old behavior but is incorrect, and should be fixed. | |
| 68 TaskManagerBackgroundContentsResource::TaskManagerBackgroundContentsResource( | |
| 69 BackgroundContents* background_contents, | |
| 70 const string16& application_name) | |
| 71 : TaskManagerRendererResource( | |
| 72 background_contents->web_contents()->GetRenderProcessHost()-> | |
| 73 GetHandle() ? | |
| 74 background_contents->web_contents()->GetRenderProcessHost()-> | |
| 75 GetHandle() : | |
| 76 base::Process::Current().handle(), | |
| 77 background_contents->web_contents()->GetRenderViewHost()), | |
| 78 background_contents_(background_contents), | |
| 79 application_name_(application_name) { | |
| 80 // Just use the same icon that other extension resources do. | |
| 81 // TODO(atwilson): Use the favicon when that's available. | |
| 82 if (!default_icon_) { | |
| 83 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
| 84 default_icon_ = rb.GetImageSkiaNamed(IDR_PLUGINS_FAVICON); | |
| 85 } | |
| 86 // Ensure that the string has the appropriate direction markers (see comment | |
| 87 // in TaskManagerTabContentsResource::GetTitle()). | |
| 88 base::i18n::AdjustStringForLocaleDirection(&application_name_); | |
| 89 } | |
| 90 | |
| 91 TaskManagerBackgroundContentsResource::~TaskManagerBackgroundContentsResource( | |
| 92 ) { | |
| 93 } | |
| 94 | |
| 95 string16 TaskManagerBackgroundContentsResource::GetTitle() const { | |
| 96 string16 title = application_name_; | |
| 97 | |
| 98 if (title.empty()) { | |
| 99 // No title (can't locate the parent app for some reason) so just display | |
| 100 // the URL (properly forced to be LTR). | |
| 101 title = base::i18n::GetDisplayStringInLTRDirectionality( | |
| 102 UTF8ToUTF16(background_contents_->GetURL().spec())); | |
| 103 } | |
| 104 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_BACKGROUND_PREFIX, title); | |
| 105 } | |
| 106 | |
| 107 string16 TaskManagerBackgroundContentsResource::GetProfileName() const { | |
| 108 return string16(); | |
| 109 } | |
| 110 | |
| 111 gfx::ImageSkia TaskManagerBackgroundContentsResource::GetIcon() const { | |
| 112 return *default_icon_; | |
| 113 } | |
| 114 | |
| 115 bool TaskManagerBackgroundContentsResource::IsBackground() const { | |
| 116 return true; | |
| 117 } | |
| 118 | |
| 119 //////////////////////////////////////////////////////////////////////////////// | |
| 120 // TaskManagerBackgroundContentsResourceProvider class | |
| 121 //////////////////////////////////////////////////////////////////////////////// | |
| 122 | |
| 123 TaskManagerBackgroundContentsResourceProvider:: | |
| 124 TaskManagerBackgroundContentsResourceProvider(TaskManager* task_manager) | |
| 125 : updating_(false), | |
| 126 task_manager_(task_manager) { | |
| 127 } | |
| 128 | |
| 129 TaskManagerBackgroundContentsResourceProvider:: | |
| 130 ~TaskManagerBackgroundContentsResourceProvider() { | |
| 131 } | |
| 132 | |
| 133 TaskManager::Resource* | |
| 134 TaskManagerBackgroundContentsResourceProvider::GetResource( | |
| 135 int origin_pid, | |
| 136 int render_process_host_id, | |
| 137 int routing_id) { | |
| 138 // If an origin PID was specified, the request is from a plugin, not the | |
| 139 // render view host process | |
| 140 if (origin_pid) | |
| 141 return NULL; | |
| 142 | |
| 143 for (Resources::iterator i = resources_.begin(); i != resources_.end(); i++) { | |
| 144 WebContents* tab = i->first->web_contents(); | |
| 145 if (tab->GetRenderProcessHost()->GetID() == render_process_host_id | |
| 146 && tab->GetRenderViewHost()->GetRoutingID() == routing_id) { | |
| 147 return i->second; | |
| 148 } | |
| 149 } | |
| 150 | |
| 151 // Can happen if the page went away while a network request was being | |
| 152 // performed. | |
| 153 return NULL; | |
| 154 } | |
| 155 | |
| 156 void TaskManagerBackgroundContentsResourceProvider::StartUpdating() { | |
| 157 DCHECK(!updating_); | |
| 158 updating_ = true; | |
| 159 | |
| 160 // Add all the existing BackgroundContents from every profile, including | |
| 161 // incognito profiles. | |
| 162 ProfileManager* profile_manager = g_browser_process->profile_manager(); | |
| 163 std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles()); | |
| 164 size_t num_default_profiles = profiles.size(); | |
| 165 for (size_t i = 0; i < num_default_profiles; ++i) { | |
| 166 if (profiles[i]->HasOffTheRecordProfile()) { | |
| 167 profiles.push_back(profiles[i]->GetOffTheRecordProfile()); | |
| 168 } | |
| 169 } | |
| 170 for (size_t i = 0; i < profiles.size(); ++i) { | |
| 171 BackgroundContentsService* background_contents_service = | |
| 172 BackgroundContentsServiceFactory::GetForProfile(profiles[i]); | |
| 173 std::vector<BackgroundContents*> contents = | |
| 174 background_contents_service->GetBackgroundContents(); | |
| 175 ExtensionService* extension_service = profiles[i]->GetExtensionService(); | |
| 176 for (std::vector<BackgroundContents*>::iterator iterator = contents.begin(); | |
| 177 iterator != contents.end(); ++iterator) { | |
| 178 string16 application_name; | |
| 179 // Lookup the name from the parent extension. | |
| 180 if (extension_service) { | |
| 181 const string16& application_id = | |
| 182 background_contents_service->GetParentApplicationId(*iterator); | |
| 183 const Extension* extension = extension_service->GetExtensionById( | |
| 184 UTF16ToUTF8(application_id), false); | |
| 185 if (extension) | |
| 186 application_name = UTF8ToUTF16(extension->name()); | |
| 187 } | |
| 188 Add(*iterator, application_name); | |
| 189 } | |
| 190 } | |
| 191 | |
| 192 // Then we register for notifications to get new BackgroundContents. | |
| 193 registrar_.Add(this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_OPENED, | |
| 194 content::NotificationService::AllBrowserContextsAndSources()); | |
| 195 registrar_.Add(this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED, | |
| 196 content::NotificationService::AllBrowserContextsAndSources()); | |
| 197 registrar_.Add(this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED, | |
| 198 content::NotificationService::AllBrowserContextsAndSources()); | |
| 199 } | |
| 200 | |
| 201 void TaskManagerBackgroundContentsResourceProvider::StopUpdating() { | |
| 202 DCHECK(updating_); | |
| 203 updating_ = false; | |
| 204 | |
| 205 // Unregister for notifications | |
| 206 registrar_.Remove( | |
| 207 this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_OPENED, | |
| 208 content::NotificationService::AllBrowserContextsAndSources()); | |
| 209 registrar_.Remove( | |
| 210 this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED, | |
| 211 content::NotificationService::AllBrowserContextsAndSources()); | |
| 212 registrar_.Remove( | |
| 213 this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED, | |
| 214 content::NotificationService::AllBrowserContextsAndSources()); | |
| 215 | |
| 216 // Delete all the resources. | |
| 217 STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end()); | |
| 218 | |
| 219 resources_.clear(); | |
| 220 } | |
| 221 | |
| 222 void TaskManagerBackgroundContentsResourceProvider::AddToTaskManager( | |
| 223 BackgroundContents* background_contents, | |
| 224 const string16& application_name) { | |
| 225 TaskManagerBackgroundContentsResource* resource = | |
| 226 new TaskManagerBackgroundContentsResource(background_contents, | |
| 227 application_name); | |
| 228 resources_[background_contents] = resource; | |
| 229 task_manager_->AddResource(resource); | |
| 230 } | |
| 231 | |
| 232 void TaskManagerBackgroundContentsResourceProvider::Add( | |
| 233 BackgroundContents* contents, const string16& application_name) { | |
| 234 if (!updating_) | |
| 235 return; | |
| 236 | |
| 237 // TODO(atwilson): http://crbug.com/116893 | |
| 238 // We should check that the process handle is valid here, but it won't | |
| 239 // be in the case of NOTIFICATION_BACKGROUND_CONTENTS_OPENED. | |
| 240 | |
| 241 // Should never add the same BackgroundContents twice. | |
| 242 DCHECK(resources_.find(contents) == resources_.end()); | |
| 243 AddToTaskManager(contents, application_name); | |
| 244 } | |
| 245 | |
| 246 void TaskManagerBackgroundContentsResourceProvider::Remove( | |
| 247 BackgroundContents* contents) { | |
| 248 if (!updating_) | |
| 249 return; | |
| 250 Resources::iterator iter = resources_.find(contents); | |
| 251 DCHECK(iter != resources_.end()); | |
| 252 | |
| 253 // Remove the resource from the Task Manager. | |
| 254 TaskManagerBackgroundContentsResource* resource = iter->second; | |
| 255 task_manager_->RemoveResource(resource); | |
| 256 // And from the provider. | |
| 257 resources_.erase(iter); | |
| 258 // Finally, delete the resource. | |
| 259 delete resource; | |
| 260 } | |
| 261 | |
| 262 void TaskManagerBackgroundContentsResourceProvider::Observe( | |
| 263 int type, | |
| 264 const content::NotificationSource& source, | |
| 265 const content::NotificationDetails& details) { | |
| 266 switch (type) { | |
| 267 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_OPENED: { | |
| 268 // Get the name from the parent application. If no parent application is | |
| 269 // found, just pass an empty string - BackgroundContentsResource::GetTitle | |
| 270 // will display the URL instead in this case. This should never happen | |
| 271 // except in rare cases when an extension is being unloaded or chrome is | |
| 272 // exiting while the task manager is displayed. | |
| 273 string16 application_name; | |
| 274 ExtensionService* service = | |
| 275 content::Source<Profile>(source)->GetExtensionService(); | |
| 276 if (service) { | |
| 277 std::string application_id = UTF16ToUTF8( | |
| 278 content::Details<BackgroundContentsOpenedDetails>(details)-> | |
| 279 application_id); | |
| 280 const Extension* extension = | |
| 281 service->GetExtensionById(application_id, false); | |
| 282 // Extension can be NULL when running unit tests. | |
| 283 if (extension) | |
| 284 application_name = UTF8ToUTF16(extension->name()); | |
| 285 } | |
| 286 Add(content::Details<BackgroundContentsOpenedDetails>(details)->contents, | |
| 287 application_name); | |
| 288 // Opening a new BackgroundContents needs to force the display to refresh | |
| 289 // (applications may now be considered "background" that weren't before). | |
| 290 task_manager_->ModelChanged(); | |
| 291 break; | |
| 292 } | |
| 293 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED: { | |
| 294 BackgroundContents* contents = | |
| 295 content::Details<BackgroundContents>(details).ptr(); | |
| 296 // Should never get a NAVIGATED before OPENED. | |
| 297 DCHECK(resources_.find(contents) != resources_.end()); | |
| 298 // Preserve the application name. | |
| 299 string16 application_name( | |
| 300 resources_.find(contents)->second->application_name()); | |
| 301 Remove(contents); | |
| 302 Add(contents, application_name); | |
| 303 break; | |
| 304 } | |
| 305 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED: | |
| 306 Remove(content::Details<BackgroundContents>(details).ptr()); | |
| 307 // Closing a BackgroundContents needs to force the display to refresh | |
| 308 // (applications may now be considered "foreground" that weren't before). | |
| 309 task_manager_->ModelChanged(); | |
| 310 break; | |
| 311 default: | |
| 312 NOTREACHED() << "Unexpected notification."; | |
| 313 return; | |
| 314 } | |
| 315 } | |
| OLD | NEW |