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
RenderViewHostTarget(RenderViewHost * rvh,bool is_tab)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
Activate() const109 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
Close() const120 bool RenderViewHostTarget::Close() const {
121 RenderViewHost* rvh = GetRenderViewHost();
122 if (!rvh)
123 return false;
124 rvh->ClosePage();
125 return true;
126 }
127
GetRenderViewHost() const128 RenderViewHost* RenderViewHostTarget::GetRenderViewHost() const {
129 return agent_host_->GetRenderViewHost();
130 }
131
GetTabId() const132 int RenderViewHostTarget::GetTabId() const {
133 return tab_id_;
134 }
135
GetExtensionId() const136 std::string RenderViewHostTarget::GetExtensionId() const {
137 return extension_id_;
138 }
139
Inspect(Profile * profile) const140 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
WorkerTarget(const WorkerService::WorkerInfo & worker)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
TerminateWorker(int process_id,int route_id)178 static void TerminateWorker(int process_id, int route_id) {
179 WorkerService::GetInstance()->TerminateWorker(process_id, route_id);
180 }
181
Close() const182 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
Inspect(Profile * profile) const188 void WorkerTarget::Inspect(Profile* profile) const {
189 DevToolsWindow::OpenDevToolsWindowForWorker(profile, agent_host_.get());
190 }
191
192 } // namespace
193
~DevToolsTargetImpl()194 DevToolsTargetImpl::~DevToolsTargetImpl() {
195 }
196
DevToolsTargetImpl()197 DevToolsTargetImpl::DevToolsTargetImpl() {
198 }
199
GetId() const200 std::string DevToolsTargetImpl::GetId() const {
201 return id_;
202 }
203
GetType() const204 std::string DevToolsTargetImpl::GetType() const {
205 return type_;
206 }
207
GetTitle() const208 std::string DevToolsTargetImpl::GetTitle() const {
209 return title_;
210 }
211
GetDescription() const212 std::string DevToolsTargetImpl::GetDescription() const {
213 return description_;
214 }
215
GetUrl() const216 GURL DevToolsTargetImpl::GetUrl() const {
217 return url_;
218 }
219
GetFaviconUrl() const220 GURL DevToolsTargetImpl::GetFaviconUrl() const {
221 return favicon_url_;
222 }
223
GetLastActivityTime() const224 base::TimeTicks DevToolsTargetImpl::GetLastActivityTime() const {
225 return last_activity_time_;
226 }
227
228 scoped_refptr<content::DevToolsAgentHost>
GetAgentHost() const229 DevToolsTargetImpl::GetAgentHost() const {
230 return agent_host_;
231 }
232
IsAttached() const233 bool DevToolsTargetImpl::IsAttached() const {
234 return agent_host_->IsAttached();
235 }
236
Activate() const237 bool DevToolsTargetImpl::Activate() const {
238 return false;
239 }
240
Close() const241 bool DevToolsTargetImpl::Close() const {
242 return false;
243 }
244
GetTabId() const245 int DevToolsTargetImpl::GetTabId() const {
246 return -1;
247 }
248
GetRenderViewHost() const249 RenderViewHost* DevToolsTargetImpl::GetRenderViewHost() const {
250 return NULL;
251 }
252
GetExtensionId() const253 std::string DevToolsTargetImpl::GetExtensionId() const {
254 return std::string();
255 }
256
Inspect(Profile *) const257 void DevToolsTargetImpl::Inspect(Profile*) const {
258 }
259
Reload() const260 void DevToolsTargetImpl::Reload() const {
261 }
262
263 // static
CreateForRenderViewHost(content::RenderViewHost * rvh,bool is_tab)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
CreateForWorker(const WorkerService::WorkerInfo & worker_info)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
EnumerateRenderViewHostTargets()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
CreateWorkerTargets(const std::vector<WorkerService::WorkerInfo> & worker_info,DevToolsTargetImpl::Callback callback)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
EnumerateWorkerTargets(Callback callback)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
CollectAllTargets(DevToolsTargetImpl::Callback callback,const DevToolsTargetImpl::List & worker_targets)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
EnumerateAllTargets(Callback callback)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