devtools_target_impl.cc revision 010d83a9304c5a91596085d917d248abff47903a
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/profiles/profile.h"
13#include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
14#include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
15#include "chrome/common/extensions/extension_constants.h"
16#include "content/public/browser/browser_thread.h"
17#include "content/public/browser/favicon_status.h"
18#include "content/public/browser/navigation_entry.h"
19#include "content/public/browser/render_frame_host.h"
20#include "content/public/browser/render_view_host.h"
21#include "content/public/browser/web_contents.h"
22#include "extensions/browser/extension_host.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
39// RenderViewHostTarget --------------------------------------------------------
40
41class RenderViewHostTarget : public DevToolsTargetImpl {
42 public:
43  explicit RenderViewHostTarget(RenderViewHost* rvh, bool is_tab);
44
45  // DevToolsTargetImpl overrides:
46  virtual bool Activate() const OVERRIDE;
47  virtual bool Close() const OVERRIDE;
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    : DevToolsTargetImpl(DevToolsAgentHost::GetOrCreateFor(rvh)),
60      tab_id_(-1) {
61  set_type(kTargetTypeOther);
62  WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
63  if (!web_contents)
64    return;  // Orphan RVH will show up with no title/url/icon in clients.
65
66  content::RenderFrameHost* rfh = rvh->GetMainFrame();
67  if (rfh->IsCrossProcessSubframe()) {
68    set_url(rfh->GetLastCommittedURL());
69    set_type(kTargetTypeOther);
70    // TODO(kaznacheev) Try setting the title when the frame navigation
71    // refactoring is done.
72    return;
73  }
74
75  set_title(base::UTF16ToUTF8(web_contents->GetTitle()));
76  set_url(web_contents->GetURL());
77  content::NavigationController& controller = web_contents->GetController();
78  content::NavigationEntry* entry = controller.GetActiveEntry();
79  if (entry != NULL && entry->GetURL().is_valid())
80    set_favicon_url(entry->GetFavicon().url);
81  set_last_activity_time(web_contents->GetLastActiveTime());
82
83  if (is_tab) {
84    set_type(kTargetTypePage);
85    tab_id_ = extensions::ExtensionTabUtil::GetTabId(web_contents);
86  } else {
87    Profile* profile =
88        Profile::FromBrowserContext(web_contents->GetBrowserContext());
89    if (profile) {
90      ExtensionService* extension_service = profile->GetExtensionService();
91      const extensions::Extension* extension = extension_service->
92          extensions()->GetByID(GetURL().host());
93      if (extension) {
94        set_title(extension->name());
95        extensions::ExtensionHost* extension_host =
96            extensions::ExtensionSystem::Get(profile)->process_manager()->
97                GetBackgroundHostForExtension(extension->id());
98        if (extension_host &&
99            extension_host->host_contents() == web_contents) {
100          set_type(kTargetTypeBackgroundPage);
101          extension_id_ = extension->id();
102        } else if (extension->is_hosted_app()
103            || extension->is_legacy_packaged_app()
104            || extension->is_platform_app()) {
105          set_type(kTargetTypeApp);
106        }
107        set_favicon_url(extensions::ExtensionIconSource::GetIconURL(
108            extension, extension_misc::EXTENSION_ICON_SMALLISH,
109            ExtensionIconSet::MATCH_BIGGER, false, NULL));
110      }
111    }
112  }
113}
114
115bool RenderViewHostTarget::Activate() const {
116  RenderViewHost* rvh = GetRenderViewHost();
117  if (!rvh)
118    return false;
119  WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
120  if (!web_contents)
121    return false;
122  web_contents->GetDelegate()->ActivateContents(web_contents);
123  return true;
124}
125
126bool RenderViewHostTarget::Close() const {
127  RenderViewHost* rvh = GetRenderViewHost();
128  if (!rvh)
129    return false;
130  rvh->ClosePage();
131  return true;
132}
133
134RenderViewHost* RenderViewHostTarget::GetRenderViewHost() const {
135  return GetAgentHost()->GetRenderViewHost();
136}
137
138int RenderViewHostTarget::GetTabId() const {
139  return tab_id_;
140}
141
142std::string RenderViewHostTarget::GetExtensionId() const {
143  return extension_id_;
144}
145
146void RenderViewHostTarget::Inspect(Profile* profile) const {
147  RenderViewHost* rvh = GetRenderViewHost();
148  if (!rvh)
149    return;
150  DevToolsWindow::OpenDevToolsWindow(rvh);
151}
152
153// WorkerTarget ----------------------------------------------------------------
154
155class WorkerTarget : public DevToolsTargetImpl {
156 public:
157  explicit WorkerTarget(const WorkerService::WorkerInfo& worker_info);
158
159  // content::DevToolsTarget overrides:
160  virtual bool Close() const OVERRIDE;
161
162  // DevToolsTargetImpl overrides:
163  virtual void Inspect(Profile* profile) const OVERRIDE;
164
165 private:
166  int process_id_;
167  int route_id_;
168};
169
170WorkerTarget::WorkerTarget(const WorkerService::WorkerInfo& worker)
171    : DevToolsTargetImpl(DevToolsAgentHost::GetForWorker(worker.process_id,
172                                                         worker.route_id)) {
173  set_type(kTargetTypeWorker);
174  set_title(base::UTF16ToUTF8(worker.name));
175  set_description(base::StringPrintf("Worker pid:%d",
176                      base::GetProcId(worker.handle)));
177  set_url(worker.url);
178
179  process_id_ = worker.process_id;
180  route_id_ = worker.route_id;
181}
182
183static void TerminateWorker(int process_id, int route_id) {
184  WorkerService::GetInstance()->TerminateWorker(process_id, route_id);
185}
186
187bool WorkerTarget::Close() const {
188  content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
189      base::Bind(&TerminateWorker, process_id_, route_id_));
190  return true;
191}
192
193void WorkerTarget::Inspect(Profile* profile) const {
194  DevToolsWindow::OpenDevToolsWindowForWorker(profile, GetAgentHost());
195}
196
197}  // namespace
198
199// DevToolsTargetImpl ----------------------------------------------------------
200
201DevToolsTargetImpl::~DevToolsTargetImpl() {
202}
203
204DevToolsTargetImpl::DevToolsTargetImpl(DevToolsAgentHost* agent_host)
205    : agent_host_(agent_host) {
206}
207
208std::string DevToolsTargetImpl::GetId() const {
209  return agent_host_->GetId();
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
278DevToolsTargetImpl::List DevToolsTargetImpl::EnumerateRenderViewHostTargets() {
279  std::set<RenderViewHost*> tab_rvhs;
280  for (TabContentsIterator it; !it.done(); it.Next())
281    tab_rvhs.insert(it->GetRenderViewHost());
282
283  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
284  DevToolsTargetImpl::List result;
285  std::vector<RenderViewHost*> rvh_list =
286      content::DevToolsAgentHost::GetValidRenderViewHosts();
287  for (std::vector<RenderViewHost*>::iterator it = rvh_list.begin();
288       it != rvh_list.end(); ++it) {
289    bool is_tab = tab_rvhs.find(*it) != tab_rvhs.end();
290    result.push_back(new RenderViewHostTarget(*it, is_tab));
291  }
292  return result;
293}
294
295static void CreateWorkerTargets(
296    const std::vector<WorkerService::WorkerInfo>& worker_info,
297    DevToolsTargetImpl::Callback callback) {
298  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
299  DevToolsTargetImpl::List result;
300  for (size_t i = 0; i < worker_info.size(); ++i) {
301    result.push_back(new WorkerTarget(worker_info[i]));
302  }
303  callback.Run(result);
304}
305
306// static
307void DevToolsTargetImpl::EnumerateWorkerTargets(Callback callback) {
308  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
309  content::BrowserThread::PostTask(
310      content::BrowserThread::UI,
311      FROM_HERE,
312      base::Bind(&CreateWorkerTargets,
313                 WorkerService::GetInstance()->GetWorkers(),
314                 callback));
315}
316
317static void CollectAllTargets(
318    DevToolsTargetImpl::Callback callback,
319    const DevToolsTargetImpl::List& worker_targets) {
320  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
321  DevToolsTargetImpl::List result =
322      DevToolsTargetImpl::EnumerateRenderViewHostTargets();
323  result.insert(result.begin(), worker_targets.begin(), worker_targets.end());
324  callback.Run(result);
325}
326
327// static
328void DevToolsTargetImpl::EnumerateAllTargets(Callback callback) {
329  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
330  content::BrowserThread::PostTask(
331      content::BrowserThread::IO,
332      FROM_HERE,
333      base::Bind(&DevToolsTargetImpl::EnumerateWorkerTargets,
334                 base::Bind(&CollectAllTargets, callback)));
335}
336