1/* 2 * Copyright (C) 2010, 2011, 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#import "config.h" 27 28#import "ChildProcessEntryPoint.h" 29#import "EnvironmentUtilities.h" 30#import "EnvironmentVariables.h" 31#import "StringUtilities.h" 32#import "WKBase.h" 33#import "WebProcess.h" 34#import <mach/mach_error.h> 35#import <servers/bootstrap.h> 36#import <spawn.h> 37#import <stdio.h> 38#import <wtf/RetainPtr.h> 39#import <wtf/RunLoop.h> 40#import <wtf/text/CString.h> 41#import <wtf/text/WTFString.h> 42 43#if PLATFORM(IOS) 44#import <GraphicsServices/GraphicsServices.h> 45#import <WebCore/WebCoreThreadSystemInterface.h> 46#endif // PLATFORM(IOS) 47 48#if USE(APPKIT) 49@interface NSApplication (WebNSApplicationDetails) 50-(void)_installAutoreleasePoolsOnCurrentThreadIfNecessary; 51@end 52#endif 53 54extern "C" kern_return_t bootstrap_register2(mach_port_t, name_t, mach_port_t, uint64_t); 55 56using namespace WebCore; 57 58namespace WebKit { 59 60class WebContentProcessMainDelegate : public ChildProcessMainDelegate { 61public: 62 WebContentProcessMainDelegate(const CommandLine& commandLine) 63 : ChildProcessMainDelegate(commandLine) 64 { 65 } 66 67 virtual void doPreInitializationWork() 68 { 69 // Remove the WebProcess and SecItem shims from the DYLD_INSERT_LIBRARIES environment variable so any processes 70 // spawned by the WebProcess don't try to insert the shims and crash. 71 EnvironmentUtilities::stripValuesEndingWithString("DYLD_INSERT_LIBRARIES", "/WebProcessShim.dylib"); 72 EnvironmentUtilities::stripValuesEndingWithString("DYLD_INSERT_LIBRARIES", "/SecItemShim.dylib"); 73 74#if USE(APPKIT) 75 // Initialize AppKit. 76 [NSApplication sharedApplication]; 77 78 // Installs autorelease pools on the current runloop which prevents memory from accumulating between user events. 79 // FIXME: Remove when <rdar://problem/8929426> is fixed. 80 [NSApp _installAutoreleasePoolsOnCurrentThreadIfNecessary]; 81#endif 82 83#if PLATFORM(IOS) 84 GSInitialize(); 85 InitWebCoreThreadSystemInterface(); 86#endif // PLATFORM(IOS) 87 } 88 89 virtual bool getConnectionIdentifier(IPC::Connection::Identifier& identifier) 90 { 91 String clientExecutable = m_commandLine["client-executable"]; 92 if (clientExecutable.isEmpty()) 93 return ChildProcessMainDelegate::getConnectionIdentifier(identifier); 94 95 mach_port_name_t publishedService; 96 mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &publishedService); 97 mach_port_insert_right(mach_task_self(), publishedService, publishedService, MACH_MSG_TYPE_MAKE_SEND); 98 // Make it possible to look up. 99 String serviceName = String::format("com.apple.WebKit.WebProcess-%d", getpid()); 100 if (kern_return_t kr = bootstrap_register2(bootstrap_port, const_cast<char*>(serviceName.utf8().data()), publishedService, 0)) { 101 WTFLogAlways("Failed to register service name \"%s\". %s (%x)\n", serviceName.utf8().data(), mach_error_string(kr), kr); 102 return false; 103 } 104 105 CString command = clientExecutable.utf8(); 106 const char* args[] = { command.data(), 0 }; 107 108 EnvironmentVariables environmentVariables; 109 environmentVariables.set(EnvironmentVariables::preexistingProcessServiceNameKey(), serviceName.utf8().data()); 110 environmentVariables.set(EnvironmentVariables::preexistingProcessTypeKey(), m_commandLine["type"].utf8().data()); 111 112 posix_spawn_file_actions_t fileActions; 113 posix_spawn_file_actions_init(&fileActions); 114 posix_spawn_file_actions_addinherit_np(&fileActions, STDIN_FILENO); 115 posix_spawn_file_actions_addinherit_np(&fileActions, STDOUT_FILENO); 116 posix_spawn_file_actions_addinherit_np(&fileActions, STDERR_FILENO); 117 118 posix_spawnattr_t attributes; 119 posix_spawnattr_init(&attributes); 120 posix_spawnattr_setflags(&attributes, POSIX_SPAWN_CLOEXEC_DEFAULT | POSIX_SPAWN_SETPGROUP); 121 122 int spawnResult = posix_spawn(0, command.data(), &fileActions, &attributes, const_cast<char**>(args), environmentVariables.environmentPointer()); 123 124 posix_spawnattr_destroy(&attributes); 125 posix_spawn_file_actions_destroy(&fileActions); 126 127 if (spawnResult) 128 return false; 129 130 mach_msg_empty_rcv_t message; 131 if (kern_return_t kr = mach_msg(&message.header, MACH_RCV_MSG, 0, sizeof(message), publishedService, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL)) { 132 WTFLogAlways("Failed to receive port from the UI process. %s (%x)\n", mach_error_string(kr), kr); 133 return false; 134 } 135 136 mach_port_mod_refs(mach_task_self(), publishedService, MACH_PORT_RIGHT_RECEIVE, -1); 137 mach_port_t serverPort = message.header.msgh_remote_port; 138 mach_port_type_t portType; 139 kern_return_t kr = mach_port_type(mach_task_self(), serverPort, &portType); 140 if (kr || !(portType & MACH_PORT_TYPE_SEND)) { 141 WTFLogAlways("Failed to obtain send right for port received from the UI process.\n"); 142 return false; 143 } 144 145 identifier = serverPort; 146 return true; 147 } 148 149 virtual bool getClientIdentifier(String& clientIdentifier) 150 { 151 String clientExecutable = m_commandLine["client-executable"]; 152 if (clientExecutable.isEmpty()) 153 return ChildProcessMainDelegate::getClientIdentifier(clientIdentifier); 154 155 RetainPtr<NSURL> clientExecutableURL = adoptNS([[NSURL alloc] initFileURLWithPath:nsStringFromWebCoreString(clientExecutable)]); 156 RetainPtr<CFURLRef> clientBundleURL = adoptCF(WKCopyBundleURLForExecutableURL((CFURLRef)clientExecutableURL.get())); 157 RetainPtr<NSBundle> clientBundle = adoptNS([[NSBundle alloc] initWithURL:(NSURL *)clientBundleURL.get()]); 158 clientIdentifier = [clientBundle bundleIdentifier]; 159 if (clientIdentifier.isEmpty()) 160 return false; 161 return true; 162 } 163 164 virtual bool getClientProcessName(String& clientProcessName) 165 { 166 String clientExecutable = m_commandLine["client-executable"]; 167 if (clientExecutable.isEmpty()) 168 return ChildProcessMainDelegate::getClientProcessName(clientProcessName); 169 170 // Conjure up a process name by using everything after the last slash from the client-executable, 171 // e.g. /Applications/Safari.app/Contents/MacOS/Safari becomes Safari. 172 size_t lastSlash = clientExecutable.reverseFind('/'); 173 clientProcessName = clientExecutable.substring(lastSlash + 1); 174 if (clientProcessName.isEmpty()) 175 return false; 176 return true; 177 } 178 179 virtual void startRunLoop() override 180 { 181#if USE(APPKIT) 182 ASSERT(NSApp); 183 [NSApp run]; 184#else 185 RunLoop::run(); 186#endif 187 } 188}; 189 190} // namespace WebKit 191 192using namespace WebKit; 193 194extern "C" WK_EXPORT int WebContentProcessMain(int argc, char** argv); 195 196int WebContentProcessMain(int argc, char** argv) 197{ 198 return ChildProcessMain<WebProcess, WebContentProcessMainDelegate>(argc, argv); 199} 200