Diff
Modified: trunk/Source/WebKit2/ChangeLog (120204 => 120205)
--- trunk/Source/WebKit2/ChangeLog 2012-06-13 14:37:49 UTC (rev 120204)
+++ trunk/Source/WebKit2/ChangeLog 2012-06-13 14:39:32 UTC (rev 120205)
@@ -1,3 +1,35 @@
+2012-06-13 Balazs Kelemen <[email protected]>
+
+ [Qt][WK2] Scanning plugins blocks the UI for a long time
+ https://bugs.webkit.org/show_bug.cgi?id=88535
+
+ Reviewed by Simon Hausmann.
+
+ Implement a persistent cache for the meta data of plugins.
+ This way the UI process will not block for too long when
+ it's time to scan the plugins (except the first time).
+ The cache is a json file stored in a standard hidden cache
+ directory.
+
+ * Shared/qt/QtDefaultDataLocation.cpp: Added.
+ (WebKit):
+ (WebKit::defaultDataLocation):
+ * Shared/qt/QtDefaultDataLocation.h: Added.
+ (WebKit):
+ Added a common helper for the path we use to
+ put stuff into.
+
+ * Target.pri:
+ * UIProcess/Plugins/qt/PluginProcessProxyQt.cpp:
+ (WebKit::cacheFile):
+ (WebKit):
+ (WebKit::readMetaDataFromCacheFile):
+ (WebKit::writeToCacheFile):
+ (WebKit::appendToCacheFile):
+ (WebKit::tryReadPluginMetaDataFromCacheFile):
+ (WebKit::PluginProcessProxy::scanPlugin):
+ * UIProcess/qt/WebContextQt.cpp:
+
2012-06-13 Kenneth Rohde Christiansen <[email protected]>
[Qt] Do not set contents pos to the current position
Added: trunk/Source/WebKit2/Shared/qt/QtDefaultDataLocation.cpp (0 => 120205)
--- trunk/Source/WebKit2/Shared/qt/QtDefaultDataLocation.cpp (rev 0)
+++ trunk/Source/WebKit2/Shared/qt/QtDefaultDataLocation.cpp 2012-06-13 14:39:32 UTC (rev 120205)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2012 University of Szeged. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "QtDefaultDataLocation.h"
+
+#include <QCoreApplication>
+#include <QDir>
+#include <QStandardPaths>
+#include <QStringBuilder>
+#include <WebCore/FileSystem.h>
+
+namespace WebKit {
+
+QString defaultDataLocation()
+{
+ static QString s_dataLocation;
+
+ if (!s_dataLocation.isEmpty())
+ return s_dataLocation;
+
+ QString dataLocation = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
+ if (dataLocation.isEmpty())
+ dataLocation = QDir::homePath() % QDir::separator() % QCoreApplication::applicationName();
+ s_dataLocation = dataLocation % QDir::separator() % QStringLiteral(".QtWebKit") % QDir::separator();
+ QDir::root().mkpath(s_dataLocation);
+
+ return s_dataLocation;
+}
+
+}
Added: trunk/Source/WebKit2/Shared/qt/QtDefaultDataLocation.h (0 => 120205)
--- trunk/Source/WebKit2/Shared/qt/QtDefaultDataLocation.h (rev 0)
+++ trunk/Source/WebKit2/Shared/qt/QtDefaultDataLocation.h 2012-06-13 14:39:32 UTC (rev 120205)
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2012 University of Szeged. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef QtDefaultDataLocation_h
+#define QtDefaultDataLocation_h
+
+#include <QString>
+
+namespace WebKit {
+
+QString defaultDataLocation();
+
+}
+
+#endif
Modified: trunk/Source/WebKit2/Target.pri (120204 => 120205)
--- trunk/Source/WebKit2/Target.pri 2012-06-13 14:37:49 UTC (rev 120204)
+++ trunk/Source/WebKit2/Target.pri 2012-06-13 14:39:32 UTC (rev 120205)
@@ -137,6 +137,7 @@
Shared/qt/ArgumentCodersQt.h \
Shared/qt/PlatformCertificateInfo.h \
Shared/qt/WebEventFactoryQt.h \
+ Shared/qt/QtDefaultDataLocation.h \
Shared/qt/QtNetworkReplyData.h \
Shared/qt/QtNetworkRequestData.h \
UIProcess/API/C/WKAPICast.h \
@@ -489,6 +490,7 @@
Shared/qt/ProcessExecutablePathQt.cpp \
Shared/qt/WebCoreArgumentCodersQt.cpp \
Shared/qt/WebEventFactoryQt.cpp \
+ Shared/qt/QtDefaultDataLocation.cpp \
Shared/qt/QtNetworkReplyData.cpp \
Shared/qt/QtNetworkRequestData.cpp \
Shared/qt/WebURLRequestQt.cpp \
Modified: trunk/Source/WebKit2/UIProcess/Plugins/qt/PluginProcessProxyQt.cpp (120204 => 120205)
--- trunk/Source/WebKit2/UIProcess/Plugins/qt/PluginProcessProxyQt.cpp 2012-06-13 14:37:49 UTC (rev 120204)
+++ trunk/Source/WebKit2/UIProcess/Plugins/qt/PluginProcessProxyQt.cpp 2012-06-13 14:39:32 UTC (rev 120205)
@@ -29,12 +29,23 @@
#if ENABLE(PLUGIN_PROCESS)
#include "ProcessExecutablePath.h"
+#include "QtDefaultDataLocation.h"
#include <QByteArray>
#include <QCoreApplication>
+#include <QDateTime>
#include <QDir>
#include <QEventLoop>
+#include <QFile>
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QMap>
#include <QProcess>
-#include <QString>
+#include <QStringBuilder>
+#include <QVariant>
+#include <WebCore/FileSystem.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
namespace WebKit {
@@ -44,35 +55,181 @@
{
}
+static PassOwnPtr<QFile> cacheFile()
+{
+ static QString cacheFilePath = defaultDataLocation() % QStringLiteral("plugin_meta_data.json");
+ return adoptPtr(new QFile(cacheFilePath));
+}
+
+struct ReadResult {
+ enum Tag {
+ Empty,
+ Error,
+ Success
+ };
+};
+
+static ReadResult::Tag readMetaDataFromCacheFile(QJsonDocument& result)
+{
+ OwnPtr<QFile> file = cacheFile();
+ if (!file->open(QFile::ReadOnly))
+ return ReadResult::Empty;
+ QByteArray data = ""
+ if (data.isEmpty())
+ return ReadResult::Empty;
+
+ QJsonParseError error;
+ result = QJsonDocument::fromJson(data, &error);
+ if (error.error != QJsonParseError::NoError || !result.isArray()) {
+ // Corrupted file.
+ file->remove();
+ return ReadResult::Error;
+ }
+
+ return ReadResult::Success;
+}
+
+static void writeToCacheFile(const QJsonArray& array)
+{
+ OwnPtr<QFile> file = cacheFile();
+ if (!file->open(QFile::WriteOnly | QFile::Truncate)) {
+ // It should never but let's be pessimistic, it is the file system after all.
+ qWarning("Cannot write into plugin meta data cache file: %s\n", qPrintable(file->fileName()));
+ return;
+ }
+
+ // Don't care about write error here. We will detect it later.
+ file->write(QJsonDocument(array).toJson());
+}
+
+static void appendToCacheFile(const QJsonObject& object)
+{
+ QJsonDocument jsonDocument;
+ ReadResult::Tag result = readMetaDataFromCacheFile(jsonDocument);
+ if (result == ReadResult::Error)
+ return;
+ if (result == ReadResult::Empty)
+ jsonDocument.setArray(QJsonArray());
+
+ QJsonArray array = jsonDocument.array();
+ array.append(object);
+ writeToCacheFile(array);
+}
+
+struct MetaDataResult {
+ enum Tag {
+ NotAvailable,
+ Unloadable,
+ Available
+ };
+};
+
+static MetaDataResult::Tag tryReadPluginMetaDataFromCacheFile(const QString& canonicalPluginPath, RawPluginMetaData& result)
+{
+ QJsonDocument jsonDocument;
+ if (readMetaDataFromCacheFile(jsonDocument) != ReadResult::Success)
+ return MetaDataResult::NotAvailable;
+
+ QJsonArray array = jsonDocument.array();
+ QDateTime pluginLastModified = QFileInfo(canonicalPluginPath).lastModified();
+ for (QJsonArray::const_iterator i = array.constBegin(); i != array.constEnd(); ++i) {
+ QJsonValue item = *i;
+ if (!item.isObject()) {
+ cacheFile()->remove();
+ return MetaDataResult::NotAvailable;
+ }
+
+ QJsonObject object = item.toObject();
+ if (object.value(QStringLiteral("path")).toString() == canonicalPluginPath) {
+ QString timestampString = object.value(QStringLiteral("timestamp")).toString();
+ if (timestampString.isEmpty()) {
+ cacheFile()->remove();
+ return MetaDataResult::NotAvailable;
+ }
+ QDateTime timestamp = QDateTime::fromString(timestampString);
+ if (timestamp < pluginLastModified) {
+ // Out of date data for this plugin => remove it from the file.
+ array.removeAt(i.i);
+ writeToCacheFile(array);
+ return MetaDataResult::NotAvailable;
+ }
+
+ if (object.contains(QLatin1String("unloadable")))
+ return MetaDataResult::Unloadable;
+
+ // Match.
+ result.name = object.value(QStringLiteral("name")).toString();
+ result.description = object.value(QStringLiteral("description")).toString();
+ result.mimeDescription = object.value(QStringLiteral("mimeDescription")).toString();
+ if (result.mimeDescription.isEmpty()) {
+ // Only the mime description is mandatory.
+ // Don't trust in the cache file if it is empty.
+ cacheFile()->remove();
+ return MetaDataResult::NotAvailable;
+ }
+
+ return MetaDataResult::Available;
+ }
+ }
+
+ return MetaDataResult::NotAvailable;
+}
+
bool PluginProcessProxy::scanPlugin(const String& pluginPath, RawPluginMetaData& result)
{
- QString commandLine = QLatin1String("%1 %2 %3");
- commandLine = commandLine.arg(executablePathOfPluginProcess());
- commandLine = commandLine.arg(QStringLiteral("-scanPlugin")).arg(static_cast<QString>(pluginPath));
+ QFileInfo pluginFileInfo(pluginPath);
+ if (!pluginFileInfo.exists())
+ return false;
+ MetaDataResult::Tag metaDataResult = tryReadPluginMetaDataFromCacheFile(pluginFileInfo.canonicalFilePath(), result);
+ if (metaDataResult == MetaDataResult::Available)
+ return true;
+ if (metaDataResult == MetaDataResult::Unloadable)
+ return false;
+
+ // Scan the plugin via the plugin process.
+ QString commandLine = QString(executablePathOfPluginProcess()) % QLatin1Char(' ')
+ % QStringLiteral("-scanPlugin") % QLatin1Char(' ') % pluginFileInfo.canonicalFilePath();
QProcess process;
process.setReadChannel(QProcess::StandardOutput);
process.start(commandLine);
- if (!process.waitForFinished()
- || process.exitStatus() != QProcess::NormalExit
- || process.exitCode() != EXIT_SUCCESS) {
+ bool ranSuccessfully = process.waitForFinished()
+ && process.exitStatus() == QProcess::NormalExit
+ && process.exitCode() == EXIT_SUCCESS;
+ if (ranSuccessfully) {
+ QByteArray outputBytes = process.readAll();
+ ASSERT(!(outputBytes.size() % sizeof(UChar)));
+
+ String output(reinterpret_cast<const UChar*>(outputBytes.constData()), outputBytes.size() / sizeof(UChar));
+ Vector<String> lines;
+ output.split(UChar('\n'), lines);
+ ASSERT(lines.size() == 3);
+
+ result.name.swap(lines[0]);
+ result.description.swap(lines[1]);
+ result.mimeDescription.swap(lines[2]);
+ } else
process.kill();
+
+ QVariantMap map;
+ map[QStringLiteral("path")] = QString(pluginFileInfo.canonicalFilePath());
+ map[QStringLiteral("timestamp")] = QDateTime::currentDateTime().toString();
+
+ if (!ranSuccessfully || result.mimeDescription.isEmpty()) {
+ // We failed getting the meta data in some way. Cache this information, so we don't
+ // need to rescan such plugins every time. We will retry it once the plugin is updated.
+
+ map[QStringLiteral("unloadable")] = QStringLiteral("true");
+ appendToCacheFile(QJsonObject::fromVariantMap(map));
return false;
}
- QByteArray outputBytes = process.readAll();
- ASSERT(!(outputBytes.size() % sizeof(UChar)));
-
- String output(reinterpret_cast<const UChar*>(outputBytes.constData()), outputBytes.size() / sizeof(UChar));
- Vector<String> lines;
- output.split(UChar('\n'), lines);
- ASSERT(lines.size() == 3);
-
- result.name.swap(lines[0]);
- result.description.swap(lines[1]);
- result.mimeDescription.swap(lines[2]);
- return !result.mimeDescription.isEmpty();
+ map[QStringLiteral("name")] = QString(result.name);
+ map[QStringLiteral("description")] = QString(result.description);
+ map[QStringLiteral("mimeDescription")] = QString(result.mimeDescription);
+ appendToCacheFile(QJsonObject::fromVariantMap(map));
+ return true;
}
} // namespace WebKit
Modified: trunk/Source/WebKit2/UIProcess/qt/WebContextQt.cpp (120204 => 120205)
--- trunk/Source/WebKit2/UIProcess/qt/WebContextQt.cpp 2012-06-13 14:37:49 UTC (rev 120204)
+++ trunk/Source/WebKit2/UIProcess/qt/WebContextQt.cpp 2012-06-13 14:39:32 UTC (rev 120205)
@@ -29,33 +29,18 @@
#include "ApplicationCacheStorage.h"
#include "FileSystem.h"
+#include "QtDefaultDataLocation.h"
#include "WKSharedAPICast.h"
#if ENABLE(GEOLOCATION)
#include "WebGeolocationProviderQt.h"
#endif
#include "WebProcessCreationParameters.h"
#include <QCoreApplication>
-#include <QStandardPaths>
#include <QDir>
#include <QProcess>
namespace WebKit {
-static QString defaultDataLocation()
-{
- static QString s_dataLocation;
-
- if (!s_dataLocation.isEmpty())
- return s_dataLocation;
-
- QString dataLocation = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
- if (dataLocation.isEmpty())
- dataLocation = WebCore::pathByAppendingComponent(QDir::homePath(), QCoreApplication::applicationName());
- s_dataLocation = WebCore::pathByAppendingComponent(dataLocation, ".QtWebKit/");
- WebCore::makeAllDirectories(s_dataLocation);
- return s_dataLocation;
-}
-
static QString s_defaultDatabaseDirectory;
static QString s_defaultLocalStorageDirectory;