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