Home | History | Annotate | Download | only in inspector
      1 /*
      2  * Copyright (C) 2011 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 
     33 #include "core/inspector/InspectorWorkerAgent.h"
     34 
     35 #include "core/InspectorFrontend.h"
     36 #include "core/inspector/InspectorState.h"
     37 #include "core/inspector/InstrumentingAgents.h"
     38 #include "core/inspector/JSONParser.h"
     39 #include "core/workers/WorkerInspectorProxy.h"
     40 #include "platform/JSONValues.h"
     41 #include "platform/weborigin/KURL.h"
     42 #include "wtf/PassOwnPtr.h"
     43 #include "wtf/RefPtr.h"
     44 #include "wtf/text/WTFString.h"
     45 
     46 namespace blink {
     47 
     48 namespace WorkerAgentState {
     49 static const char workerInspectionEnabled[] = "workerInspectionEnabled";
     50 static const char autoconnectToWorkers[] = "autoconnectToWorkers";
     51 };
     52 
     53 class InspectorWorkerAgent::WorkerFrontendChannel FINAL : public WorkerInspectorProxy::PageInspector {
     54     WTF_MAKE_FAST_ALLOCATED;
     55 public:
     56     explicit WorkerFrontendChannel(InspectorFrontend::Worker* frontend, WorkerInspectorProxy* proxy)
     57         : m_frontend(frontend)
     58         , m_proxy(proxy)
     59         , m_id(s_nextId++)
     60         , m_connected(false)
     61     {
     62         ASSERT(!proxy->pageInspector());
     63     }
     64     virtual ~WorkerFrontendChannel()
     65     {
     66         disconnectFromWorker();
     67     }
     68 
     69     int id() const { return m_id; }
     70     WorkerInspectorProxy* proxy() const { return m_proxy; }
     71 
     72     void connectToWorker()
     73     {
     74         if (m_connected)
     75             return;
     76         m_connected = true;
     77         m_proxy->connectToInspector(this);
     78     }
     79 
     80     void disconnectFromWorker()
     81     {
     82         if (!m_connected)
     83             return;
     84         m_connected = false;
     85         m_proxy->disconnectFromInspector();
     86     }
     87 
     88 private:
     89     // WorkerInspectorProxy::PageInspector implementation
     90     virtual void dispatchMessageFromWorker(const String& message) OVERRIDE
     91     {
     92         RefPtr<JSONValue> value = parseJSON(message);
     93         if (!value)
     94             return;
     95         RefPtr<JSONObject> messageObject = value->asObject();
     96         if (!messageObject)
     97             return;
     98         m_frontend->dispatchMessageFromWorker(m_id, messageObject);
     99     }
    100 
    101     InspectorFrontend::Worker* m_frontend;
    102     WorkerInspectorProxy* m_proxy;
    103     int m_id;
    104     bool m_connected;
    105     static int s_nextId;
    106 };
    107 
    108 int InspectorWorkerAgent::WorkerFrontendChannel::s_nextId = 1;
    109 
    110 PassOwnPtrWillBeRawPtr<InspectorWorkerAgent> InspectorWorkerAgent::create()
    111 {
    112     return adoptPtrWillBeNoop(new InspectorWorkerAgent());
    113 }
    114 
    115 InspectorWorkerAgent::InspectorWorkerAgent()
    116     : InspectorBaseAgent<InspectorWorkerAgent>("Worker")
    117     , m_frontend(0)
    118 {
    119 }
    120 
    121 InspectorWorkerAgent::~InspectorWorkerAgent()
    122 {
    123 #if !ENABLE(OILPAN)
    124     m_instrumentingAgents->setInspectorWorkerAgent(0);
    125 #endif
    126 }
    127 
    128 void InspectorWorkerAgent::init()
    129 {
    130     m_instrumentingAgents->setInspectorWorkerAgent(this);
    131 }
    132 
    133 void InspectorWorkerAgent::setFrontend(InspectorFrontend* frontend)
    134 {
    135     m_frontend = frontend->worker();
    136 }
    137 
    138 void InspectorWorkerAgent::restore()
    139 {
    140     if (m_state->getBoolean(WorkerAgentState::workerInspectionEnabled))
    141         createWorkerFrontendChannelsForExistingWorkers();
    142 }
    143 
    144 void InspectorWorkerAgent::clearFrontend()
    145 {
    146     m_state->setBoolean(WorkerAgentState::autoconnectToWorkers, false);
    147     disable(0);
    148     m_frontend = 0;
    149 }
    150 
    151 void InspectorWorkerAgent::enable(ErrorString*)
    152 {
    153     m_state->setBoolean(WorkerAgentState::workerInspectionEnabled, true);
    154     if (!m_frontend)
    155         return;
    156     createWorkerFrontendChannelsForExistingWorkers();
    157 }
    158 
    159 void InspectorWorkerAgent::disable(ErrorString*)
    160 {
    161     m_state->setBoolean(WorkerAgentState::workerInspectionEnabled, false);
    162     if (!m_frontend)
    163         return;
    164     destroyWorkerFrontendChannels();
    165 }
    166 
    167 void InspectorWorkerAgent::canInspectWorkers(ErrorString*, bool* result)
    168 {
    169     *result = true;
    170 }
    171 
    172 void InspectorWorkerAgent::connectToWorker(ErrorString* error, int workerId)
    173 {
    174     WorkerFrontendChannel* channel = m_idToChannel.get(workerId);
    175     if (channel)
    176         channel->connectToWorker();
    177     else
    178         *error = "Worker is gone";
    179 }
    180 
    181 void InspectorWorkerAgent::disconnectFromWorker(ErrorString* error, int workerId)
    182 {
    183     WorkerFrontendChannel* channel = m_idToChannel.get(workerId);
    184     if (channel)
    185         channel->disconnectFromWorker();
    186     else
    187         *error = "Worker is gone";
    188 }
    189 
    190 void InspectorWorkerAgent::sendMessageToWorker(ErrorString* error, int workerId, const RefPtr<JSONObject>& message)
    191 {
    192     WorkerFrontendChannel* channel = m_idToChannel.get(workerId);
    193     if (channel)
    194         channel->proxy()->sendMessageToInspector(message->toJSONString());
    195     else
    196         *error = "Worker is gone";
    197 }
    198 
    199 void InspectorWorkerAgent::setAutoconnectToWorkers(ErrorString*, bool value)
    200 {
    201     m_state->setBoolean(WorkerAgentState::autoconnectToWorkers, value);
    202 }
    203 
    204 void InspectorWorkerAgent::setTracingSessionId(const String& sessionId)
    205 {
    206     m_tracingSessionId = sessionId;
    207     if (sessionId.isEmpty())
    208         return;
    209     for (WorkerIds::iterator it = m_workerIds.begin(); it != m_workerIds.end(); ++it)
    210         it->key->writeTimelineStartedEvent(sessionId);
    211 }
    212 
    213 bool InspectorWorkerAgent::shouldPauseDedicatedWorkerOnStart()
    214 {
    215     return m_state->getBoolean(WorkerAgentState::autoconnectToWorkers);
    216 }
    217 
    218 void InspectorWorkerAgent::didStartWorker(WorkerInspectorProxy* workerInspectorProxy, const KURL& url)
    219 {
    220     m_workerIds.set(workerInspectorProxy, url.string());
    221     if (m_frontend && m_state->getBoolean(WorkerAgentState::workerInspectionEnabled))
    222         createWorkerFrontendChannel(workerInspectorProxy, url.string());
    223     if (!m_tracingSessionId.isEmpty())
    224         workerInspectorProxy->writeTimelineStartedEvent(m_tracingSessionId);
    225 }
    226 
    227 void InspectorWorkerAgent::workerTerminated(WorkerInspectorProxy* proxy)
    228 {
    229     m_workerIds.remove(proxy);
    230     for (WorkerChannels::iterator it = m_idToChannel.begin(); it != m_idToChannel.end(); ++it) {
    231         if (proxy == it->value->proxy()) {
    232             m_frontend->workerTerminated(it->key);
    233             delete it->value;
    234             m_idToChannel.remove(it);
    235             return;
    236         }
    237     }
    238 }
    239 
    240 void InspectorWorkerAgent::createWorkerFrontendChannelsForExistingWorkers()
    241 {
    242     for (WorkerIds::iterator it = m_workerIds.begin(); it != m_workerIds.end(); ++it)
    243         createWorkerFrontendChannel(it->key, it->value);
    244 }
    245 
    246 void InspectorWorkerAgent::destroyWorkerFrontendChannels()
    247 {
    248     for (WorkerChannels::iterator it = m_idToChannel.begin(); it != m_idToChannel.end(); ++it) {
    249         it->value->disconnectFromWorker();
    250         delete it->value;
    251     }
    252     m_idToChannel.clear();
    253 }
    254 
    255 void InspectorWorkerAgent::createWorkerFrontendChannel(WorkerInspectorProxy* workerInspectorProxy, const String& url)
    256 {
    257     WorkerFrontendChannel* channel = new WorkerFrontendChannel(m_frontend, workerInspectorProxy);
    258     m_idToChannel.set(channel->id(), channel);
    259 
    260     ASSERT(m_frontend);
    261     bool autoconnectToWorkers = m_state->getBoolean(WorkerAgentState::autoconnectToWorkers);
    262     if (autoconnectToWorkers)
    263         channel->connectToWorker();
    264     m_frontend->workerCreated(channel->id(), url, autoconnectToWorkers);
    265 }
    266 
    267 } // namespace blink
    268