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