1/* 2 * Copyright (C) 2012 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 "ChildProcessProxy.h" 28 29#include <wtf/RunLoop.h> 30 31namespace WebKit { 32 33ChildProcessProxy::ChildProcessProxy() 34{ 35} 36 37ChildProcessProxy::~ChildProcessProxy() 38{ 39 if (m_connection) 40 m_connection->invalidate(); 41 42 if (m_processLauncher) { 43 m_processLauncher->invalidate(); 44 m_processLauncher = 0; 45 } 46} 47 48ChildProcessProxy* ChildProcessProxy::fromConnection(IPC::Connection* connection) 49{ 50 ASSERT(connection); 51 52 ChildProcessProxy* childProcessProxy = static_cast<ChildProcessProxy*>(connection->client()); 53 ASSERT(childProcessProxy->connection() == connection); 54 55 return childProcessProxy; 56} 57 58void ChildProcessProxy::connect() 59{ 60 ASSERT(!m_processLauncher); 61 ProcessLauncher::LaunchOptions launchOptions; 62 getLaunchOptions(launchOptions); 63 m_processLauncher = ProcessLauncher::create(this, launchOptions); 64} 65 66void ChildProcessProxy::terminate() 67{ 68#if PLATFORM(COCOA) 69 if (m_connection && m_connection->kill()) 70 return; 71#endif 72 73 // FIXME: We should really merge process launching into IPC connection creation and get rid of the process launcher. 74 if (m_processLauncher) 75 m_processLauncher->terminateProcess(); 76} 77 78ChildProcessProxy::State ChildProcessProxy::state() const 79{ 80 if (m_processLauncher && m_processLauncher->isLaunching()) 81 return ChildProcessProxy::State::Launching; 82 83 if (!m_connection) 84 return ChildProcessProxy::State::Terminated; 85 86 return ChildProcessProxy::State::Running; 87} 88 89bool ChildProcessProxy::sendMessage(std::unique_ptr<IPC::MessageEncoder> encoder, unsigned messageSendFlags) 90{ 91 switch (state()) { 92 case State::Launching: 93 // If we're waiting for the child process to launch, we need to stash away the messages so we can send them once we have a connection. 94 m_pendingMessages.append(std::make_pair(WTF::move(encoder), messageSendFlags)); 95 return true; 96 97 case State::Running: 98 return connection()->sendMessage(WTF::move(encoder), messageSendFlags); 99 100 case State::Terminated: 101 return false; 102 } 103 104 return false; 105} 106 107void ChildProcessProxy::addMessageReceiver(IPC::StringReference messageReceiverName, IPC::MessageReceiver& messageReceiver) 108{ 109 m_messageReceiverMap.addMessageReceiver(messageReceiverName, messageReceiver); 110} 111 112void ChildProcessProxy::addMessageReceiver(IPC::StringReference messageReceiverName, uint64_t destinationID, IPC::MessageReceiver& messageReceiver) 113{ 114 m_messageReceiverMap.addMessageReceiver(messageReceiverName, destinationID, messageReceiver); 115} 116 117void ChildProcessProxy::removeMessageReceiver(IPC::StringReference messageReceiverName, uint64_t destinationID) 118{ 119 m_messageReceiverMap.removeMessageReceiver(messageReceiverName, destinationID); 120} 121 122bool ChildProcessProxy::dispatchMessage(IPC::Connection* connection, IPC::MessageDecoder& decoder) 123{ 124 return m_messageReceiverMap.dispatchMessage(connection, decoder); 125} 126 127bool ChildProcessProxy::dispatchSyncMessage(IPC::Connection* connection, IPC::MessageDecoder& decoder, std::unique_ptr<IPC::MessageEncoder>& replyEncoder) 128{ 129 return m_messageReceiverMap.dispatchSyncMessage(connection, decoder, replyEncoder); 130} 131 132void ChildProcessProxy::didFinishLaunching(ProcessLauncher*, IPC::Connection::Identifier connectionIdentifier) 133{ 134 ASSERT(!m_connection); 135 136 m_connection = IPC::Connection::createServerConnection(connectionIdentifier, this, RunLoop::main()); 137#if PLATFORM(MAC) 138 m_connection->setShouldCloseConnectionOnMachExceptions(); 139#endif 140 141 connectionWillOpen(m_connection.get()); 142 m_connection->open(); 143 144 for (size_t i = 0; i < m_pendingMessages.size(); ++i) { 145 std::unique_ptr<IPC::MessageEncoder> message = WTF::move(m_pendingMessages[i].first); 146 unsigned messageSendFlags = m_pendingMessages[i].second; 147 m_connection->sendMessage(WTF::move(message), messageSendFlags); 148 } 149 150 m_pendingMessages.clear(); 151} 152 153void ChildProcessProxy::abortProcessLaunchIfNeeded() 154{ 155 if (state() != State::Launching) 156 return; 157 158 m_processLauncher->invalidate(); 159 m_processLauncher = nullptr; 160} 161 162void ChildProcessProxy::clearConnection() 163{ 164 if (!m_connection) 165 return; 166 167 connectionWillClose(m_connection.get()); 168 169 m_connection->invalidate(); 170 m_connection = nullptr; 171} 172 173void ChildProcessProxy::connectionWillOpen(IPC::Connection*) 174{ 175} 176 177void ChildProcessProxy::connectionWillClose(IPC::Connection*) 178{ 179} 180 181} // namespace WebKit 182