Home | History | Annotate | Download | only in devtools
      1 // Copyright 2014 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 "content/browser/devtools/embedded_worker_devtools_agent_host.h"
      6 
      7 #include "base/strings/utf_string_conversions.h"
      8 #include "content/browser/devtools/devtools_protocol.h"
      9 #include "content/browser/devtools/devtools_protocol_constants.h"
     10 #include "content/browser/service_worker/service_worker_context_core.h"
     11 #include "content/browser/service_worker/service_worker_version.h"
     12 #include "content/browser/shared_worker/shared_worker_service_impl.h"
     13 #include "content/common/devtools_messages.h"
     14 #include "content/public/browser/browser_thread.h"
     15 #include "content/public/browser/render_process_host.h"
     16 
     17 namespace content {
     18 
     19 namespace {
     20 
     21 void TerminateSharedWorkerOnIO(
     22     EmbeddedWorkerDevToolsAgentHost::WorkerId worker_id) {
     23   SharedWorkerServiceImpl::GetInstance()->TerminateWorker(
     24       worker_id.first, worker_id.second);
     25 }
     26 
     27 void StatusNoOp(ServiceWorkerStatusCode status) {
     28 }
     29 
     30 void TerminateServiceWorkerOnIO(
     31     base::WeakPtr<ServiceWorkerContextCore> context_weak,
     32     int64 version_id) {
     33   if (ServiceWorkerContextCore* context = context_weak.get()) {
     34     if (ServiceWorkerVersion* version = context->GetLiveVersion(version_id))
     35       version->StopWorker(base::Bind(&StatusNoOp));
     36   }
     37 }
     38 
     39 }
     40 
     41 EmbeddedWorkerDevToolsAgentHost::EmbeddedWorkerDevToolsAgentHost(
     42     WorkerId worker_id,
     43     const SharedWorkerInstance& shared_worker)
     44     : shared_worker_(new SharedWorkerInstance(shared_worker)),
     45       state_(WORKER_UNINSPECTED),
     46       worker_id_(worker_id) {
     47   WorkerCreated();
     48 }
     49 
     50 EmbeddedWorkerDevToolsAgentHost::EmbeddedWorkerDevToolsAgentHost(
     51     WorkerId worker_id,
     52     const ServiceWorkerIdentifier& service_worker,
     53     bool debug_service_worker_on_start)
     54     : service_worker_(new ServiceWorkerIdentifier(service_worker)),
     55       state_(WORKER_UNINSPECTED),
     56       worker_id_(worker_id) {
     57   if (debug_service_worker_on_start)
     58     state_ = WORKER_PAUSED_FOR_DEBUG_ON_START;
     59   WorkerCreated();
     60 }
     61 
     62 bool EmbeddedWorkerDevToolsAgentHost::IsWorker() const {
     63   return true;
     64 }
     65 
     66 DevToolsAgentHost::Type EmbeddedWorkerDevToolsAgentHost::GetType() {
     67   return shared_worker_ ? TYPE_SHARED_WORKER : TYPE_SERVICE_WORKER;
     68 }
     69 
     70 std::string EmbeddedWorkerDevToolsAgentHost::GetTitle() {
     71   if (shared_worker_ && shared_worker_->name().length())
     72     return base::UTF16ToUTF8(shared_worker_->name());
     73   if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first)) {
     74     return base::StringPrintf("Worker pid:%d",
     75                               base::GetProcId(host->GetHandle()));
     76   }
     77   return "";
     78 }
     79 
     80 GURL EmbeddedWorkerDevToolsAgentHost::GetURL() {
     81   if (shared_worker_)
     82     return shared_worker_->url();
     83   if (service_worker_)
     84     return service_worker_->url();
     85   return GURL();
     86 }
     87 
     88 bool EmbeddedWorkerDevToolsAgentHost::Activate() {
     89   return false;
     90 }
     91 
     92 bool EmbeddedWorkerDevToolsAgentHost::Close() {
     93   if (shared_worker_) {
     94     BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
     95         base::Bind(&TerminateSharedWorkerOnIO, worker_id_));
     96     return true;
     97   }
     98   if (service_worker_) {
     99     BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
    100         base::Bind(&TerminateServiceWorkerOnIO,
    101                    service_worker_->context_weak(),
    102                    service_worker_->version_id()));
    103     return true;
    104   }
    105   return false;
    106 }
    107 
    108 void EmbeddedWorkerDevToolsAgentHost::SendMessageToAgent(
    109     IPC::Message* message_raw) {
    110   scoped_ptr<IPC::Message> message(message_raw);
    111   if (state_ != WORKER_INSPECTED)
    112     return;
    113   if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first)) {
    114     message->set_routing_id(worker_id_.second);
    115     host->Send(message.release());
    116   }
    117 }
    118 
    119 void EmbeddedWorkerDevToolsAgentHost::Attach() {
    120   if (state_ != WORKER_INSPECTED) {
    121     state_ = WORKER_INSPECTED;
    122     AttachToWorker();
    123   }
    124   IPCDevToolsAgentHost::Attach();
    125 }
    126 
    127 void EmbeddedWorkerDevToolsAgentHost::OnClientDetached() {
    128   if (state_ == WORKER_INSPECTED) {
    129     state_ = WORKER_UNINSPECTED;
    130     DetachFromWorker();
    131   } else if (state_ == WORKER_PAUSED_FOR_REATTACH) {
    132     state_ = WORKER_UNINSPECTED;
    133   }
    134 }
    135 
    136 bool EmbeddedWorkerDevToolsAgentHost::OnMessageReceived(
    137     const IPC::Message& msg) {
    138   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    139   bool handled = true;
    140   IPC_BEGIN_MESSAGE_MAP(EmbeddedWorkerDevToolsAgentHost, msg)
    141   IPC_MESSAGE_HANDLER(DevToolsClientMsg_DispatchOnInspectorFrontend,
    142                       OnDispatchOnInspectorFrontend)
    143   IPC_MESSAGE_HANDLER(DevToolsHostMsg_SaveAgentRuntimeState,
    144                       OnSaveAgentRuntimeState)
    145   IPC_MESSAGE_UNHANDLED(handled = false)
    146   IPC_END_MESSAGE_MAP()
    147   return handled;
    148 }
    149 
    150 void EmbeddedWorkerDevToolsAgentHost::WorkerReadyForInspection() {
    151   if (state_ == WORKER_PAUSED_FOR_DEBUG_ON_START) {
    152     RenderProcessHost* rph = RenderProcessHost::FromID(worker_id_.first);
    153     Inspect(rph->GetBrowserContext());
    154   } else if (state_ == WORKER_PAUSED_FOR_REATTACH) {
    155     DCHECK(IsAttached());
    156     state_ = WORKER_INSPECTED;
    157     AttachToWorker();
    158     Reattach(saved_agent_state_);
    159   }
    160 }
    161 
    162 void EmbeddedWorkerDevToolsAgentHost::WorkerContextStarted() {
    163 }
    164 
    165 void EmbeddedWorkerDevToolsAgentHost::WorkerRestarted(WorkerId worker_id) {
    166   DCHECK_EQ(WORKER_TERMINATED, state_);
    167   state_ = IsAttached() ? WORKER_PAUSED_FOR_REATTACH : WORKER_UNINSPECTED;
    168   worker_id_ = worker_id;
    169   WorkerCreated();
    170 }
    171 
    172 void EmbeddedWorkerDevToolsAgentHost::WorkerDestroyed() {
    173   DCHECK_NE(WORKER_TERMINATED, state_);
    174   if (state_ == WORKER_INSPECTED) {
    175     DCHECK(IsAttached());
    176     // Client host is debugging this worker agent host.
    177     std::string notification =
    178         DevToolsProtocol::CreateNotification(
    179             devtools::Worker::disconnectedFromWorker::kName, NULL)->Serialize();
    180     SendMessageToClient(notification);
    181     DetachFromWorker();
    182   }
    183   state_ = WORKER_TERMINATED;
    184   Release();  // Balanced in WorkerCreated()
    185 }
    186 
    187 bool EmbeddedWorkerDevToolsAgentHost::Matches(
    188     const SharedWorkerInstance& other) {
    189   return shared_worker_ && shared_worker_->Matches(other);
    190 }
    191 
    192 bool EmbeddedWorkerDevToolsAgentHost::Matches(
    193     const ServiceWorkerIdentifier& other) {
    194   return service_worker_ && service_worker_->Matches(other);
    195 }
    196 
    197 bool EmbeddedWorkerDevToolsAgentHost::IsTerminated() {
    198   return state_ == WORKER_TERMINATED;
    199 }
    200 
    201 EmbeddedWorkerDevToolsAgentHost::~EmbeddedWorkerDevToolsAgentHost() {
    202   DCHECK_EQ(WORKER_TERMINATED, state_);
    203   EmbeddedWorkerDevToolsManager::GetInstance()->RemoveInspectedWorkerData(
    204       worker_id_);
    205 }
    206 
    207 void EmbeddedWorkerDevToolsAgentHost::AttachToWorker() {
    208   if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first))
    209     host->AddRoute(worker_id_.second, this);
    210 }
    211 
    212 void EmbeddedWorkerDevToolsAgentHost::DetachFromWorker() {
    213   if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first))
    214     host->RemoveRoute(worker_id_.second);
    215 }
    216 
    217 void EmbeddedWorkerDevToolsAgentHost::WorkerCreated() {
    218   AddRef();  // Balanced in WorkerDestroyed()
    219 }
    220 
    221 void EmbeddedWorkerDevToolsAgentHost::OnDispatchOnInspectorFrontend(
    222     const std::string& message) {
    223   SendMessageToClient(message);
    224 }
    225 
    226 void EmbeddedWorkerDevToolsAgentHost::OnSaveAgentRuntimeState(
    227     const std::string& state) {
    228   saved_agent_state_ = state;
    229 }
    230 
    231 }  // namespace content
    232