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