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