1 /* 2 * Copyright (C) 2010, 2011 Apple 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 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "WebProcessProxy.h" 28 29 #include "DataReference.h" 30 #include "PluginInfoStore.h" 31 #include "PluginProcessManager.h" 32 #include "TextChecker.h" 33 #include "TextCheckerState.h" 34 #include "WebBackForwardListItem.h" 35 #include "WebContext.h" 36 #include "WebNavigationDataStore.h" 37 #include "WebPageProxy.h" 38 #include "WebProcessMessages.h" 39 #include "WebProcessProxyMessages.h" 40 #include <WebCore/KURL.h> 41 #include <wtf/text/CString.h> 42 #include <wtf/text/WTFString.h> 43 44 using namespace WebCore; 45 using namespace std; 46 47 namespace WebKit { 48 49 template<typename HashMap> 50 static inline bool isGoodKey(const typename HashMap::KeyType& key) 51 { 52 return key != HashTraits<typename HashMap::KeyType>::emptyValue() && !HashTraits<typename HashMap::KeyType>::isDeletedValue(key); 53 } 54 55 static uint64_t generatePageID() 56 { 57 static uint64_t uniquePageID = 1; 58 return uniquePageID++; 59 } 60 61 PassRefPtr<WebProcessProxy> WebProcessProxy::create(PassRefPtr<WebContext> context) 62 { 63 return adoptRef(new WebProcessProxy(context)); 64 } 65 66 WebProcessProxy::WebProcessProxy(PassRefPtr<WebContext> context) 67 : m_responsivenessTimer(this) 68 , m_context(context) 69 { 70 connect(); 71 } 72 73 WebProcessProxy::~WebProcessProxy() 74 { 75 if (m_connection) 76 m_connection->invalidate(); 77 78 for (size_t i = 0; i < m_pendingMessages.size(); ++i) 79 m_pendingMessages[i].first.releaseArguments(); 80 81 if (m_processLauncher) { 82 m_processLauncher->invalidate(); 83 m_processLauncher = 0; 84 } 85 86 if (m_threadLauncher) { 87 m_threadLauncher->invalidate(); 88 m_threadLauncher = 0; 89 } 90 } 91 92 void WebProcessProxy::connect() 93 { 94 if (m_context->processModel() == ProcessModelSharedSecondaryThread) { 95 ASSERT(!m_threadLauncher); 96 m_threadLauncher = ThreadLauncher::create(this); 97 } else { 98 ASSERT(!m_processLauncher); 99 100 ProcessLauncher::LaunchOptions launchOptions; 101 launchOptions.processType = ProcessLauncher::WebProcess; 102 103 #if PLATFORM(MAC) 104 // We want the web process to match the architecture of the UI process. 105 launchOptions.architecture = ProcessLauncher::LaunchOptions::MatchCurrentArchitecture; 106 launchOptions.executableHeap = false; 107 #endif 108 m_processLauncher = ProcessLauncher::create(this, launchOptions); 109 } 110 } 111 112 void WebProcessProxy::disconnect() 113 { 114 if (m_connection) { 115 m_connection->invalidate(); 116 m_connection = nullptr; 117 } 118 119 m_responsivenessTimer.stop(); 120 121 Vector<RefPtr<WebFrameProxy> > frames; 122 copyValuesToVector(m_frameMap, frames); 123 124 for (size_t i = 0, size = frames.size(); i < size; ++i) 125 frames[i]->disconnect(); 126 m_frameMap.clear(); 127 128 m_context->disconnectProcess(this); 129 } 130 131 bool WebProcessProxy::sendMessage(CoreIPC::MessageID messageID, PassOwnPtr<CoreIPC::ArgumentEncoder> arguments, unsigned messageSendFlags) 132 { 133 // If we're waiting for the web process to launch, we need to stash away the messages so we can send them once we have 134 // a CoreIPC connection. 135 if (isLaunching()) { 136 m_pendingMessages.append(make_pair(CoreIPC::Connection::OutgoingMessage(messageID, arguments), messageSendFlags)); 137 return true; 138 } 139 140 // If the web process has exited, m_connection will be null here. 141 if (!m_connection) 142 return false; 143 144 return m_connection->sendMessage(messageID, arguments, messageSendFlags); 145 } 146 147 bool WebProcessProxy::isLaunching() const 148 { 149 if (m_processLauncher) 150 return m_processLauncher->isLaunching(); 151 if (m_threadLauncher) 152 return m_threadLauncher->isLaunching(); 153 154 return false; 155 } 156 157 void WebProcessProxy::terminate() 158 { 159 if (m_processLauncher) 160 m_processLauncher->terminateProcess(); 161 } 162 163 WebPageProxy* WebProcessProxy::webPage(uint64_t pageID) const 164 { 165 return m_pageMap.get(pageID); 166 } 167 168 PassRefPtr<WebPageProxy> WebProcessProxy::createWebPage(PageClient* pageClient, WebContext* context, WebPageGroup* pageGroup) 169 { 170 ASSERT(context->process() == this); 171 172 unsigned pageID = generatePageID(); 173 RefPtr<WebPageProxy> webPage = WebPageProxy::create(pageClient, this, pageGroup, pageID); 174 m_pageMap.set(pageID, webPage.get()); 175 return webPage.release(); 176 } 177 178 void WebProcessProxy::addExistingWebPage(WebPageProxy* webPage, uint64_t pageID) 179 { 180 m_pageMap.set(pageID, webPage); 181 } 182 183 void WebProcessProxy::removeWebPage(uint64_t pageID) 184 { 185 m_pageMap.remove(pageID); 186 } 187 188 WebBackForwardListItem* WebProcessProxy::webBackForwardItem(uint64_t itemID) const 189 { 190 return m_backForwardListItemMap.get(itemID).get(); 191 } 192 193 void WebProcessProxy::registerNewWebBackForwardListItem(WebBackForwardListItem* item) 194 { 195 // This item was just created by the UIProcess and is being added to the map for the first time 196 // so we should not already have an item for this ID. 197 ASSERT(!m_backForwardListItemMap.contains(item->itemID())); 198 199 m_backForwardListItemMap.set(item->itemID(), item); 200 } 201 202 void WebProcessProxy::addBackForwardItem(uint64_t itemID, const String& originalURL, const String& url, const String& title, const CoreIPC::DataReference& backForwardData) 203 { 204 std::pair<WebBackForwardListItemMap::iterator, bool> result = m_backForwardListItemMap.add(itemID, 0); 205 if (result.second) { 206 // New item. 207 result.first->second = WebBackForwardListItem::create(originalURL, url, title, backForwardData.data(), backForwardData.size(), itemID); 208 return; 209 } 210 211 // Update existing item. 212 result.first->second->setOriginalURL(originalURL); 213 result.first->second->setURL(url); 214 result.first->second->setTitle(title); 215 result.first->second->setBackForwardData(backForwardData.data(), backForwardData.size()); 216 } 217 218 #if ENABLE(PLUGIN_PROCESS) 219 void WebProcessProxy::getPluginProcessConnection(const String& pluginPath, PassRefPtr<Messages::WebProcessProxy::GetPluginProcessConnection::DelayedReply> reply) 220 { 221 PluginProcessManager::shared().getPluginProcessConnection(context()->pluginInfoStore(), pluginPath, reply); 222 } 223 224 void WebProcessProxy::pluginSyncMessageSendTimedOut(const String& pluginPath) 225 { 226 PluginProcessManager::shared().pluginSyncMessageSendTimedOut(pluginPath); 227 } 228 #endif 229 230 void WebProcessProxy::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments) 231 { 232 if (messageID.is<CoreIPC::MessageClassWebProcessProxy>()) { 233 didReceiveWebProcessProxyMessage(connection, messageID, arguments); 234 return; 235 } 236 237 if (messageID.is<CoreIPC::MessageClassWebContext>() 238 || messageID.is<CoreIPC::MessageClassWebContextLegacy>() 239 || messageID.is<CoreIPC::MessageClassDownloadProxy>() 240 || messageID.is<CoreIPC::MessageClassWebApplicationCacheManagerProxy>() 241 || messageID.is<CoreIPC::MessageClassWebCookieManagerProxy>() 242 || messageID.is<CoreIPC::MessageClassWebDatabaseManagerProxy>() 243 || messageID.is<CoreIPC::MessageClassWebGeolocationManagerProxy>() 244 || messageID.is<CoreIPC::MessageClassWebIconDatabase>() 245 || messageID.is<CoreIPC::MessageClassWebKeyValueStorageManagerProxy>() 246 || messageID.is<CoreIPC::MessageClassWebMediaCacheManagerProxy>() 247 || messageID.is<CoreIPC::MessageClassWebResourceCacheManagerProxy>()) { 248 m_context->didReceiveMessage(connection, messageID, arguments); 249 return; 250 } 251 252 uint64_t pageID = arguments->destinationID(); 253 if (!pageID) 254 return; 255 256 WebPageProxy* pageProxy = webPage(pageID); 257 if (!pageProxy) 258 return; 259 260 pageProxy->didReceiveMessage(connection, messageID, arguments); 261 } 262 263 CoreIPC::SyncReplyMode WebProcessProxy::didReceiveSyncMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments, CoreIPC::ArgumentEncoder* reply) 264 { 265 if (messageID.is<CoreIPC::MessageClassWebProcessProxy>()) 266 return didReceiveSyncWebProcessProxyMessage(connection, messageID, arguments, reply); 267 268 if (messageID.is<CoreIPC::MessageClassWebContext>() || messageID.is<CoreIPC::MessageClassWebContextLegacy>() 269 || messageID.is<CoreIPC::MessageClassDownloadProxy>() || messageID.is<CoreIPC::MessageClassWebIconDatabase>()) 270 return m_context->didReceiveSyncMessage(connection, messageID, arguments, reply); 271 272 uint64_t pageID = arguments->destinationID(); 273 if (!pageID) 274 return CoreIPC::AutomaticReply; 275 276 WebPageProxy* pageProxy = webPage(pageID); 277 if (!pageProxy) 278 return CoreIPC::AutomaticReply; 279 280 pageProxy->didReceiveSyncMessage(connection, messageID, arguments, reply); 281 return CoreIPC::AutomaticReply; 282 } 283 284 void WebProcessProxy::didClose(CoreIPC::Connection*) 285 { 286 // Protect ourselves, as the call to disconnect() below may otherwise cause us 287 // to be deleted before we can finish our work. 288 RefPtr<WebProcessProxy> protect(this); 289 290 Vector<RefPtr<WebPageProxy> > pages; 291 copyValuesToVector(m_pageMap, pages); 292 293 disconnect(); 294 295 for (size_t i = 0, size = pages.size(); i < size; ++i) 296 pages[i]->processDidCrash(); 297 } 298 299 void WebProcessProxy::didReceiveInvalidMessage(CoreIPC::Connection*, CoreIPC::MessageID messageID) 300 { 301 // We received an invalid message from the web process, invalidate our connection and kill it. 302 m_connection->invalidate(); 303 304 terminate(); 305 } 306 307 void WebProcessProxy::syncMessageSendTimedOut(CoreIPC::Connection*) 308 { 309 } 310 311 void WebProcessProxy::didBecomeUnresponsive(ResponsivenessTimer*) 312 { 313 Vector<RefPtr<WebPageProxy> > pages; 314 copyValuesToVector(m_pageMap, pages); 315 for (size_t i = 0, size = pages.size(); i < size; ++i) 316 pages[i]->processDidBecomeUnresponsive(); 317 } 318 319 void WebProcessProxy::didBecomeResponsive(ResponsivenessTimer*) 320 { 321 Vector<RefPtr<WebPageProxy> > pages; 322 copyValuesToVector(m_pageMap, pages); 323 for (size_t i = 0, size = pages.size(); i < size; ++i) 324 pages[i]->processDidBecomeResponsive(); 325 } 326 327 void WebProcessProxy::didFinishLaunching(ProcessLauncher*, CoreIPC::Connection::Identifier connectionIdentifier) 328 { 329 didFinishLaunching(connectionIdentifier); 330 } 331 332 void WebProcessProxy::didFinishLaunching(ThreadLauncher*, CoreIPC::Connection::Identifier connectionIdentifier) 333 { 334 didFinishLaunching(connectionIdentifier); 335 } 336 337 void WebProcessProxy::didFinishLaunching(CoreIPC::Connection::Identifier connectionIdentifier) 338 { 339 ASSERT(!m_connection); 340 341 m_connection = CoreIPC::Connection::createServerConnection(connectionIdentifier, this, RunLoop::main()); 342 #if PLATFORM(MAC) 343 m_connection->setShouldCloseConnectionOnMachExceptions(); 344 #elif PLATFORM(QT) || PLATFORM(GTK) 345 m_connection->setShouldCloseConnectionOnProcessTermination(processIdentifier()); 346 #endif 347 348 m_connection->open(); 349 350 for (size_t i = 0; i < m_pendingMessages.size(); ++i) { 351 CoreIPC::Connection::OutgoingMessage& outgoingMessage = m_pendingMessages[i].first; 352 unsigned messageSendFlags = m_pendingMessages[i].second; 353 m_connection->sendMessage(outgoingMessage.messageID(), adoptPtr(outgoingMessage.arguments()), messageSendFlags); 354 } 355 356 m_pendingMessages.clear(); 357 358 // Tell the context that we finished launching. 359 m_context->processDidFinishLaunching(this); 360 } 361 362 WebFrameProxy* WebProcessProxy::webFrame(uint64_t frameID) const 363 { 364 return isGoodKey<WebFrameProxyMap>(frameID) ? m_frameMap.get(frameID).get() : 0; 365 } 366 367 bool WebProcessProxy::canCreateFrame(uint64_t frameID) const 368 { 369 return isGoodKey<WebFrameProxyMap>(frameID) && !m_frameMap.contains(frameID); 370 } 371 372 void WebProcessProxy::frameCreated(uint64_t frameID, WebFrameProxy* frameProxy) 373 { 374 ASSERT(canCreateFrame(frameID)); 375 m_frameMap.set(frameID, frameProxy); 376 } 377 378 void WebProcessProxy::didDestroyFrame(uint64_t frameID) 379 { 380 // If the page is closed before it has had the chance to send the DidCreateMainFrame message 381 // back to the UIProcess, then the frameDestroyed message will still be received because it 382 // gets sent directly to the WebProcessProxy. 383 ASSERT(isGoodKey<WebFrameProxyMap>(frameID)); 384 m_frameMap.remove(frameID); 385 } 386 387 void WebProcessProxy::disconnectFramesFromPage(WebPageProxy* page) 388 { 389 Vector<RefPtr<WebFrameProxy> > frames; 390 copyValuesToVector(m_frameMap, frames); 391 for (size_t i = 0, size = frames.size(); i < size; ++i) { 392 if (frames[i]->page() == page) 393 frames[i]->disconnect(); 394 } 395 } 396 397 size_t WebProcessProxy::frameCountInPage(WebPageProxy* page) const 398 { 399 size_t result = 0; 400 for (HashMap<uint64_t, RefPtr<WebFrameProxy> >::const_iterator iter = m_frameMap.begin(); iter != m_frameMap.end(); ++iter) { 401 if (iter->second->page() == page) 402 ++result; 403 } 404 return result; 405 } 406 407 void WebProcessProxy::shouldTerminate(bool& shouldTerminate) 408 { 409 if (!m_pageMap.isEmpty() || !m_context->shouldTerminate(this)) { 410 shouldTerminate = false; 411 return; 412 } 413 414 shouldTerminate = true; 415 416 // We know that the web process is going to terminate so disconnect it from the context. 417 disconnect(); 418 } 419 420 void WebProcessProxy::updateTextCheckerState() 421 { 422 if (!isValid()) 423 return; 424 425 send(Messages::WebProcess::SetTextCheckerState(TextChecker::state()), 0); 426 } 427 428 } // namespace WebKit 429