PluginProcessProxy.cpp [plain text]
#include "config.h"
#include "PluginProcessProxy.h"
#if ENABLE(NETSCAPE_PLUGIN_API)
#include "PluginProcessConnectionManagerMessages.h"
#include "PluginProcessCreationParameters.h"
#include "PluginProcessManager.h"
#include "PluginProcessMessages.h"
#include "WebCoreArgumentCoders.h"
#include "WebProcessPool.h"
#include "WebProcessProxy.h"
#include <WebCore/NotImplemented.h>
#include <wtf/RunLoop.h>
#if OS(LINUX)
#include "MemoryPressureMonitor.h"
#endif
using namespace WebCore;
namespace WebKit {
static const double minimumLifetime = 2 * 60;
static const double snapshottingMinimumLifetime = 30;
static const double shutdownTimeout = 1 * 60;
static const double snapshottingShutdownTimeout = 15;
static uint64_t generateCallbackID()
{
static uint64_t callbackID;
return ++callbackID;
}
Ref<PluginProcessProxy> PluginProcessProxy::create(PluginProcessManager* PluginProcessManager, const PluginProcessAttributes& pluginProcessAttributes, uint64_t pluginProcessToken)
{
return adoptRef(*new PluginProcessProxy(PluginProcessManager, pluginProcessAttributes, pluginProcessToken));
}
PluginProcessProxy::PluginProcessProxy(PluginProcessManager* PluginProcessManager, const PluginProcessAttributes& pluginProcessAttributes, uint64_t pluginProcessToken)
: m_pluginProcessManager(PluginProcessManager)
, m_pluginProcessAttributes(pluginProcessAttributes)
, m_pluginProcessToken(pluginProcessToken)
, m_numPendingConnectionRequests(0)
#if PLATFORM(COCOA)
, m_modalWindowIsShowing(false)
, m_fullscreenWindowIsShowing(false)
, m_preFullscreenAppPresentationOptions(0)
#endif
{
connect();
}
PluginProcessProxy::~PluginProcessProxy()
{
ASSERT(m_pendingFetchWebsiteDataRequests.isEmpty());
ASSERT(m_pendingFetchWebsiteDataCallbacks.isEmpty());
ASSERT(m_pendingDeleteWebsiteDataRequests.isEmpty());
ASSERT(m_pendingDeleteWebsiteDataCallbacks.isEmpty());
}
void PluginProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& launchOptions)
{
ChildProcessProxy::getLaunchOptions(launchOptions);
platformGetLaunchOptions(launchOptions, m_pluginProcessAttributes);
}
void PluginProcessProxy::processWillShutDown(IPC::Connection& connection)
{
ASSERT_UNUSED(connection, this->connection() == &connection);
}
void PluginProcessProxy::getPluginProcessConnection(PassRefPtr<Messages::WebProcessProxy::GetPluginProcessConnection::DelayedReply> reply)
{
m_pendingConnectionReplies.append(reply);
if (state() == State::Launching) {
m_numPendingConnectionRequests++;
return;
}
m_connection->send(Messages::PluginProcess::CreateWebProcessConnection(), 0, IPC::DispatchMessageEvenWhenWaitingForSyncReply);
}
void PluginProcessProxy::fetchWebsiteData(std::function<void (Vector<String>)> completionHandler)
{
uint64_t callbackID = generateCallbackID();
m_pendingFetchWebsiteDataCallbacks.set(callbackID, WTFMove(completionHandler));
if (state() == State::Launching) {
m_pendingFetchWebsiteDataRequests.append(callbackID);
return;
}
m_connection->send(Messages::PluginProcess::GetSitesWithData(callbackID), 0);
}
void PluginProcessProxy::deleteWebsiteData(std::chrono::system_clock::time_point modifiedSince, std::function<void ()> completionHandler)
{
uint64_t callbackID = generateCallbackID();
m_pendingDeleteWebsiteDataCallbacks.set(callbackID, WTFMove(completionHandler));
if (state() == State::Launching) {
m_pendingDeleteWebsiteDataRequests.append({ modifiedSince, callbackID });
return;
}
m_connection->send(Messages::PluginProcess::DeleteWebsiteData(modifiedSince, callbackID), 0);
}
void PluginProcessProxy::deleteWebsiteDataForHostNames(const Vector<String>& hostNames, std::function<void ()> completionHandler)
{
uint64_t callbackID = generateCallbackID();
m_pendingDeleteWebsiteDataForHostNamesCallbacks.set(callbackID, WTFMove(completionHandler));
if (state() == State::Launching) {
m_pendingDeleteWebsiteDataForHostNamesRequests.append({ hostNames, callbackID });
return;
}
m_connection->send(Messages::PluginProcess::DeleteWebsiteDataForHostNames(hostNames, callbackID), 0);
}
void PluginProcessProxy::pluginProcessCrashedOrFailedToLaunch()
{
while (!m_pendingConnectionReplies.isEmpty()) {
RefPtr<Messages::WebProcessProxy::GetPluginProcessConnection::DelayedReply> reply = m_pendingConnectionReplies.takeFirst();
#if USE(UNIX_DOMAIN_SOCKETS)
reply->send(IPC::Attachment(), false);
#elif OS(DARWIN)
reply->send(IPC::Attachment(0, MACH_MSG_TYPE_MOVE_SEND), false);
#else
notImplemented();
#endif
}
m_pendingFetchWebsiteDataRequests.clear();
for (const auto& callback : m_pendingFetchWebsiteDataCallbacks.values())
callback({ });
m_pendingFetchWebsiteDataCallbacks.clear();
m_pendingDeleteWebsiteDataRequests.clear();
for (const auto& callback : m_pendingDeleteWebsiteDataCallbacks.values())
callback();
m_pendingDeleteWebsiteDataRequests.clear();
m_pendingDeleteWebsiteDataForHostNamesRequests.clear();
for (const auto& callback : m_pendingDeleteWebsiteDataForHostNamesCallbacks.values())
callback();
m_pendingDeleteWebsiteDataForHostNamesCallbacks.clear();
m_pluginProcessManager->removePluginProcessProxy(this);
}
void PluginProcessProxy::didClose(IPC::Connection&)
{
#if PLATFORM(COCOA)
if (m_modalWindowIsShowing)
endModal();
if (m_fullscreenWindowIsShowing)
exitFullscreen();
#endif
const Vector<WebProcessPool*>& processPools = WebProcessPool::allProcessPools();
for (size_t i = 0; i < processPools.size(); ++i)
processPools[i]->sendToAllProcesses(Messages::PluginProcessConnectionManager::PluginProcessCrashed(m_pluginProcessToken));
pluginProcessCrashedOrFailedToLaunch();
}
void PluginProcessProxy::didReceiveInvalidMessage(IPC::Connection&, IPC::StringReference, IPC::StringReference)
{
}
void PluginProcessProxy::didFinishLaunching(ProcessLauncher*, IPC::Connection::Identifier connectionIdentifier)
{
ASSERT(!m_connection);
if (IPC::Connection::identifierIsNull(connectionIdentifier)) {
pluginProcessCrashedOrFailedToLaunch();
return;
}
m_connection = IPC::Connection::createServerConnection(connectionIdentifier, *this);
#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED <= 101000
m_connection->setShouldCloseConnectionOnMachExceptions();
#endif
m_connection->open();
PluginProcessCreationParameters parameters;
parameters.processType = m_pluginProcessAttributes.processType;
if (parameters.processType == PluginProcessTypeSnapshot) {
parameters.minimumLifetime = snapshottingMinimumLifetime;
parameters.terminationTimeout = snapshottingShutdownTimeout;
} else {
parameters.minimumLifetime = minimumLifetime;
parameters.terminationTimeout = shutdownTimeout;
}
#if OS(LINUX)
if (MemoryPressureMonitor::isEnabled())
parameters.memoryPressureMonitorHandle = MemoryPressureMonitor::singleton().createHandle();
#endif
platformInitializePluginProcess(parameters);
m_connection->send(Messages::PluginProcess::InitializePluginProcess(parameters), 0);
#if PLATFORM(COCOA)
m_connection->send(Messages::PluginProcess::SetQOS(pluginProcessLatencyQOS(), pluginProcessThroughputQOS()), 0);
#endif
for (auto callbackID : m_pendingFetchWebsiteDataRequests)
m_connection->send(Messages::PluginProcess::GetSitesWithData(callbackID), 0);
m_pendingFetchWebsiteDataRequests.clear();
for (auto& request : m_pendingDeleteWebsiteDataRequests)
m_connection->send(Messages::PluginProcess::DeleteWebsiteData(request.modifiedSince, request.callbackID), 0);
m_pendingDeleteWebsiteDataRequests.clear();
for (auto& request : m_pendingDeleteWebsiteDataForHostNamesRequests)
m_connection->send(Messages::PluginProcess::DeleteWebsiteDataForHostNames(request.hostNames, request.callbackID), 0);
m_pendingDeleteWebsiteDataForHostNamesRequests.clear();
for (unsigned i = 0; i < m_numPendingConnectionRequests; ++i)
m_connection->send(Messages::PluginProcess::CreateWebProcessConnection(), 0);
m_numPendingConnectionRequests = 0;
#if PLATFORM(COCOA)
if (!PluginProcessManager::singleton().processSuppressionDisabled())
setProcessSuppressionEnabled(true);
#endif
}
void PluginProcessProxy::didCreateWebProcessConnection(const IPC::Attachment& connectionIdentifier, bool supportsAsynchronousPluginInitialization)
{
ASSERT(!m_pendingConnectionReplies.isEmpty());
RefPtr<Messages::WebProcessProxy::GetPluginProcessConnection::DelayedReply> reply = m_pendingConnectionReplies.takeFirst();
#if USE(UNIX_DOMAIN_SOCKETS)
reply->send(connectionIdentifier, supportsAsynchronousPluginInitialization);
#elif OS(DARWIN)
reply->send(IPC::Attachment(connectionIdentifier.port(), MACH_MSG_TYPE_MOVE_SEND), supportsAsynchronousPluginInitialization);
#else
notImplemented();
#endif
}
void PluginProcessProxy::didGetSitesWithData(const Vector<String>& sites, uint64_t callbackID)
{
auto callback = m_pendingFetchWebsiteDataCallbacks.take(callbackID);
callback(sites);
}
void PluginProcessProxy::didDeleteWebsiteData(uint64_t callbackID)
{
auto callback = m_pendingDeleteWebsiteDataCallbacks.take(callbackID);
callback();
}
void PluginProcessProxy::didDeleteWebsiteDataForHostNames(uint64_t callbackID)
{
auto callback = m_pendingDeleteWebsiteDataForHostNamesCallbacks.take(callbackID);
callback();
}
}
#endif // ENABLE(NETSCAPE_PLUGIN_API)