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