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