devtools_target_impl.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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_tab_util.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_view_host.h"
21#include "content/public/browser/web_contents.h"
22#include "extensions/browser/extension_system.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_ = base::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->GetLastActiveTime();
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        extensions::ExtensionHost* extension_host =
88            extensions::ExtensionSystem::Get(profile)->process_manager()->
89                GetBackgroundHostForExtension(extension->id());
90        if (extension_host &&
91            extension_host->host_contents() == web_contents) {
92          type_ = kTargetTypeBackgroundPage;
93          extension_id_ = extension->id();
94        } else if (extension->is_hosted_app()
95            || extension->is_legacy_packaged_app()
96            || extension->is_platform_app()) {
97          type_ = kTargetTypeApp;
98        }
99        favicon_url_ = extensions::ExtensionIconSource::GetIconURL(
100            extension, extension_misc::EXTENSION_ICON_SMALLISH,
101            ExtensionIconSet::MATCH_BIGGER, false, NULL);
102      }
103    }
104  }
105}
106
107bool RenderViewHostTarget::Activate() const {
108  RenderViewHost* rvh = GetRenderViewHost();
109  if (!rvh)
110    return false;
111  WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
112  if (!web_contents)
113    return false;
114  web_contents->GetDelegate()->ActivateContents(web_contents);
115  return true;
116}
117
118bool RenderViewHostTarget::Close() const {
119  RenderViewHost* rvh = GetRenderViewHost();
120  if (!rvh)
121    return false;
122  rvh->ClosePage();
123  return true;
124}
125
126RenderViewHost* RenderViewHostTarget::GetRenderViewHost() const {
127  return agent_host_->GetRenderViewHost();
128}
129
130int RenderViewHostTarget::GetTabId() const {
131  return tab_id_;
132}
133
134std::string RenderViewHostTarget::GetExtensionId() const {
135  return extension_id_;
136}
137
138void RenderViewHostTarget::Inspect(Profile* profile) const {
139  RenderViewHost* rvh = GetRenderViewHost();
140  if (!rvh)
141    return;
142  DevToolsWindow::OpenDevToolsWindow(rvh);
143}
144
145///////////////////////////////////////////////////////////////////////////////
146
147class WorkerTarget : public DevToolsTargetImpl {
148 public:
149  explicit WorkerTarget(const WorkerService::WorkerInfo& worker_info);
150
151  // content::DevToolsTarget overrides:
152  virtual bool Close() const OVERRIDE;
153
154  // DevToolsTargetImpl overrides:
155  virtual void Inspect(Profile* profile) const OVERRIDE;
156
157 private:
158  int process_id_;
159  int route_id_;
160};
161
162WorkerTarget::WorkerTarget(const WorkerService::WorkerInfo& worker) {
163  agent_host_ =
164      DevToolsAgentHost::GetForWorker(worker.process_id, worker.route_id);
165  id_ = agent_host_->GetId();
166  type_ = kTargetTypeWorker;
167  title_ = base::UTF16ToUTF8(worker.name);
168  description_ =
169      base::StringPrintf("Worker pid:%d", base::GetProcId(worker.handle));
170  url_ = worker.url;
171
172  process_id_ = worker.process_id;
173  route_id_ = worker.route_id;
174}
175
176static void TerminateWorker(int process_id, int route_id) {
177  WorkerService::GetInstance()->TerminateWorker(process_id, route_id);
178}
179
180bool WorkerTarget::Close() const {
181  content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
182      base::Bind(&TerminateWorker, process_id_, route_id_));
183  return true;
184}
185
186void WorkerTarget::Inspect(Profile* profile) const {
187  DevToolsWindow::OpenDevToolsWindowForWorker(profile, agent_host_.get());
188}
189
190}  // namespace
191
192DevToolsTargetImpl::~DevToolsTargetImpl() {
193}
194
195DevToolsTargetImpl::DevToolsTargetImpl() {
196}
197
198std::string DevToolsTargetImpl::GetId() const {
199  return id_;
200}
201
202std::string DevToolsTargetImpl::GetType() const {
203  return type_;
204}
205
206std::string DevToolsTargetImpl::GetTitle() const {
207  return title_;
208}
209
210std::string DevToolsTargetImpl::GetDescription() const {
211  return description_;
212}
213
214GURL DevToolsTargetImpl::GetUrl() const {
215  return url_;
216}
217
218GURL DevToolsTargetImpl::GetFaviconUrl() const {
219  return favicon_url_;
220}
221
222base::TimeTicks DevToolsTargetImpl::GetLastActivityTime() const {
223  return last_activity_time_;
224}
225
226scoped_refptr<content::DevToolsAgentHost>
227DevToolsTargetImpl::GetAgentHost() const {
228  return agent_host_;
229}
230
231bool DevToolsTargetImpl::IsAttached() const {
232  return agent_host_->IsAttached();
233}
234
235bool DevToolsTargetImpl::Activate() const {
236  return false;
237}
238
239bool DevToolsTargetImpl::Close() const {
240  return false;
241}
242
243int DevToolsTargetImpl::GetTabId() const {
244  return -1;
245}
246
247RenderViewHost* DevToolsTargetImpl::GetRenderViewHost() const {
248  return NULL;
249}
250
251std::string DevToolsTargetImpl::GetExtensionId() const {
252  return std::string();
253}
254
255void DevToolsTargetImpl::Inspect(Profile*) const {
256}
257
258void DevToolsTargetImpl::Reload() const {
259}
260
261// static
262scoped_ptr<DevToolsTargetImpl> DevToolsTargetImpl::CreateForRenderViewHost(
263    content::RenderViewHost* rvh, bool is_tab) {
264  return scoped_ptr<DevToolsTargetImpl>(new RenderViewHostTarget(rvh, is_tab));
265}
266
267// static
268scoped_ptr<DevToolsTargetImpl> DevToolsTargetImpl::CreateForWorker(
269    const WorkerService::WorkerInfo& worker_info) {
270  return scoped_ptr<DevToolsTargetImpl>(new WorkerTarget(worker_info));
271}
272
273// static
274DevToolsTargetImpl::List DevToolsTargetImpl::EnumerateRenderViewHostTargets() {
275  std::set<RenderViewHost*> tab_rvhs;
276  for (TabContentsIterator it; !it.done(); it.Next())
277    tab_rvhs.insert(it->GetRenderViewHost());
278
279  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
280  DevToolsTargetImpl::List result;
281  std::vector<RenderViewHost*> rvh_list =
282      content::DevToolsAgentHost::GetValidRenderViewHosts();
283  for (std::vector<RenderViewHost*>::iterator it = rvh_list.begin();
284       it != rvh_list.end(); ++it) {
285    bool is_tab = tab_rvhs.find(*it) != tab_rvhs.end();
286    result.push_back(new RenderViewHostTarget(*it, is_tab));
287  }
288  return result;
289}
290
291static void CreateWorkerTargets(
292    const std::vector<WorkerService::WorkerInfo>& worker_info,
293    DevToolsTargetImpl::Callback callback) {
294  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
295  DevToolsTargetImpl::List result;
296  for (size_t i = 0; i < worker_info.size(); ++i) {
297    result.push_back(new WorkerTarget(worker_info[i]));
298  }
299  callback.Run(result);
300}
301
302// static
303void DevToolsTargetImpl::EnumerateWorkerTargets(Callback callback) {
304  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
305  content::BrowserThread::PostTask(
306      content::BrowserThread::UI,
307      FROM_HERE,
308      base::Bind(&CreateWorkerTargets,
309                 WorkerService::GetInstance()->GetWorkers(),
310                 callback));
311}
312
313static void CollectAllTargets(
314    DevToolsTargetImpl::Callback callback,
315    const DevToolsTargetImpl::List& worker_targets) {
316  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
317  DevToolsTargetImpl::List result =
318      DevToolsTargetImpl::EnumerateRenderViewHostTargets();
319  result.insert(result.begin(), worker_targets.begin(), worker_targets.end());
320  callback.Run(result);
321}
322
323// static
324void DevToolsTargetImpl::EnumerateAllTargets(Callback callback) {
325  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
326  content::BrowserThread::PostTask(
327      content::BrowserThread::IO,
328      FROM_HERE,
329      base::Bind(&DevToolsTargetImpl::EnumerateWorkerTargets,
330                 base::Bind(&CollectAllTargets, callback)));
331}
332