devtools_target_impl.cc revision 46d4c2bc3267f3f028f39e7e311b0f89aba2e4fd
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
27using content::BrowserThread;
28using content::DevToolsAgentHost;
29using content::RenderViewHost;
30using content::WebContents;
31using content::WorkerService;
32
33namespace {
34
35const char kTargetTypeApp[] = "app";
36const char kTargetTypeBackgroundPage[] = "background_page";
37const char kTargetTypePage[] = "page";
38const char kTargetTypeWorker[] = "worker";
39const char kTargetTypeWebView[] = "webview";
40const char kTargetTypeIFrame[] = "iframe";
41const char kTargetTypeOther[] = "other";
42
43// RenderViewHostTarget --------------------------------------------------------
44
45class 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
62RenderViewHostTarget::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  if (guest) {
91    set_type(kTargetTypeWebView);
92    RenderViewHost* parent_rvh =
93        guest->embedder_web_contents()->GetRenderViewHost();
94    set_parent_id(DevToolsAgentHost::GetOrCreateFor(parent_rvh)->GetId());
95    return;
96  }
97
98  if (is_tab) {
99    set_type(kTargetTypePage);
100    tab_id_ = extensions::ExtensionTabUtil::GetTabId(web_contents);
101  } else {
102    Profile* profile =
103        Profile::FromBrowserContext(web_contents->GetBrowserContext());
104    if (profile) {
105      ExtensionService* extension_service = profile->GetExtensionService();
106      const extensions::Extension* extension = extension_service->
107          extensions()->GetByID(GetURL().host());
108      if (extension) {
109        set_title(extension->name());
110        extensions::ExtensionHost* extension_host =
111            extensions::ExtensionSystem::Get(profile)->process_manager()->
112                GetBackgroundHostForExtension(extension->id());
113        if (extension_host &&
114            extension_host->host_contents() == web_contents) {
115          set_type(kTargetTypeBackgroundPage);
116          extension_id_ = extension->id();
117        } else if (extension->is_hosted_app()
118            || extension->is_legacy_packaged_app()
119            || extension->is_platform_app()) {
120          set_type(kTargetTypeApp);
121        }
122        set_favicon_url(extensions::ExtensionIconSource::GetIconURL(
123            extension, extension_misc::EXTENSION_ICON_SMALLISH,
124            ExtensionIconSet::MATCH_BIGGER, false, NULL));
125      }
126    }
127  }
128}
129
130bool RenderViewHostTarget::Activate() const {
131  RenderViewHost* rvh = GetRenderViewHost();
132  if (!rvh)
133    return false;
134  WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
135  if (!web_contents)
136    return false;
137  web_contents->GetDelegate()->ActivateContents(web_contents);
138  return true;
139}
140
141bool RenderViewHostTarget::Close() const {
142  RenderViewHost* rvh = GetRenderViewHost();
143  if (!rvh)
144    return false;
145  rvh->ClosePage();
146  return true;
147}
148
149RenderViewHost* RenderViewHostTarget::GetRenderViewHost() const {
150  return GetAgentHost()->GetRenderViewHost();
151}
152
153int RenderViewHostTarget::GetTabId() const {
154  return tab_id_;
155}
156
157std::string RenderViewHostTarget::GetExtensionId() const {
158  return extension_id_;
159}
160
161void RenderViewHostTarget::Inspect(Profile* profile) const {
162  RenderViewHost* rvh = GetRenderViewHost();
163  if (!rvh)
164    return;
165  DevToolsWindow::OpenDevToolsWindow(rvh);
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
277RenderViewHost* DevToolsTargetImpl::GetRenderViewHost() const {
278  return NULL;
279}
280
281std::string DevToolsTargetImpl::GetExtensionId() const {
282  return std::string();
283}
284
285void DevToolsTargetImpl::Inspect(Profile*) const {
286}
287
288void DevToolsTargetImpl::Reload() const {
289}
290
291// static
292scoped_ptr<DevToolsTargetImpl> DevToolsTargetImpl::CreateForRenderViewHost(
293    content::RenderViewHost* rvh, bool is_tab) {
294  return scoped_ptr<DevToolsTargetImpl>(new RenderViewHostTarget(rvh, is_tab));
295}
296
297// static
298DevToolsTargetImpl::List DevToolsTargetImpl::EnumerateRenderViewHostTargets() {
299  std::set<RenderViewHost*> tab_rvhs;
300  for (TabContentsIterator it; !it.done(); it.Next())
301    tab_rvhs.insert(it->GetRenderViewHost());
302
303  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
304  DevToolsTargetImpl::List result;
305  std::vector<RenderViewHost*> rvh_list =
306      content::DevToolsAgentHost::GetValidRenderViewHosts();
307  for (std::vector<RenderViewHost*>::iterator it = rvh_list.begin();
308       it != rvh_list.end(); ++it) {
309    bool is_tab = tab_rvhs.find(*it) != tab_rvhs.end();
310    result.push_back(new RenderViewHostTarget(*it, is_tab));
311  }
312  return result;
313}
314
315static void CreateWorkerTargets(
316    const std::vector<WorkerService::WorkerInfo>& worker_info,
317    DevToolsTargetImpl::Callback callback) {
318  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
319  DevToolsTargetImpl::List result;
320  for (size_t i = 0; i < worker_info.size(); ++i) {
321    result.push_back(new WorkerTarget(worker_info[i]));
322  }
323  callback.Run(result);
324}
325
326// static
327void DevToolsTargetImpl::EnumerateWorkerTargets(Callback callback) {
328  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
329  content::BrowserThread::PostTask(
330      content::BrowserThread::UI,
331      FROM_HERE,
332      base::Bind(&CreateWorkerTargets,
333                 WorkerService::GetInstance()->GetWorkers(),
334                 callback));
335}
336
337static void CollectAllTargets(
338    DevToolsTargetImpl::Callback callback,
339    const DevToolsTargetImpl::List& worker_targets) {
340  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
341  DevToolsTargetImpl::List result =
342      DevToolsTargetImpl::EnumerateRenderViewHostTargets();
343  result.insert(result.begin(), worker_targets.begin(), worker_targets.end());
344  callback.Run(result);
345}
346
347// static
348void DevToolsTargetImpl::EnumerateAllTargets(Callback callback) {
349  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
350  content::BrowserThread::PostTask(
351      content::BrowserThread::IO,
352      FROM_HERE,
353      base::Bind(&DevToolsTargetImpl::EnumerateWorkerTargets,
354                 base::Bind(&CollectAllTargets, callback)));
355}
356