Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / task_manager / background_resource_provider.cc
blob4e72f904e0b61bbaaac307f19381cfb86b14ab33
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 {
41 public:
42 BackgroundContentsResource(
43 BackgroundContents* background_contents,
44 const base::string16& application_name);
45 virtual ~BackgroundContentsResource();
47 // Resource methods:
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_; }
54 private:
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)
75 : RendererResource(
76 background_contents->web_contents()->GetRenderProcessHost()->
77 GetHandle() ?
78 background_contents->web_contents()->GetRenderProcessHost()->
79 GetHandle() :
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.
86 if (!default_icon_) {
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_;
101 if (title.empty()) {
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 {
119 return true;
122 ////////////////////////////////////////////////////////////////////////////////
123 // BackgroundContentsResourceProvider class
124 ////////////////////////////////////////////////////////////////////////////////
126 BackgroundContentsResourceProvider::
127 BackgroundContentsResourceProvider(TaskManager* task_manager)
128 : updating_(false),
129 task_manager_(task_manager) {
132 BackgroundContentsResourceProvider::~BackgroundContentsResourceProvider() {
135 Resource* BackgroundContentsResourceProvider::GetResource(
136 int origin_pid,
137 int child_id,
138 int route_id) {
139 // If an origin PID was specified, the request is from a plugin, not the
140 // render view host process
141 if (origin_pid)
142 return NULL;
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())
151 return i->second;
154 // Can happen if the page went away while a network request was being
155 // performed.
156 return NULL;
159 void BackgroundContentsResourceProvider::StartUpdating() {
160 DCHECK(!updating_);
161 updating_ = true;
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);
188 if (extension)
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() {
207 DCHECK(updating_);
208 updating_ = false;
210 // Unregister for notifications
211 registrar_.Remove(
212 this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_OPENED,
213 content::NotificationService::AllBrowserContextsAndSources());
214 registrar_.Remove(
215 this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED,
216 content::NotificationService::AllBrowserContextsAndSources());
217 registrar_.Remove(
218 this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED,
219 content::NotificationService::AllBrowserContextsAndSources());
220 registrar_.Remove(
221 this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
222 content::NotificationService::AllBrowserContextsAndSources());
224 // Delete all the resources.
225 STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
227 resources_.clear();
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) {
241 if (!updating_)
242 return;
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) {
254 if (!updating_)
255 return;
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.
265 delete resource;
268 void BackgroundContentsResourceProvider::Observe(
269 int type,
270 const content::NotificationSource& source,
271 const content::NotificationDetails& details) {
272 switch (type) {
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();
282 if (service) {
283 std::string application_id = base::UTF16ToUTF8(
284 content::Details<BackgroundContentsOpenedDetails>(details)->
285 application_id);
286 const Extension* extension =
287 service->GetExtensionById(application_id, false);
288 // Extension can be NULL when running unit tests.
289 if (extension)
290 application_name = base::UTF8ToUTF16(extension->name());
292 Add(content::Details<BackgroundContentsOpenedDetails>(details)->contents,
293 application_name);
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();
297 break;
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());
307 Remove(contents);
308 Add(contents, application_name);
309 break;
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();
316 break;
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();
320 i++) {
321 if (i->first->web_contents() == web_contents) {
322 base::string16 application_name = i->second->application_name();
323 BackgroundContents* contents = i->first;
324 Remove(contents);
325 Add(contents, application_name);
326 return;
329 break;
331 default:
332 NOTREACHED() << "Unexpected notification.";
333 return;
337 } // namespace task_manager