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.
5 #include "chrome/browser/task_manager/background_resource_provider.h"
7 #include "base/i18n/rtl.h"
8 #include "base/strings/string16.h"
9 #include "base/strings/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/chrome_notification_types.h"
14 #include "chrome/browser/extensions/extension_service.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/profiles/profile_manager.h"
17 #include "chrome/browser/tab_contents/background_contents.h"
18 #include "chrome/browser/task_manager/renderer_resource.h"
19 #include "chrome/browser/task_manager/resource_provider.h"
20 #include "chrome/browser/task_manager/task_manager.h"
21 #include "content/public/browser/notification_service.h"
22 #include "content/public/browser/render_frame_host.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 "extensions/common/extension.h"
27 #include "grit/generated_resources.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"
33 using content::RenderProcessHost
;
34 using content::RenderViewHost
;
35 using content::WebContents
;
36 using extensions::Extension
;
38 namespace task_manager
{
40 class BackgroundContentsResource
: public RendererResource
{
42 BackgroundContentsResource(
43 BackgroundContents
* background_contents
,
44 const base::string16
& application_name
);
45 virtual ~BackgroundContentsResource();
48 virtual base::string16
GetTitle() const OVERRIDE
;
49 virtual base::string16
GetProfileName() const OVERRIDE
;
50 virtual gfx::ImageSkia
GetIcon() const OVERRIDE
;
51 virtual bool IsBackground() const OVERRIDE
;
53 const base::string16
& application_name() const { return application_name_
; }
55 BackgroundContents
* background_contents_
;
57 base::string16 application_name_
;
59 // The icon painted for BackgroundContents.
60 // TODO(atwilson): Use the favicon when there's a way to get the favicon for
61 // BackgroundContents.
62 static gfx::ImageSkia
* default_icon_
;
64 DISALLOW_COPY_AND_ASSIGN(BackgroundContentsResource
);
67 gfx::ImageSkia
* BackgroundContentsResource::default_icon_
= NULL
;
69 // TODO(atwilson): http://crbug.com/116893
70 // HACK: if the process handle is invalid, we use the current process's handle.
71 // This preserves old behavior but is incorrect, and should be fixed.
72 BackgroundContentsResource::BackgroundContentsResource(
73 BackgroundContents
* background_contents
,
74 const base::string16
& application_name
)
76 background_contents
->web_contents()->GetRenderProcessHost()->
78 background_contents
->web_contents()->GetRenderProcessHost()->
80 base::Process::Current().handle(),
81 background_contents
->web_contents()->GetRenderViewHost()),
82 background_contents_(background_contents
),
83 application_name_(application_name
) {
84 // Just use the same icon that other extension resources do.
85 // TODO(atwilson): Use the favicon when that's available.
87 ResourceBundle
& rb
= ResourceBundle::GetSharedInstance();
88 default_icon_
= rb
.GetImageSkiaNamed(IDR_PLUGINS_FAVICON
);
90 // Ensure that the string has the appropriate direction markers (see comment
91 // in TabContentsResource::GetTitle()).
92 base::i18n::AdjustStringForLocaleDirection(&application_name_
);
95 BackgroundContentsResource::~BackgroundContentsResource() {
98 base::string16
BackgroundContentsResource::GetTitle() const {
99 base::string16 title
= application_name_
;
102 // No title (can't locate the parent app for some reason) so just display
103 // the URL (properly forced to be LTR).
104 title
= base::i18n::GetDisplayStringInLTRDirectionality(
105 base::UTF8ToUTF16(background_contents_
->GetURL().spec()));
107 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_BACKGROUND_PREFIX
, title
);
110 base::string16
BackgroundContentsResource::GetProfileName() const {
111 return base::string16();
114 gfx::ImageSkia
BackgroundContentsResource::GetIcon() const {
115 return *default_icon_
;
118 bool BackgroundContentsResource::IsBackground() const {
122 ////////////////////////////////////////////////////////////////////////////////
123 // BackgroundContentsResourceProvider class
124 ////////////////////////////////////////////////////////////////////////////////
126 BackgroundContentsResourceProvider::
127 BackgroundContentsResourceProvider(TaskManager
* task_manager
)
129 task_manager_(task_manager
) {
132 BackgroundContentsResourceProvider::~BackgroundContentsResourceProvider() {
135 Resource
* BackgroundContentsResourceProvider::GetResource(
139 // If an origin PID was specified, the request is from a plugin, not the
140 // render view host process
144 content::RenderFrameHost
* rfh
=
145 content::RenderFrameHost::FromID(child_id
, route_id
);
146 content::WebContents
* web_contents
=
147 content::WebContents::FromRenderFrameHost(rfh
);
149 for (Resources::iterator i
= resources_
.begin(); i
!= resources_
.end(); i
++) {
150 if (web_contents
== i
->first
->web_contents())
154 // Can happen if the page went away while a network request was being
159 void BackgroundContentsResourceProvider::StartUpdating() {
163 // Add all the existing BackgroundContents from every profile, including
164 // incognito profiles.
165 ProfileManager
* profile_manager
= g_browser_process
->profile_manager();
166 std::vector
<Profile
*> profiles(profile_manager
->GetLoadedProfiles());
167 size_t num_default_profiles
= profiles
.size();
168 for (size_t i
= 0; i
< num_default_profiles
; ++i
) {
169 if (profiles
[i
]->HasOffTheRecordProfile()) {
170 profiles
.push_back(profiles
[i
]->GetOffTheRecordProfile());
173 for (size_t i
= 0; i
< profiles
.size(); ++i
) {
174 BackgroundContentsService
* background_contents_service
=
175 BackgroundContentsServiceFactory::GetForProfile(profiles
[i
]);
176 std::vector
<BackgroundContents
*> contents
=
177 background_contents_service
->GetBackgroundContents();
178 ExtensionService
* extension_service
= profiles
[i
]->GetExtensionService();
179 for (std::vector
<BackgroundContents
*>::iterator iterator
= contents
.begin();
180 iterator
!= contents
.end(); ++iterator
) {
181 base::string16 application_name
;
182 // Lookup the name from the parent extension.
183 if (extension_service
) {
184 const base::string16
& application_id
=
185 background_contents_service
->GetParentApplicationId(*iterator
);
186 const Extension
* extension
= extension_service
->GetExtensionById(
187 base::UTF16ToUTF8(application_id
), false);
189 application_name
= base::UTF8ToUTF16(extension
->name());
191 Add(*iterator
, application_name
);
195 // Then we register for notifications to get new BackgroundContents.
196 registrar_
.Add(this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_OPENED
,
197 content::NotificationService::AllBrowserContextsAndSources());
198 registrar_
.Add(this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED
,
199 content::NotificationService::AllBrowserContextsAndSources());
200 registrar_
.Add(this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED
,
201 content::NotificationService::AllBrowserContextsAndSources());
202 registrar_
.Add(this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED
,
203 content::NotificationService::AllBrowserContextsAndSources());
206 void BackgroundContentsResourceProvider::StopUpdating() {
210 // Unregister for notifications
212 this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_OPENED
,
213 content::NotificationService::AllBrowserContextsAndSources());
215 this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED
,
216 content::NotificationService::AllBrowserContextsAndSources());
218 this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED
,
219 content::NotificationService::AllBrowserContextsAndSources());
221 this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED
,
222 content::NotificationService::AllBrowserContextsAndSources());
224 // Delete all the resources.
225 STLDeleteContainerPairSecondPointers(resources_
.begin(), resources_
.end());
230 void BackgroundContentsResourceProvider::AddToTaskManager(
231 BackgroundContents
* background_contents
,
232 const base::string16
& application_name
) {
233 BackgroundContentsResource
* resource
=
234 new BackgroundContentsResource(background_contents
, application_name
);
235 resources_
[background_contents
] = resource
;
236 task_manager_
->AddResource(resource
);
239 void BackgroundContentsResourceProvider::Add(
240 BackgroundContents
* contents
, const base::string16
& application_name
) {
244 // TODO(atwilson): http://crbug.com/116893
245 // We should check that the process handle is valid here, but it won't
246 // be in the case of NOTIFICATION_BACKGROUND_CONTENTS_OPENED.
248 // Should never add the same BackgroundContents twice.
249 DCHECK(resources_
.find(contents
) == resources_
.end());
250 AddToTaskManager(contents
, application_name
);
253 void BackgroundContentsResourceProvider::Remove(BackgroundContents
* contents
) {
256 Resources::iterator iter
= resources_
.find(contents
);
257 DCHECK(iter
!= resources_
.end());
259 // Remove the resource from the Task Manager.
260 BackgroundContentsResource
* resource
= iter
->second
;
261 task_manager_
->RemoveResource(resource
);
262 // And from the provider.
263 resources_
.erase(iter
);
264 // Finally, delete the resource.
268 void BackgroundContentsResourceProvider::Observe(
270 const content::NotificationSource
& source
,
271 const content::NotificationDetails
& details
) {
273 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_OPENED
: {
274 // Get the name from the parent application. If no parent application is
275 // found, just pass an empty string - BackgroundContentsResource::GetTitle
276 // will display the URL instead in this case. This should never happen
277 // except in rare cases when an extension is being unloaded or chrome is
278 // exiting while the task manager is displayed.
279 base::string16 application_name
;
280 ExtensionService
* service
=
281 content::Source
<Profile
>(source
)->GetExtensionService();
283 std::string application_id
= base::UTF16ToUTF8(
284 content::Details
<BackgroundContentsOpenedDetails
>(details
)->
286 const Extension
* extension
=
287 service
->GetExtensionById(application_id
, false);
288 // Extension can be NULL when running unit tests.
290 application_name
= base::UTF8ToUTF16(extension
->name());
292 Add(content::Details
<BackgroundContentsOpenedDetails
>(details
)->contents
,
294 // Opening a new BackgroundContents needs to force the display to refresh
295 // (applications may now be considered "background" that weren't before).
296 task_manager_
->ModelChanged();
299 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED
: {
300 BackgroundContents
* contents
=
301 content::Details
<BackgroundContents
>(details
).ptr();
302 // Should never get a NAVIGATED before OPENED.
303 DCHECK(resources_
.find(contents
) != resources_
.end());
304 // Preserve the application name.
305 base::string16
application_name(
306 resources_
.find(contents
)->second
->application_name());
308 Add(contents
, application_name
);
311 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED
:
312 Remove(content::Details
<BackgroundContents
>(details
).ptr());
313 // Closing a BackgroundContents needs to force the display to refresh
314 // (applications may now be considered "foreground" that weren't before).
315 task_manager_
->ModelChanged();
317 case content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED
: {
318 WebContents
* web_contents
= content::Source
<WebContents
>(source
).ptr();
319 for (Resources::iterator i
= resources_
.begin(); i
!= resources_
.end();
321 if (i
->first
->web_contents() == web_contents
) {
322 base::string16 application_name
= i
->second
->application_name();
323 BackgroundContents
* contents
= i
->first
;
325 Add(contents
, application_name
);
332 NOTREACHED() << "Unexpected notification.";
337 } // namespace task_manager