devtools_target_impl.cc revision f2477e01787aa58f445919b809d89e252beef54f
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
38class 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
57RenderViewHostTarget::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
109bool 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
120bool RenderViewHostTarget::Close() const {
121  RenderViewHost* rvh = GetRenderViewHost();
122  if (!rvh)
123    return false;
124  rvh->ClosePage();
125  return true;
126}
127
128RenderViewHost* RenderViewHostTarget::GetRenderViewHost() const {
129  return agent_host_->GetRenderViewHost();
130}
131
132int RenderViewHostTarget::GetTabId() const {
133  return tab_id_;
134}
135
136std::string RenderViewHostTarget::GetExtensionId() const {
137  return extension_id_;
138}
139
140void RenderViewHostTarget::Inspect(Profile* profile) const {
141  RenderViewHost* rvh = GetRenderViewHost();
142  if (!rvh)
143    return;
144  DevToolsWindow::OpenDevToolsWindow(rvh);
145}
146
147///////////////////////////////////////////////////////////////////////////////
148
149class 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
164WorkerTarget::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
178static void TerminateWorker(int process_id, int route_id) {
179  WorkerService::GetInstance()->TerminateWorker(process_id, route_id);
180}
181
182bool 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
188void WorkerTarget::Inspect(Profile* profile) const {
189  DevToolsWindow::OpenDevToolsWindowForWorker(profile, agent_host_.get());
190}
191
192}  // namespace
193
194DevToolsTargetImpl::~DevToolsTargetImpl() {
195}
196
197DevToolsTargetImpl::DevToolsTargetImpl() {
198}
199
200std::string DevToolsTargetImpl::GetId() const {
201  return id_;
202}
203
204std::string DevToolsTargetImpl::GetType() const {
205  return type_;
206}
207
208std::string DevToolsTargetImpl::GetTitle() const {
209  return title_;
210}
211
212std::string DevToolsTargetImpl::GetDescription() const {
213  return description_;
214}
215
216GURL DevToolsTargetImpl::GetUrl() const {
217  return url_;
218}
219
220GURL DevToolsTargetImpl::GetFaviconUrl() const {
221  return favicon_url_;
222}
223
224base::TimeTicks DevToolsTargetImpl::GetLastActivityTime() const {
225  return last_activity_time_;
226}
227
228scoped_refptr<content::DevToolsAgentHost>
229DevToolsTargetImpl::GetAgentHost() const {
230  return agent_host_;
231}
232
233bool DevToolsTargetImpl::IsAttached() const {
234  return agent_host_->IsAttached();
235}
236
237bool DevToolsTargetImpl::Activate() const {
238  return false;
239}
240
241bool DevToolsTargetImpl::Close() const {
242  return false;
243}
244
245int DevToolsTargetImpl::GetTabId() const {
246  return -1;
247}
248
249RenderViewHost* DevToolsTargetImpl::GetRenderViewHost() const {
250  return NULL;
251}
252
253std::string DevToolsTargetImpl::GetExtensionId() const {
254  return std::string();
255}
256
257void DevToolsTargetImpl::Inspect(Profile*) const {
258}
259
260void DevToolsTargetImpl::Reload() const {
261}
262
263// static
264scoped_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
270scoped_ptr<DevToolsTargetImpl> DevToolsTargetImpl::CreateForWorker(
271    const WorkerService::WorkerInfo& worker_info) {
272  return scoped_ptr<DevToolsTargetImpl>(new WorkerTarget(worker_info));
273}
274
275// static
276DevToolsTargetImpl::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
293static 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
305void 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
315static 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
326void 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