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/extension_process_resource_provider.h" 6 7#include "base/strings/string16.h" 8#include "base/strings/utf_string_conversions.h" 9#include "chrome/browser/browser_process.h" 10#include "chrome/browser/chrome_notification_types.h" 11#include "chrome/browser/devtools/devtools_window.h" 12#include "chrome/browser/extensions/extension_host.h" 13#include "chrome/browser/extensions/extension_process_manager.h" 14#include "chrome/browser/extensions/extension_system.h" 15#include "chrome/browser/profiles/profile.h" 16#include "chrome/browser/profiles/profile_manager.h" 17#include "chrome/browser/task_manager/resource_provider.h" 18#include "chrome/browser/task_manager/task_manager.h" 19#include "chrome/browser/task_manager/task_manager_util.h" 20#include "chrome/common/extensions/extension.h" 21#include "content/public/browser/notification_details.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/site_instance.h" 26#include "content/public/browser/web_contents.h" 27#include "extensions/browser/view_type_utils.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" 32 33using content::WebContents; 34using extensions::Extension; 35 36namespace task_manager { 37 38class ExtensionProcessResource : public Resource { 39 public: 40 explicit ExtensionProcessResource( 41 content::RenderViewHost* render_view_host); 42 virtual ~ExtensionProcessResource(); 43 44 // Resource methods: 45 virtual string16 GetTitle() const OVERRIDE; 46 virtual string16 GetProfileName() const OVERRIDE; 47 virtual gfx::ImageSkia GetIcon() const OVERRIDE; 48 virtual base::ProcessHandle GetProcess() const OVERRIDE; 49 virtual int GetUniqueChildProcessId() const OVERRIDE; 50 virtual Type GetType() const OVERRIDE; 51 virtual bool CanInspect() const OVERRIDE; 52 virtual void Inspect() const OVERRIDE; 53 virtual bool SupportNetworkUsage() const OVERRIDE; 54 virtual void SetSupportNetworkUsage() OVERRIDE; 55 virtual const extensions::Extension* GetExtension() const OVERRIDE; 56 57 // Returns the pid of the extension process. 58 int process_id() const { return pid_; } 59 60 // Returns true if the associated extension has a background page. 61 virtual bool IsBackground() const OVERRIDE; 62 63 private: 64 // The icon painted for the extension process. 65 static gfx::ImageSkia* default_icon_; 66 67 content::RenderViewHost* render_view_host_; 68 69 // Cached data about the extension. 70 base::ProcessHandle process_handle_; 71 int pid_; 72 int unique_process_id_; 73 string16 title_; 74 75 DISALLOW_COPY_AND_ASSIGN(ExtensionProcessResource); 76}; 77 78gfx::ImageSkia* ExtensionProcessResource::default_icon_ = NULL; 79 80ExtensionProcessResource::ExtensionProcessResource( 81 content::RenderViewHost* render_view_host) 82 : render_view_host_(render_view_host) { 83 if (!default_icon_) { 84 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 85 default_icon_ = rb.GetImageSkiaNamed(IDR_PLUGINS_FAVICON); 86 } 87 process_handle_ = render_view_host_->GetProcess()->GetHandle(); 88 unique_process_id_ = render_view_host->GetProcess()->GetID(); 89 pid_ = base::GetProcId(process_handle_); 90 string16 extension_name = UTF8ToUTF16(GetExtension()->name()); 91 DCHECK(!extension_name.empty()); 92 93 Profile* profile = Profile::FromBrowserContext( 94 render_view_host->GetProcess()->GetBrowserContext()); 95 int message_id = util::GetMessagePrefixID( 96 GetExtension()->is_app(), 97 true, // is_extension 98 profile->IsOffTheRecord(), 99 false, // is_prerender 100 false, // is_instant_overlay 101 IsBackground()); 102 title_ = l10n_util::GetStringFUTF16(message_id, extension_name); 103} 104 105ExtensionProcessResource::~ExtensionProcessResource() { 106} 107 108string16 ExtensionProcessResource::GetTitle() const { 109 return title_; 110} 111 112string16 ExtensionProcessResource::GetProfileName() const { 113 return util::GetProfileNameFromInfoCache( 114 Profile::FromBrowserContext( 115 render_view_host_->GetProcess()->GetBrowserContext())); 116} 117 118gfx::ImageSkia ExtensionProcessResource::GetIcon() const { 119 return *default_icon_; 120} 121 122base::ProcessHandle ExtensionProcessResource::GetProcess() const { 123 return process_handle_; 124} 125 126int ExtensionProcessResource::GetUniqueChildProcessId() const { 127 return unique_process_id_; 128} 129 130Resource::Type ExtensionProcessResource::GetType() const { 131 return EXTENSION; 132} 133 134bool ExtensionProcessResource::CanInspect() const { 135 return true; 136} 137 138void ExtensionProcessResource::Inspect() const { 139 DevToolsWindow::OpenDevToolsWindow(render_view_host_); 140} 141 142bool ExtensionProcessResource::SupportNetworkUsage() const { 143 return true; 144} 145 146void ExtensionProcessResource::SetSupportNetworkUsage() { 147 NOTREACHED(); 148} 149 150const Extension* ExtensionProcessResource::GetExtension() const { 151 Profile* profile = Profile::FromBrowserContext( 152 render_view_host_->GetProcess()->GetBrowserContext()); 153 ExtensionProcessManager* process_manager = 154 extensions::ExtensionSystem::Get(profile)->process_manager(); 155 return process_manager->GetExtensionForRenderViewHost(render_view_host_); 156} 157 158bool ExtensionProcessResource::IsBackground() const { 159 WebContents* web_contents = 160 WebContents::FromRenderViewHost(render_view_host_); 161 extensions::ViewType view_type = extensions::GetViewType(web_contents); 162 return view_type == extensions::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE; 163} 164 165//////////////////////////////////////////////////////////////////////////////// 166// ExtensionProcessResourceProvider class 167//////////////////////////////////////////////////////////////////////////////// 168 169ExtensionProcessResourceProvider:: 170 ExtensionProcessResourceProvider(TaskManager* task_manager) 171 : task_manager_(task_manager), 172 updating_(false) { 173} 174 175ExtensionProcessResourceProvider::~ExtensionProcessResourceProvider() { 176} 177 178Resource* ExtensionProcessResourceProvider::GetResource( 179 int origin_pid, 180 int render_process_host_id, 181 int routing_id) { 182 // If an origin PID was specified, the request is from a plugin, not the 183 // render view host process 184 if (origin_pid) 185 return NULL; 186 187 for (ExtensionRenderViewHostMap::iterator i = resources_.begin(); 188 i != resources_.end(); i++) { 189 if (i->first->GetSiteInstance()->GetProcess()->GetID() == 190 render_process_host_id && 191 i->first->GetRoutingID() == routing_id) 192 return i->second; 193 } 194 195 // Can happen if the page went away while a network request was being 196 // performed. 197 return NULL; 198} 199 200void ExtensionProcessResourceProvider::StartUpdating() { 201 DCHECK(!updating_); 202 updating_ = true; 203 204 // Add all the existing extension views from all Profiles, including those 205 // from incognito split mode. 206 ProfileManager* profile_manager = g_browser_process->profile_manager(); 207 std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles()); 208 size_t num_default_profiles = profiles.size(); 209 for (size_t i = 0; i < num_default_profiles; ++i) { 210 if (profiles[i]->HasOffTheRecordProfile()) { 211 profiles.push_back(profiles[i]->GetOffTheRecordProfile()); 212 } 213 } 214 215 for (size_t i = 0; i < profiles.size(); ++i) { 216 ExtensionProcessManager* process_manager = 217 extensions::ExtensionSystem::Get(profiles[i])->process_manager(); 218 if (process_manager) { 219 const ExtensionProcessManager::ViewSet all_views = 220 process_manager->GetAllViews(); 221 ExtensionProcessManager::ViewSet::const_iterator jt = all_views.begin(); 222 for (; jt != all_views.end(); ++jt) { 223 content::RenderViewHost* rvh = *jt; 224 // Don't add dead extension processes. 225 if (!rvh->IsRenderViewLive()) 226 continue; 227 228 AddToTaskManager(rvh); 229 } 230 } 231 } 232 233 // Register for notifications about extension process changes. 234 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_VIEW_REGISTERED, 235 content::NotificationService::AllBrowserContextsAndSources()); 236 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED, 237 content::NotificationService::AllBrowserContextsAndSources()); 238 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED, 239 content::NotificationService::AllBrowserContextsAndSources()); 240} 241 242void ExtensionProcessResourceProvider::StopUpdating() { 243 DCHECK(updating_); 244 updating_ = false; 245 246 // Unregister for notifications about extension process changes. 247 registrar_.Remove( 248 this, chrome::NOTIFICATION_EXTENSION_VIEW_REGISTERED, 249 content::NotificationService::AllBrowserContextsAndSources()); 250 registrar_.Remove( 251 this, chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED, 252 content::NotificationService::AllBrowserContextsAndSources()); 253 registrar_.Remove( 254 this, chrome::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED, 255 content::NotificationService::AllBrowserContextsAndSources()); 256 257 // Delete all the resources. 258 STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end()); 259 260 resources_.clear(); 261} 262 263void ExtensionProcessResourceProvider::Observe( 264 int type, 265 const content::NotificationSource& source, 266 const content::NotificationDetails& details) { 267 switch (type) { 268 case chrome::NOTIFICATION_EXTENSION_VIEW_REGISTERED: 269 AddToTaskManager( 270 content::Details<content::RenderViewHost>(details).ptr()); 271 break; 272 case chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED: 273 RemoveFromTaskManager( 274 content::Details<extensions::ExtensionHost>(details).ptr()-> 275 render_view_host()); 276 break; 277 case chrome::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED: 278 RemoveFromTaskManager( 279 content::Details<content::RenderViewHost>(details).ptr()); 280 break; 281 default: 282 NOTREACHED() << "Unexpected notification."; 283 return; 284 } 285} 286 287bool ExtensionProcessResourceProvider:: 288 IsHandledByThisProvider(content::RenderViewHost* render_view_host) { 289 WebContents* web_contents = WebContents::FromRenderViewHost(render_view_host); 290 // Don't add WebContents that belong to a guest (those are handled by 291 // GuestResourceProvider). Otherwise they will be added twice, and 292 // in this case they will have the app's name as a title (due to the 293 // ExtensionProcessResource constructor). 294 if (web_contents->GetRenderProcessHost()->IsGuest()) 295 return false; 296 extensions::ViewType view_type = extensions::GetViewType(web_contents); 297 // Don't add WebContents (those are handled by 298 // TabContentsResourceProvider) or background contents (handled 299 // by BackgroundResourceProvider). 300#if defined(USE_ASH) 301 return (view_type != extensions::VIEW_TYPE_TAB_CONTENTS && 302 view_type != extensions::VIEW_TYPE_BACKGROUND_CONTENTS); 303#else 304 return (view_type != extensions::VIEW_TYPE_TAB_CONTENTS && 305 view_type != extensions::VIEW_TYPE_BACKGROUND_CONTENTS && 306 view_type != extensions::VIEW_TYPE_PANEL); 307#endif // USE_ASH 308} 309 310void ExtensionProcessResourceProvider::AddToTaskManager( 311 content::RenderViewHost* render_view_host) { 312 if (!IsHandledByThisProvider(render_view_host)) 313 return; 314 315 ExtensionProcessResource* resource = 316 new ExtensionProcessResource(render_view_host); 317 DCHECK(resources_.find(render_view_host) == resources_.end()); 318 resources_[render_view_host] = resource; 319 task_manager_->AddResource(resource); 320} 321 322void ExtensionProcessResourceProvider::RemoveFromTaskManager( 323 content::RenderViewHost* render_view_host) { 324 if (!updating_) 325 return; 326 std::map<content::RenderViewHost*, ExtensionProcessResource*> 327 ::iterator iter = resources_.find(render_view_host); 328 if (iter == resources_.end()) 329 return; 330 331 // Remove the resource from the Task Manager. 332 ExtensionProcessResource* resource = iter->second; 333 task_manager_->RemoveResource(resource); 334 335 // Remove it from the provider. 336 resources_.erase(iter); 337 338 // Finally, delete the resource. 339 delete resource; 340} 341 342} // namespace task_manager 343