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