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 46namespace blink { 47 48namespace WorkerAgentState { 49static const char workerInspectionEnabled[] = "workerInspectionEnabled"; 50static const char autoconnectToWorkers[] = "autoconnectToWorkers"; 51}; 52 53class InspectorWorkerAgent::WorkerFrontendChannel FINAL : public WorkerInspectorProxy::PageInspector { 54 WTF_MAKE_FAST_ALLOCATED; 55public: 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 88private: 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 108int InspectorWorkerAgent::WorkerFrontendChannel::s_nextId = 1; 109 110PassOwnPtrWillBeRawPtr<InspectorWorkerAgent> InspectorWorkerAgent::create() 111{ 112 return adoptPtrWillBeNoop(new InspectorWorkerAgent()); 113} 114 115InspectorWorkerAgent::InspectorWorkerAgent() 116 : InspectorBaseAgent<InspectorWorkerAgent>("Worker") 117 , m_frontend(0) 118{ 119} 120 121InspectorWorkerAgent::~InspectorWorkerAgent() 122{ 123#if !ENABLE(OILPAN) 124 m_instrumentingAgents->setInspectorWorkerAgent(0); 125#endif 126} 127 128void InspectorWorkerAgent::init() 129{ 130 m_instrumentingAgents->setInspectorWorkerAgent(this); 131} 132 133void InspectorWorkerAgent::setFrontend(InspectorFrontend* frontend) 134{ 135 m_frontend = frontend->worker(); 136} 137 138void InspectorWorkerAgent::restore() 139{ 140 if (m_state->getBoolean(WorkerAgentState::workerInspectionEnabled)) 141 createWorkerFrontendChannelsForExistingWorkers(); 142} 143 144void InspectorWorkerAgent::clearFrontend() 145{ 146 m_state->setBoolean(WorkerAgentState::autoconnectToWorkers, false); 147 disable(0); 148 m_frontend = 0; 149} 150 151void InspectorWorkerAgent::enable(ErrorString*) 152{ 153 m_state->setBoolean(WorkerAgentState::workerInspectionEnabled, true); 154 if (!m_frontend) 155 return; 156 createWorkerFrontendChannelsForExistingWorkers(); 157} 158 159void InspectorWorkerAgent::disable(ErrorString*) 160{ 161 m_state->setBoolean(WorkerAgentState::workerInspectionEnabled, false); 162 if (!m_frontend) 163 return; 164 destroyWorkerFrontendChannels(); 165} 166 167void InspectorWorkerAgent::canInspectWorkers(ErrorString*, bool* result) 168{ 169 *result = true; 170} 171 172void 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 181void 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 190void 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 199void InspectorWorkerAgent::setAutoconnectToWorkers(ErrorString*, bool value) 200{ 201 m_state->setBoolean(WorkerAgentState::autoconnectToWorkers, value); 202} 203 204void 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 213bool InspectorWorkerAgent::shouldPauseDedicatedWorkerOnStart() 214{ 215 return m_state->getBoolean(WorkerAgentState::autoconnectToWorkers); 216} 217 218void 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 227void 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 240void InspectorWorkerAgent::createWorkerFrontendChannelsForExistingWorkers() 241{ 242 for (WorkerIds::iterator it = m_workerIds.begin(); it != m_workerIds.end(); ++it) 243 createWorkerFrontendChannel(it->key, it->value); 244} 245 246void 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 255void 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