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 |