Plasma Plugin Loading
Sebastian Kügler
sebas at kde.org
Tue Sep 2 01:14:44 UTC 2014
Hi,
I've seen that Aaron asked about the way we want to load plugins, and pointed
out a number of different ways this is currently done. Since I've worked a bit
on these bits last year, I thought I'd give some background information and
propose a strategy forward -- nothing set in stone, but as a base for further
discussions. It does, at least, make sense to me. :)
TL;DR:
- the transition from KService / ksycoca towards KPluginInfo is not finished
yet
- for binary plugins, we do not need KService / ksycoca anymore, metadata is
queried directly from the plugin.so file's metadata section
- the APIs necessary to simplify Plasma::PluginLoader and our installation of
non-binary plugins are there, we should be able to transition away from
ksycoca "pretty easily" by querying the metadata.desktop files inside the
packages directly
First, quick background. Qt changed the way plugins are loaded in Qt 5. Our
old infrastructure has been updated to use Qt's new plugin mechanism
internally. This allows to bake metadata directly into the plugin's binary and
load it. This has mostly been a transparent change for creating plugins, since
we were able to change the macros to create the new Qt plugins. KPluginLoader
and KPluginFactory are basically handling this transparently. For loading
plugins, the KService::List-based APIs have been deprecated, recommended is
new API in KPluginTrader::query, operating on KPluginInfo instead of KService,
in essence, KServiceTypeTrader -> KPluginTrader.
The change for plugins is that at build-time, we're now converting the
.desktop file to json, and bake that information into the plugin through Qt5's
new standard mechanism. (In Plasma, that's the _WITH_JSON C++ macros and the
kservice_desktop_to_json() cmake macro handling that.) We do still install the
metadata.desktop file into the services directory, in order to keep
KServiceTypeTrader working (see plasma_install* cmake macros).
For now, KPluginTrader is not a complete replacement for all our needs. Two
things especially:
- It's slower than ksycoca. In order to query metainformation, it needs to
read it from every plugin. This scales linearly with the size of the plugin
dir. We're installing plugins into subdirectories in KF5, in part to reduce
the cost of plugin loading. In Plasma, we install (binary) plugins into
subdirectories based on their servicetype. I'm not privy to details, dfaure
has ideas about this. Also, on non-rotational media, this is not much of an
issue (relatively small amounts of data read, lots of disk seeks). Rotating
media suck pretty much exactly what one would expect (in the range of 3-7ms
per plugin queried, disk caches alleviate cases where the same plugins are
read multiple times. Ultimately, the idea is to create a cache, but not
ksycoca -- ask dfaure.
- KPluginTrader only loads .so files. Plasma uses a lot of non-binary plugins.
In these cases, we need the KService-based API (KServiceTypeTrader and
friends) right now. In Plasma::PluginLoader, we're using KPluginTrader (so
KPluginInfo-based API) for binary plugins such as DataEngines and
PackageStructures, and KServiceTypeTrader for non-binaries -- applets and
packages in general. The transition from KService to KPluginInfo (and thus
away from ksycoca) there is not finished yet.
So for binary plugins, we have a way now to avoid KService and ksycoca. In
Plasma, we use KService for two things: querying and loading its KPluginInfo.
The querying in KPluginTrader can operate on KPluginInfo lists since 5.0
(KPluginInfo::List KPluginTrader::query(const QString &subDirectory, const
QString &servicetype, const QString &constraint)). This function walks over
the installed plugins in a given subdirectory under Qt's plugin pathes
(QCoreApplication::libraryPaths()), and loads all the plugins to retrieve the
metadata; creates a KPluginInfo::List from that metadata, then it filters it
based on the constraints.
We can now change Plasma::PluginLoader away from ksycoca by creating a list of
KPluginInfos from all the metadata.desktop files in our installation paths and
get back a list filtered on constraints. That's basically replicating
KPluginTrader::query(), to use metadata.desktop files and populate a
KPluginInfo::List from that, instead of constructing KPluginInfos from
QPluginLoader::metaData(). This would, I think, be a logical next step.
One thing we might run into here is that our servicetypes have custom keys
that are not known to KPluginInfo, we're interested in the type information of
our custom keys, especially. We do still have the service definitions with
that info, supposedly we can load this from there.
That means we can use a mechanism similar to the Qt one to query plugins and
then load them, KService would be out of the picture, so would ksycoca be --
we can use the query language parser without KService.
KPluginTrader::applyConstraints(KPluginInfo::List &list, QString constraints)
is indeed public API. That's the the really complex piece of code. The rest is
basically looking up files in a bunch of directories.
The upside is that we can then remove the separately installed .desktop files
in the services directories, and packages would be entirely standalone, no
ksycoca runs necessary anymore, installing a package is simply a matter of
unzipping it into the right package directory, removing it also becomes
easier, and we have less problems with stale or outdated service files around.
Regarding the packages and plugins itself, this is a fully transparent change.
It also means that plasmapkg can be cut down a bit, likely more cleanups can
be done in other places. Also, less deprecation warnings.
I think my brain is empty now. :)
Cheers,
--
sebas
http://www.kde.org | http://vizZzion.org | GPG Key ID: 9119 0EF9
More information about the Plasma-devel
mailing list