Plugin-based IVI Architectures with Qt

Preview:

Citation preview

Plugin-based IVI Architectures with QtVladimir Moolle, Krzysztof Krzewniak,Integrated Computer Solutions, Inc.

Plugins as such -- what are they?

• One of the ways of making an IVI system more flexible in terms of testing, deployment and maintainability

• Plugins are dynamic (shared) libraries, loaded by the application “explicitly” (not linked to), standard example -- your favorite image editor (probably) or Qt Creator

• A curious Qt-specific case -- static “plugins”, mostly an artifact of the differences between build / deploy process of monolithic and non-monolithic applications (Note / question: has anyone seen static plugins outside of Qt?)

• Note: for static VS dynamic libraries 101, you can visit:https://wiki.qt.io/How_to_create_a_library_with_Qt_and_use_it_in_an_applicationhttp://www.network-theory.co.uk/docs/gccintro/gccintro_25.html

2

Plugins in Qt the framework

• Why? Ease of extending the framework / applications (example: adding a new database driver does not involve Qt libraries’ or even application rebuild)

• Used for: database drivers (above), image formats, etc.

• Designer and Qt Creator heavily rely on plugins as well

• You can define your own plugin formats

• Note -- for the description of the mechanism, check:http://doc.qt.io/qt-5/plugins-howto.html https://wiki.qt.io/Plugins http://doc.qt.io/qt-5/plugins.html

3

Plugins in QML

• It goes without question that QML is the technology of choice for automotive IVIs, when it comes to Qt

• The “standard” QML plugins (referenced by “plugin” entries in qmldir) are QQmlExtensionPlugin-based and provide custom C++-implemented components as well as register the types; QQmlExtensionPlugin rely on the regular plugin loading mechanism (see the previous slide)

• Unlike the regular plugins (which are enumerated and loaded at startup), the QML ones have traditionally been lazy-loaded (Question to the audience: is this the case with the QML compiler?), meaning, a plugin may even never be loaded with certain execution paths (note: whole module / plugin “chains” / trees can be left out)

4

Fundamentals of a good plugin-based IVI architecture• Plugin interfaces and what the plugins supply should be chosen to match the project’s

specifics in terms of intended levels of component reusability, team setup, field deployment setup, etc.

• If possible, inter-plugin dependencies should be minimized or explicitly manifested, as otherwise deployment and API compatibility issues might arise.

5

• The part of the system responsible for loading the plugins and providing an interface the plugins can use to influence the IVI (request popups, interruptions, etc.) should be a library.This ensures plugins can be developed and tested independently (including the ability to use mock setups in case of hardware scarcity scenarios etc.)

Fundamentals of a good plugin-based IVI architecture (core functionality separation)

6

Main IVI Binary Core Library

Plugin 1

Plugin n

Fundamentals of a good plugin-based IVI architecture (IP protection)• Relying on fixed interfaces and compiled binary code, can help protect both the 3rd party

suppliers’ and the IVI vendor’s IP

7

Plugin 1 Vendor Plugin 2 VendorIVI Vendor

Plugin-to-core library interface(bi-directional)

Example IVI architecture (overview)

• To illustrate some possible approaches, an example IVI architecture was implemented

• The demo architecture does not utilize QML plugins, but rather uses QPluginLoader directly, as the plugins in the demo architecture not only provide the QML types but also enough information to compose the UI out of those types’ instances

• Three “types” of plugins are supported:• Feature plugins -- realizing the actual functionality like phone or media management• Layout plugins -- defining the way feature-provided visuals (feature previews, shortcuts,

views and popups -- more on that below) are organized on screen• Theme plugins -- responsible for customizing the common controls and providing a global

palette

8

Feature Interface(non-virtual methods stripped)class FeatureInterface{public: virtual void cleanup() {}

virtual void installTranslations(QCoreApplication *app) const { Q_UNUSED(app) } virtual void registerTypes() const {} virtual void exportContextProperties(QQmlContext *context) const { Q_UNUSED(context) }

virtual QUrl previewItemUrl() const = 0; virtual QUrl mainItemUrl() const = 0; virtual QUrl shortcutUrl() const = 0;

virtual int majorVersion() const { return 0; } virtual int minorVersion() const { return 0; }};

9

Main Layout Interface(non-virtual methods stripped)class MainLayoutInterface{public: virtual void cleanup() {}

virtual QUrl layoutRootUrl() const = 0; virtual void exportContextProperties(QQmlContext *context) const { Q_UNUSED(context) }

virtual int majorVersion() const { return 0; } virtual int minorVersion() const { return 0; }};

10

Theme Interface(non-virtual methods stripped)class ThemeInterface{public: virtual void cleanup() {}

virtual void addImageProviders(QQmlEngine *e); virtual QUrl mainThemeObjectUrl() const = 0;

virtual int majorVersion() const { return 0; } virtual int minorVersion() const { return 0; }};

11

Example IVI architecture (resource initialization, QML paths and type registration)• Plugin resources (QRC) are initialized automatically, as plugins are shared libraries

(see http://doc.qt.io/qt-5/resources.html#using-resources-in-a-library for an intro)

• The QRC file names can be the same (say, “Resource.qrc”) across different plugins, given the nature of QRC initialization in shared libraries (and plugins are just those, again)

• In contrast, QML (and not only) paths in resources should be unique (and probably, version-based) so when a new version of a plugin is loaded, there would be no confusion on the side of the resource system or the QML engine

• Note: QML type registrations are not per-engine, but rather global, i.e.

qmlRegisterSingletonType <Phone::Controller>("PhoneFeature", majorVersion(), minorVersion(), "PhoneController" , Phone::Controller::qmlInstance);

12

Example IVI architecture (the core library)• The core library registers the common QML types like:

• Panels• Buttons• ThemableItem’s -- basic Items that can be themed using enums• TextLabel’s -- basic text items with enum-based coloring

• It manages the feature model, a QAbstractListModel subclass exposing the loaded features’ properties (like main QML item’s URL)

• It provides an API for the plugins to request and dismiss popups, with the option to have the plugin notified that its popup was dismissed through a callback

• It also takes care of providing a theme manager object as well as a base class for new theme definitions

13

Plugin loading

• Code flow, simplified: QPluginLoader loader(pluginsDir.absoluteFilePath(fileName)); const QJsonObject metaData = loader.metaData(); auto it = metaData.find(QLatin1String("IID")); if (it != metaData.constEnd()) { const QString iid = it.value().toString(); if (iid.compare(QLatin1String(FeatureInterface_iid )) == 0) { FeatureInterface *interface = qobject_cast<FeatureInterface*>(loader.instance()); if (interface) { interface->installTransaltions(qApp); interface->registerTypes(); interface->exportContextProperties(engine->rootContext()); m_featureModel->addFeature(interface); } } //Other interface iid cases }

14

Plugins: physical structure(the perils of double moc-ing)

• Note: in case of QObject-based plugin interfaces, be sure to not have their header files in HEADERS in both the plugins and the core library, as that would lead to MOC-generated object / binary code linked into both as well

• Consequently, do not share the plugin interface headers via .pri files, but rather use INCLUDEPATH

• Lastly, for plugins to even be able to link, the MOC-produced code for the interface classes should reside in a shared library (in the demonstrated architecture, the same applies to non-QObject-based interfaces and the core library)

15

Plugins: physical structure(continued)

• The arrows in the diagram below show the link- and run-time dependencies of the plugin code on the shared code in the core library

16

Core Library Binary code for the plugin interface Plugin 1 .Binary code for the plugin’s

implementation of the interface

Plugin n .Binary code for the plugin’s implementation of the interface

Demo: empty IVI

• No layout• No theme• No features

17

Demo: a single feature in a layout, themed

• A phone management feature(just a mock)

• Wouldn’t work on its own, so a tiled layout is used

• Requires a theme to be usable

18

Demo: an alternative layout

• Another layout plugin added and dynamically picked

• Switching between the layouts on the fly is perfectly possible and seamless

19

Demo: another theme

• Another theme added

• Themes can be changed dynamically

20

Demo: a pure QML plugin

• Extra features can be added as pure QML plugins

• Pure QML plugins don’t get to add any context properties and custom C++ types

21

Demo: reloading a plugin

22

• Plugins can be reloaded, if a new version is available

• Technically, this leaves the plugin library in application memory, but all data structures (most importantly, QML items) created by the old plugin are cleaned up (garbage collected)

Thank you!The authors can be reached at:

● vmoolle@ics.com● kkrzewniak@ics.com

The source and these slides are soon coming to https://github.com/vmoolle/qtsummit2017demo

Questions?

Recommended