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