Likely Solution in QQmlEngine
The following design is the result of a BoF at the Qt Contributor Summit 2013, Bilbao:
QQmlEngine::setUrlInterceptor(QQmlAbstractUrlInterceptor*) QUrl QQmlAbstractUrlInterceptor::interceptUrl(url, type) qmlError(activeLoader) << "needs more permissions";
Fallback components may be loaded instead
QQml(Abstract)UrlInterceptor is private API in 5.1, if it has users, it will become public API in Qt 5.2. This means we have until ~October to check and test wether this API is sufficient for our usecase and to make possible changes. After that, it's set in stone.
Hook into "import"
Plasma must be able to register some custom hook c++ code to be executed during the parsing of the "import" keywork in qml.
The relevant code is in bool QQmlTypeLoader::Blob::addImport(const QQmlScript::Import &import, QList<QQmlError> *errors) in qtdeclarative/src/qml/qml/qqmltypeloader.cpp. The bool return value is used to signal an error when loading fails or is denied. Access to certain internals will be required; this can be seen by the use of methods such as finalUrl(), locateQmlDirectory() and addLibraryImport() in the current code. Significant classes in the import loading include QQmlImportDatabase and QQmlImports.
The use of that is twofold: fallback imports and conditional imports.
A subset of the Plasma components are platform specific (for instance optimized for touchscreens) but not all of them. We need a mechanism to be able to override an import directory with another one. Preferable files will be loaded from the other one, and fallback to the normal directory if not found. This will permit having just few "touch specific" components files while sharing 90% of the components code across all platforms.
In order to restrict applications or components in general, a security mechanism is needed in Qt. This should be implemented in collaboration with upstream Qt The basic design should be the following:
- In the import code path, the import is either done right away (current case), or it uses an optional import policy agent, which checks if the application or component has sufficient privileges, and either allows or denies the import
- The policy agent is replaceable, much like QNetworkAccessManager: QQmlImportManager (?)
- import manager is kept minimal in Qt API, but flexible in reimplementation
- different policies for subsets of the scenegraph are possible, for example per plasmoid import restrictions
- detailed failure information import failures can be handled gracefully by the application
- import performance in current case should not suffer
Plasma Implementation Bits
On the Plasma side, this needs
- signing of Plasmoids and other components (clients)
- permission validation extensions in imports metadata
- client UI for validation feedback in Plasma/Shell package
- an implementation of QQmlImportManager using the above parts
Ideas for evaluating performance with or without import manager:
- instrument a minimal binary that loads a QML file, measure load performance, measure performance with and without overridden QQmlImportManager
- Generate 10000 files that each import a bunch of modules, put them in a ListView, model: 10000