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/devtools/devtools_target_impl.h" 6 7 #include "base/strings/stringprintf.h" 8 #include "base/strings/utf_string_conversions.h" 9 #include "chrome/browser/devtools/devtools_window.h" 10 #include "chrome/browser/extensions/extension_host.h" 11 #include "chrome/browser/extensions/extension_service.h" 12 #include "chrome/browser/extensions/extension_system.h" 13 #include "chrome/browser/extensions/extension_tab_util.h" 14 #include "chrome/browser/profiles/profile.h" 15 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h" 16 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h" 17 #include "chrome/common/extensions/extension_constants.h" 18 #include "content/public/browser/browser_thread.h" 19 #include "content/public/browser/favicon_status.h" 20 #include "content/public/browser/navigation_entry.h" 21 #include "content/public/browser/render_view_host.h" 22 #include "content/public/browser/web_contents.h" 23 24 using content::BrowserThread; 25 using content::DevToolsAgentHost; 26 using content::RenderViewHost; 27 using content::WebContents; 28 using content::WorkerService; 29 30 namespace { 31 32 const char kTargetTypeApp[] = "app"; 33 const char kTargetTypeBackgroundPage[] = "background_page"; 34 const char kTargetTypePage[] = "page"; 35 const char kTargetTypeWorker[] = "worker"; 36 const char kTargetTypeOther[] = "other"; 37 38 class RenderViewHostTarget : public DevToolsTargetImpl { 39 public: 40 explicit RenderViewHostTarget(RenderViewHost* rvh, bool is_tab); 41 42 // content::DevToolsTarget overrides: 43 virtual bool Activate() const OVERRIDE; 44 virtual bool Close() const OVERRIDE; 45 46 // DevToolsTargetImpl overrides: 47 virtual RenderViewHost* GetRenderViewHost() const OVERRIDE; 48 virtual int GetTabId() const OVERRIDE; 49 virtual std::string GetExtensionId() const OVERRIDE; 50 virtual void Inspect(Profile* profile) const OVERRIDE; 51 52 private: 53 int tab_id_; 54 std::string extension_id_; 55 }; 56 57 RenderViewHostTarget::RenderViewHostTarget(RenderViewHost* rvh, bool is_tab) { 58 agent_host_ = DevToolsAgentHost::GetOrCreateFor(rvh); 59 id_ = agent_host_->GetId(); 60 type_ = kTargetTypeOther; 61 tab_id_ = -1; 62 63 WebContents* web_contents = WebContents::FromRenderViewHost(rvh); 64 if (!web_contents) 65 return; // Orphan RVH will show up with no title/url/icon in clients. 66 67 title_ = UTF16ToUTF8(web_contents->GetTitle()); 68 url_ = web_contents->GetURL(); 69 content::NavigationController& controller = web_contents->GetController(); 70 content::NavigationEntry* entry = controller.GetActiveEntry(); 71 if (entry != NULL && entry->GetURL().is_valid()) 72 favicon_url_ = entry->GetFavicon().url; 73 last_activity_time_ = web_contents->GetLastSelectedTime(); 74 75 if (is_tab) { 76 type_ = kTargetTypePage; 77 tab_id_ = extensions::ExtensionTabUtil::GetTabId(web_contents); 78 } else { 79 Profile* profile = 80 Profile::FromBrowserContext(web_contents->GetBrowserContext()); 81 if (profile) { 82 ExtensionService* extension_service = profile->GetExtensionService(); 83 const extensions::Extension* extension = extension_service-> 84 extensions()->GetByID(url_.host()); 85 if (extension) { 86 title_ = extension->name(); 87 if (extension->is_hosted_app() 88 || extension->is_legacy_packaged_app() 89 || extension->is_platform_app()) { 90 type_ = kTargetTypeApp; 91 } else { 92 extensions::ExtensionHost* extension_host = 93 extensions::ExtensionSystem::Get(profile)->process_manager()-> 94 GetBackgroundHostForExtension(extension->id()); 95 if (extension_host && 96 extension_host->host_contents() == web_contents) { 97 type_ = kTargetTypeBackgroundPage; 98 extension_id_ = extension->id(); 99 } 100 } 101 favicon_url_ = extensions::ExtensionIconSource::GetIconURL( 102 extension, extension_misc::EXTENSION_ICON_SMALLISH, 103 ExtensionIconSet::MATCH_BIGGER, false, NULL); 104 } 105 } 106 } 107 } 108 109 bool RenderViewHostTarget::Activate() const { 110 RenderViewHost* rvh = GetRenderViewHost(); 111 if (!rvh) 112 return false; 113 WebContents* web_contents = WebContents::FromRenderViewHost(rvh); 114 if (!web_contents) 115 return false; 116 web_contents->GetDelegate()->ActivateContents(web_contents); 117 return true; 118 } 119 120 bool RenderViewHostTarget::Close() const { 121 RenderViewHost* rvh = GetRenderViewHost(); 122 if (!rvh) 123 return false; 124 rvh->ClosePage(); 125 return true; 126 } 127 128 RenderViewHost* RenderViewHostTarget::GetRenderViewHost() const { 129 return agent_host_->GetRenderViewHost(); 130 } 131 132 int RenderViewHostTarget::GetTabId() const { 133 return tab_id_; 134 } 135 136 std::string RenderViewHostTarget::GetExtensionId() const { 137 return extension_id_; 138 } 139 140 void RenderViewHostTarget::Inspect(Profile* profile) const { 141 RenderViewHost* rvh = GetRenderViewHost(); 142 if (!rvh) 143 return; 144 DevToolsWindow::OpenDevToolsWindow(rvh); 145 } 146 147 /////////////////////////////////////////////////////////////////////////////// 148 149 class WorkerTarget : public DevToolsTargetImpl { 150 public: 151 explicit WorkerTarget(const WorkerService::WorkerInfo& worker_info); 152 153 // content::DevToolsTarget overrides: 154 virtual bool Close() const OVERRIDE; 155 156 // DevToolsTargetImpl overrides: 157 virtual void Inspect(Profile* profile) const OVERRIDE; 158 159 private: 160 int process_id_; 161 int route_id_; 162 }; 163 164 WorkerTarget::WorkerTarget(const WorkerService::WorkerInfo& worker) { 165 agent_host_ = 166 DevToolsAgentHost::GetForWorker(worker.process_id, worker.route_id); 167 id_ = agent_host_->GetId(); 168 type_ = kTargetTypeWorker; 169 title_ = UTF16ToUTF8(worker.name); 170 description_ = 171 base::StringPrintf("Worker pid:%d", base::GetProcId(worker.handle)); 172 url_ = worker.url; 173 174 process_id_ = worker.process_id; 175 route_id_ = worker.route_id; 176 } 177 178 static void TerminateWorker(int process_id, int route_id) { 179 WorkerService::GetInstance()->TerminateWorker(process_id, route_id); 180 } 181 182 bool WorkerTarget::Close() const { 183 content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, 184 base::Bind(&TerminateWorker, process_id_, route_id_)); 185 return true; 186 } 187 188 void WorkerTarget::Inspect(Profile* profile) const { 189 DevToolsWindow::OpenDevToolsWindowForWorker(profile, agent_host_.get()); 190 } 191 192 } // namespace 193 194 DevToolsTargetImpl::~DevToolsTargetImpl() { 195 } 196 197 DevToolsTargetImpl::DevToolsTargetImpl() { 198 } 199 200 std::string DevToolsTargetImpl::GetId() const { 201 return id_; 202 } 203 204 std::string DevToolsTargetImpl::GetType() const { 205 return type_; 206 } 207 208 std::string DevToolsTargetImpl::GetTitle() const { 209 return title_; 210 } 211 212 std::string DevToolsTargetImpl::GetDescription() const { 213 return description_; 214 } 215 216 GURL DevToolsTargetImpl::GetUrl() const { 217 return url_; 218 } 219 220 GURL DevToolsTargetImpl::GetFaviconUrl() const { 221 return favicon_url_; 222 } 223 224 base::TimeTicks DevToolsTargetImpl::GetLastActivityTime() const { 225 return last_activity_time_; 226 } 227 228 scoped_refptr<content::DevToolsAgentHost> 229 DevToolsTargetImpl::GetAgentHost() const { 230 return agent_host_; 231 } 232 233 bool DevToolsTargetImpl::IsAttached() const { 234 return agent_host_->IsAttached(); 235 } 236 237 bool DevToolsTargetImpl::Activate() const { 238 return false; 239 } 240 241 bool DevToolsTargetImpl::Close() const { 242 return false; 243 } 244 245 int DevToolsTargetImpl::GetTabId() const { 246 return -1; 247 } 248 249 RenderViewHost* DevToolsTargetImpl::GetRenderViewHost() const { 250 return NULL; 251 } 252 253 std::string DevToolsTargetImpl::GetExtensionId() const { 254 return std::string(); 255 } 256 257 void DevToolsTargetImpl::Inspect(Profile*) const { 258 } 259 260 void DevToolsTargetImpl::Reload() const { 261 } 262 263 // static 264 scoped_ptr<DevToolsTargetImpl> DevToolsTargetImpl::CreateForRenderViewHost( 265 content::RenderViewHost* rvh, bool is_tab) { 266 return scoped_ptr<DevToolsTargetImpl>(new RenderViewHostTarget(rvh, is_tab)); 267 } 268 269 // static 270 scoped_ptr<DevToolsTargetImpl> DevToolsTargetImpl::CreateForWorker( 271 const WorkerService::WorkerInfo& worker_info) { 272 return scoped_ptr<DevToolsTargetImpl>(new WorkerTarget(worker_info)); 273 } 274 275 // static 276 DevToolsTargetImpl::List DevToolsTargetImpl::EnumerateRenderViewHostTargets() { 277 std::set<RenderViewHost*> tab_rvhs; 278 for (TabContentsIterator it; !it.done(); it.Next()) 279 tab_rvhs.insert(it->GetRenderViewHost()); 280 281 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 282 DevToolsTargetImpl::List result; 283 std::vector<RenderViewHost*> rvh_list = 284 content::DevToolsAgentHost::GetValidRenderViewHosts(); 285 for (std::vector<RenderViewHost*>::iterator it = rvh_list.begin(); 286 it != rvh_list.end(); ++it) { 287 bool is_tab = tab_rvhs.find(*it) != tab_rvhs.end(); 288 result.push_back(new RenderViewHostTarget(*it, is_tab)); 289 } 290 return result; 291 } 292 293 static void CreateWorkerTargets( 294 const std::vector<WorkerService::WorkerInfo>& worker_info, 295 DevToolsTargetImpl::Callback callback) { 296 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 297 DevToolsTargetImpl::List result; 298 for (size_t i = 0; i < worker_info.size(); ++i) { 299 result.push_back(new WorkerTarget(worker_info[i])); 300 } 301 callback.Run(result); 302 } 303 304 // static 305 void DevToolsTargetImpl::EnumerateWorkerTargets(Callback callback) { 306 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 307 content::BrowserThread::PostTask( 308 content::BrowserThread::UI, 309 FROM_HERE, 310 base::Bind(&CreateWorkerTargets, 311 WorkerService::GetInstance()->GetWorkers(), 312 callback)); 313 } 314 315 static void CollectAllTargets( 316 DevToolsTargetImpl::Callback callback, 317 const DevToolsTargetImpl::List& worker_targets) { 318 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 319 DevToolsTargetImpl::List result = 320 DevToolsTargetImpl::EnumerateRenderViewHostTargets(); 321 result.insert(result.begin(), worker_targets.begin(), worker_targets.end()); 322 callback.Run(result); 323 } 324 325 // static 326 void DevToolsTargetImpl::EnumerateAllTargets(Callback callback) { 327 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 328 content::BrowserThread::PostTask( 329 content::BrowserThread::IO, 330 FROM_HERE, 331 base::Bind(&DevToolsTargetImpl::EnumerateWorkerTargets, 332 base::Bind(&CollectAllTargets, callback))); 333 } 334