devtools_target_impl.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
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
24using content::BrowserThread;
25using content::DevToolsAgentHost;
26using content::RenderViewHost;
27using content::WebContents;
28using content::WorkerService;
29
30namespace {
31
32const char kTargetTypeApp[] = "app";
33const char kTargetTypeBackgroundPage[] = "background_page";
34const char kTargetTypePage[] = "page";
35const char kTargetTypeWorker[] = "worker";
36const char kTargetTypeOther[] = "other";
37
38std::string GetExtensionName(WebContents* web_contents) {
39  Profile* profile =
40      Profile::FromBrowserContext(web_contents->GetBrowserContext());
41  if (!profile)
42    return std::string();
43
44  extensions::ExtensionHost* extension_host =
45      extensions::ExtensionSystem::Get(profile)->process_manager()->
46          GetBackgroundHostForExtension(web_contents->GetURL().host());
47
48  if (!extension_host || extension_host->host_contents() != web_contents)
49    return std::string();
50
51  return extension_host->extension()->name();
52}
53
54class RenderViewHostTarget : public DevToolsTargetImpl {
55 public:
56  explicit RenderViewHostTarget(RenderViewHost* rvh, bool is_tab);
57
58  // content::DevToolsTarget overrides:
59  virtual bool Activate() const OVERRIDE;
60  virtual bool Close() const OVERRIDE;
61
62  // DevToolsTargetImpl overrides:
63  virtual RenderViewHost* GetRenderViewHost() const OVERRIDE;
64  virtual int GetTabId() const OVERRIDE;
65  virtual std::string GetExtensionId() const OVERRIDE;
66  virtual void Inspect(Profile* profile) const OVERRIDE;
67
68 private:
69  int tab_id_;
70  std::string extension_id_;
71};
72
73RenderViewHostTarget::RenderViewHostTarget(RenderViewHost* rvh, bool is_tab) {
74  agent_host_ = DevToolsAgentHost::GetOrCreateFor(rvh);
75  id_ = agent_host_->GetId();
76  type_ = kTargetTypeOther;
77  tab_id_ = -1;
78
79  WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
80  if (!web_contents)
81    return;  // Orphan RVH will show up with no title/url/icon in clients.
82
83  title_ = UTF16ToUTF8(web_contents->GetTitle());
84  url_ = web_contents->GetURL();
85  content::NavigationController& controller = web_contents->GetController();
86  content::NavigationEntry* entry = controller.GetActiveEntry();
87  if (entry != NULL && entry->GetURL().is_valid())
88    favicon_url_ = entry->GetFavicon().url;
89  last_activity_time_ = web_contents->GetLastSelectedTime();
90
91  if (is_tab) {
92    type_ = kTargetTypePage;
93    tab_id_ = ExtensionTabUtil::GetTabId(web_contents);
94  } else {
95    Profile* profile =
96        Profile::FromBrowserContext(web_contents->GetBrowserContext());
97    if (profile) {
98      ExtensionService* extension_service = profile->GetExtensionService();
99      const extensions::Extension* extension = extension_service->
100          extensions()->GetByID(url_.host());
101      if (extension) {
102        title_ = extension->name();
103        if (extension->is_hosted_app()
104            || extension->is_legacy_packaged_app()
105            || extension->is_platform_app()) {
106          type_ = kTargetTypeApp;
107        } else {
108          extensions::ExtensionHost* extension_host =
109              extensions::ExtensionSystem::Get(profile)->process_manager()->
110                  GetBackgroundHostForExtension(extension->id());
111          if (extension_host &&
112              extension_host->host_contents() == web_contents) {
113            type_ = kTargetTypeBackgroundPage;
114            extension_id_ = extension->id();
115          }
116        }
117        favicon_url_ = extensions::ExtensionIconSource::GetIconURL(
118            extension, extension_misc::EXTENSION_ICON_SMALLISH,
119            ExtensionIconSet::MATCH_BIGGER, false, NULL);
120      }
121    }
122
123    std::string extension_name = GetExtensionName(web_contents);
124    if (!extension_name.empty()) {
125      type_ = kTargetTypeBackgroundPage;
126      title_ = extension_name;
127    }
128  }
129}
130
131bool 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
142bool RenderViewHostTarget::Close() const {
143  RenderViewHost* rvh = GetRenderViewHost();
144  if (!rvh)
145    return false;
146  rvh->ClosePage();
147  return true;
148}
149
150RenderViewHost* RenderViewHostTarget::GetRenderViewHost() const {
151  return agent_host_->GetRenderViewHost();
152}
153
154int RenderViewHostTarget::GetTabId() const {
155  return tab_id_;
156}
157
158std::string RenderViewHostTarget::GetExtensionId() const {
159  return extension_id_;
160}
161
162void RenderViewHostTarget::Inspect(Profile* profile) const {
163  RenderViewHost* rvh = GetRenderViewHost();
164  if (!rvh)
165    return;
166  DevToolsWindow::OpenDevToolsWindow(rvh);
167}
168
169///////////////////////////////////////////////////////////////////////////////
170
171class 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
186WorkerTarget::WorkerTarget(const WorkerService::WorkerInfo& worker) {
187  agent_host_ =
188      DevToolsAgentHost::GetForWorker(worker.process_id, worker.route_id);
189  id_ = agent_host_->GetId();
190  type_ = kTargetTypeWorker;
191  title_ = UTF16ToUTF8(worker.name);
192  description_ =
193      base::StringPrintf("Worker pid:%d", base::GetProcId(worker.handle));
194  url_ = worker.url;
195
196  process_id_ = worker.process_id;
197  route_id_ = worker.route_id;
198}
199
200static void TerminateWorker(int process_id, int route_id) {
201  WorkerService::GetInstance()->TerminateWorker(process_id, route_id);
202}
203
204bool WorkerTarget::Close() const {
205  content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
206      base::Bind(&TerminateWorker, process_id_, route_id_));
207  return true;
208}
209
210void WorkerTarget::Inspect(Profile* profile) const {
211  DevToolsWindow::OpenDevToolsWindowForWorker(profile, agent_host_.get());
212}
213
214}  // namespace
215
216DevToolsTargetImpl::~DevToolsTargetImpl() {
217}
218
219DevToolsTargetImpl::DevToolsTargetImpl() {
220}
221
222std::string DevToolsTargetImpl::GetId() const {
223  return id_;
224}
225
226std::string DevToolsTargetImpl::GetType() const {
227  return type_;
228}
229
230std::string DevToolsTargetImpl::GetTitle() const {
231  return title_;
232}
233
234std::string DevToolsTargetImpl::GetDescription() const {
235  return description_;
236}
237
238GURL DevToolsTargetImpl::GetUrl() const {
239  return url_;
240}
241
242GURL DevToolsTargetImpl::GetFaviconUrl() const {
243  return favicon_url_;
244}
245
246base::TimeTicks DevToolsTargetImpl::GetLastActivityTime() const {
247  return last_activity_time_;
248}
249
250scoped_refptr<content::DevToolsAgentHost>
251DevToolsTargetImpl::GetAgentHost() const {
252  return agent_host_;
253}
254
255bool DevToolsTargetImpl::IsAttached() const {
256  return agent_host_->IsAttached();
257}
258
259bool DevToolsTargetImpl::Activate() const {
260  return false;
261}
262
263bool DevToolsTargetImpl::Close() const {
264  return false;
265}
266
267int DevToolsTargetImpl::GetTabId() const {
268  return -1;
269}
270
271RenderViewHost* DevToolsTargetImpl::GetRenderViewHost() const {
272  return NULL;
273}
274
275std::string DevToolsTargetImpl::GetExtensionId() const {
276  return std::string();
277}
278
279void DevToolsTargetImpl::Inspect(Profile*) const {
280}
281
282void DevToolsTargetImpl::Reload() const {
283}
284
285// static
286scoped_ptr<DevToolsTargetImpl> DevToolsTargetImpl::CreateForRenderViewHost(
287    content::RenderViewHost* rvh, bool is_tab) {
288  return scoped_ptr<DevToolsTargetImpl>(new RenderViewHostTarget(rvh, is_tab));
289}
290
291// static
292scoped_ptr<DevToolsTargetImpl> DevToolsTargetImpl::CreateForWorker(
293    const WorkerService::WorkerInfo& worker_info) {
294  return scoped_ptr<DevToolsTargetImpl>(new WorkerTarget(worker_info));
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