1/* 2 * Copyright (C) 2008 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. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#if USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API) 27 28#import "NetscapePluginHostManager.h" 29 30#import "NetscapePluginHostProxy.h" 31#import "NetscapePluginInstanceProxy.h" 32#import "WebLocalizableStringsInternal.h" 33#import "WebKitSystemInterface.h" 34#import "WebNetscapePluginPackage.h" 35#import <mach/mach_port.h> 36#import <servers/bootstrap.h> 37#import <spawn.h> 38#import <wtf/Assertions.h> 39#import <wtf/RetainPtr.h> 40#import <wtf/StdLibExtras.h> 41 42extern "C" { 43#import "WebKitPluginAgent.h" 44#import "WebKitPluginHost.h" 45} 46 47using namespace WebCore; 48 49namespace WebKit { 50 51NetscapePluginHostManager& NetscapePluginHostManager::shared() 52{ 53 DEPRECATED_DEFINE_STATIC_LOCAL(NetscapePluginHostManager, pluginHostManager, ()); 54 55 return pluginHostManager; 56} 57 58static NSString * const pluginHostAppName = @"WebKitPluginHost.app"; 59 60NetscapePluginHostManager::NetscapePluginHostManager() 61 : m_pluginVendorPort(MACH_PORT_NULL) 62{ 63} 64 65NetscapePluginHostManager::~NetscapePluginHostManager() 66{ 67} 68 69NetscapePluginHostProxy* NetscapePluginHostManager::hostForPlugin(const WTF::String& pluginPath, cpu_type_t pluginArchitecture, const String& bundleIdentifier) 70{ 71 PluginHostMap::AddResult result = m_pluginHosts.add(pluginPath, nullptr); 72 73 // The package was already in the map, just return it. 74 if (!result.isNewEntry) 75 return result.iterator->value; 76 77 mach_port_t clientPort; 78 if (mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort) != KERN_SUCCESS) { 79 m_pluginHosts.remove(result.iterator); 80 return 0; 81 } 82 83 mach_port_t pluginHostPort; 84 ProcessSerialNumber pluginHostPSN; 85 if (!spawnPluginHost(pluginPath, pluginArchitecture, clientPort, pluginHostPort, pluginHostPSN)) { 86 mach_port_destroy(mach_task_self(), clientPort); 87 m_pluginHosts.remove(result.iterator); 88 return 0; 89 } 90 91 // Since Flash NPObjects add methods dynamically, we don't want to cache when a property/method doesn't exist 92 // on an object because it could be added later. 93 bool shouldCacheMissingPropertiesAndMethods = bundleIdentifier != "com.macromedia.Flash Player.plugin"; 94 95 NetscapePluginHostProxy* hostProxy = new NetscapePluginHostProxy(clientPort, pluginHostPort, pluginHostPSN, shouldCacheMissingPropertiesAndMethods); 96 97 result.iterator->value = hostProxy; 98 99 return hostProxy; 100} 101 102bool NetscapePluginHostManager::spawnPluginHost(const String& pluginPath, cpu_type_t pluginArchitecture, mach_port_t clientPort, mach_port_t& pluginHostPort, ProcessSerialNumber& pluginHostPSN) 103{ 104 if (m_pluginVendorPort == MACH_PORT_NULL) { 105 if (!initializeVendorPort()) 106 return false; 107 } 108 109 mach_port_t renderServerPort = WKInitializeRenderServer(); 110 if (renderServerPort == MACH_PORT_NULL) 111 return false; 112 113 NSString *pluginHostAppPath = [[NSBundle bundleForClass:[WebNetscapePluginPackage class]] pathForAuxiliaryExecutable:pluginHostAppName]; 114 NSString *pluginHostAppExecutablePath = [[NSBundle bundleWithPath:pluginHostAppPath] executablePath]; 115 116 RetainPtr<CFStringRef> localization = adoptCF(WKCopyCFLocalizationPreferredName(NULL)); 117 118 NSDictionary *launchProperties = [[NSDictionary alloc] initWithObjectsAndKeys: 119 pluginHostAppExecutablePath, @"pluginHostPath", 120 [NSNumber numberWithInt:pluginArchitecture], @"cpuType", 121 (NSString *)localization.get(), @"localization", 122 nil]; 123 124 NSData *data = [NSPropertyListSerialization dataWithPropertyList:launchProperties format:NSPropertyListBinaryFormat_v1_0 options:0 error:nullptr]; 125 ASSERT(data); 126 127 [launchProperties release]; 128 129 kern_return_t kr = _WKPASpawnPluginHost(m_pluginVendorPort, reinterpret_cast<uint8_t*>(const_cast<void*>([data bytes])), [data length], &pluginHostPort); 130 131 if (kr == MACH_SEND_INVALID_DEST) { 132 // The plug-in vendor port has gone away for some reason. Try to reinitialize it. 133 m_pluginVendorPort = MACH_PORT_NULL; 134 if (!initializeVendorPort()) 135 return false; 136 137 // And spawn the plug-in host again. 138 kr = _WKPASpawnPluginHost(m_pluginVendorPort, reinterpret_cast<uint8_t*>(const_cast<void*>([data bytes])), [data length], &pluginHostPort); 139 } 140 141 if (kr != KERN_SUCCESS) { 142 // FIXME: Check for invalid dest and try to re-spawn the plug-in agent. 143 LOG_ERROR("Failed to spawn plug-in host, error %x", kr); 144 return false; 145 } 146 147 NSString *visibleName = [NSString stringWithFormat:UI_STRING_INTERNAL("%@ (%@ Internet plug-in)", 148 "visible name of the plug-in host process. The first argument is the plug-in name " 149 "and the second argument is the application name."), 150 [[(NSString*)pluginPath lastPathComponent] stringByDeletingPathExtension], [[NSProcessInfo processInfo] processName]]; 151 152 NSDictionary *hostProperties = [[NSDictionary alloc] initWithObjectsAndKeys: 153 visibleName, @"visibleName", 154 (NSString *)pluginPath, @"bundlePath", 155 nil]; 156 157 data = [NSPropertyListSerialization dataWithPropertyList:hostProperties format:NSPropertyListBinaryFormat_v1_0 options:0 error:NULL]; 158 ASSERT(data); 159 160 [hostProperties release]; 161 162 ProcessSerialNumber psn; 163 164#pragma clang diagnostic push 165#pragma clang diagnostic ignored "-Wdeprecated-declarations" 166 GetCurrentProcess(&psn); 167#pragma clang diagnostic pop 168 169 kr = _WKPHCheckInWithPluginHost(pluginHostPort, (uint8_t*)[data bytes], [data length], clientPort, psn.highLongOfPSN, psn.lowLongOfPSN, renderServerPort, 170 &pluginHostPSN.highLongOfPSN, &pluginHostPSN.lowLongOfPSN); 171 172 if (kr != KERN_SUCCESS) { 173 mach_port_deallocate(mach_task_self(), pluginHostPort); 174 LOG_ERROR("Failed to check in with plug-in host, error %x", kr); 175 176 return false; 177 } 178 179 return true; 180} 181 182bool NetscapePluginHostManager::initializeVendorPort() 183{ 184 ASSERT(m_pluginVendorPort == MACH_PORT_NULL); 185 186 // Get the plug-in agent port. 187 mach_port_t pluginAgentPort; 188 if (bootstrap_look_up(bootstrap_port, "com.apple.WebKit.PluginAgent", &pluginAgentPort) != KERN_SUCCESS) { 189 LOG_ERROR("Failed to look up the plug-in agent port"); 190 return false; 191 } 192 193 NSData *appNameData = [[[NSProcessInfo processInfo] processName] dataUsingEncoding:NSUTF8StringEncoding]; 194 195 // Tell the plug-in agent that we exist. 196 if (_WKPACheckInApplication(pluginAgentPort, (uint8_t*)[appNameData bytes], [appNameData length], &m_pluginVendorPort) != KERN_SUCCESS) 197 return false; 198 199 // FIXME: Should we add a notification for when the vendor port dies? 200 201 return true; 202} 203 204void NetscapePluginHostManager::pluginHostDied(NetscapePluginHostProxy* pluginHost) 205{ 206 PluginHostMap::iterator end = m_pluginHosts.end(); 207 208 // This has O(n) complexity but the number of active plug-in hosts is very small so it shouldn't matter. 209 for (PluginHostMap::iterator it = m_pluginHosts.begin(); it != end; ++it) { 210 if (it->value == pluginHost) { 211 m_pluginHosts.remove(it); 212 return; 213 } 214 } 215} 216 217PassRefPtr<NetscapePluginInstanceProxy> NetscapePluginHostManager::instantiatePlugin(const String& pluginPath, cpu_type_t pluginArchitecture, const String& bundleIdentifier, WebHostedNetscapePluginView *pluginView, NSString *mimeType, NSArray *attributeKeys, NSArray *attributeValues, NSString *userAgent, NSURL *sourceURL, bool fullFrame, bool isPrivateBrowsingEnabled, bool isAcceleratedCompositingEnabled, bool hostLayersInWindowServer) 218{ 219 NetscapePluginHostProxy* hostProxy = hostForPlugin(pluginPath, pluginArchitecture, bundleIdentifier); 220 if (!hostProxy) 221 return 0; 222 223 RetainPtr<NSMutableDictionary> properties = adoptNS([[NSMutableDictionary alloc] init]); 224 225 if (mimeType) 226 [properties.get() setObject:mimeType forKey:@"mimeType"]; 227 228 ASSERT_ARG(userAgent, userAgent); 229 [properties.get() setObject:userAgent forKey:@"userAgent"]; 230 231 ASSERT_ARG(attributeKeys, attributeKeys); 232 [properties.get() setObject:attributeKeys forKey:@"attributeKeys"]; 233 234 ASSERT_ARG(attributeValues, attributeValues); 235 [properties.get() setObject:attributeValues forKey:@"attributeValues"]; 236 237 if (sourceURL) 238 [properties.get() setObject:[sourceURL absoluteString] forKey:@"sourceURL"]; 239 240 [properties.get() setObject:[NSNumber numberWithBool:fullFrame] forKey:@"fullFrame"]; 241 [properties.get() setObject:[NSNumber numberWithBool:isPrivateBrowsingEnabled] forKey:@"privateBrowsingEnabled"]; 242 [properties.get() setObject:[NSNumber numberWithBool:isAcceleratedCompositingEnabled] forKey:@"acceleratedCompositingEnabled"]; 243 [properties.get() setObject:[NSNumber numberWithBool:hostLayersInWindowServer] forKey:@"hostLayersInWindowServer"]; 244 245 NSData *data = [NSPropertyListSerialization dataWithPropertyList:properties.get() format:NSPropertyListBinaryFormat_v1_0 options:0 error:nullptr]; 246 ASSERT(data); 247 248 RefPtr<NetscapePluginInstanceProxy> instance = NetscapePluginInstanceProxy::create(hostProxy, pluginView, fullFrame); 249 uint32_t requestID = instance->nextRequestID(); 250 kern_return_t kr = _WKPHInstantiatePlugin(hostProxy->port(), requestID, (uint8_t*)[data bytes], [data length], instance->pluginID()); 251 if (kr == MACH_SEND_INVALID_DEST) { 252 // Invalidate the instance. 253 instance->invalidate(); 254 255 // The plug-in host must have died, but we haven't received the death notification yet. 256 pluginHostDied(hostProxy); 257 258 // Try to spawn it again. 259 hostProxy = hostForPlugin(pluginPath, pluginArchitecture, bundleIdentifier); 260 261 // Create a new instance. 262 instance = NetscapePluginInstanceProxy::create(hostProxy, pluginView, fullFrame); 263 requestID = instance->nextRequestID(); 264 _WKPHInstantiatePlugin(hostProxy->port(), requestID, (uint8_t*)[data bytes], [data length], instance->pluginID()); 265 } 266 267 auto reply = instance->waitForReply<NetscapePluginInstanceProxy::InstantiatePluginReply>(requestID); 268 if (!reply || reply->m_resultCode != KERN_SUCCESS) { 269 instance->cleanup(); 270 return nullptr; 271 } 272 273 instance->setRenderContextID(reply->m_renderContextID); 274 instance->setRendererType(reply->m_rendererType); 275 276 return instance.release(); 277} 278 279void NetscapePluginHostManager::createPropertyListFile(const String& pluginPath, cpu_type_t pluginArchitecture, const String& bundleIdentifier) 280{ 281 NetscapePluginHostProxy* hostProxy = hostForPlugin(pluginPath, pluginArchitecture, bundleIdentifier); 282 if (!hostProxy) 283 return; 284 285 _WKPHCreatePluginMIMETypesPreferences(hostProxy->port()); 286} 287 288void NetscapePluginHostManager::didCreateWindow() 289{ 290 // See if any of our hosts are in full-screen mode. 291 PluginHostMap::iterator end = m_pluginHosts.end(); 292 for (PluginHostMap::iterator it = m_pluginHosts.begin(); it != end; ++it) { 293 NetscapePluginHostProxy* hostProxy = it->value; 294 295 if (!hostProxy->isMenuBarVisible()) { 296 // Make ourselves the front process. 297 ProcessSerialNumber psn; 298#pragma clang diagnostic push 299#pragma clang diagnostic ignored "-Wdeprecated-declarations" 300 GetCurrentProcess(&psn); 301 SetFrontProcess(&psn); 302#pragma clang diagnostic pop 303 return; 304 } 305 } 306} 307 308} // namespace WebKit 309 310#endif // USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API) 311