1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711
|
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:FDL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
\group servicefw
\title Service Frameworks Classes
A set of APIs to that allows clients to discover and instantiate
arbitrary services.
*/
/*!
\page service-frameworks.html
\title Qt Service Framework
\brief A set of Qt APIs to that allows clients to discover and instantiate
arbitrary services.
\ingroup technology-apis
The Qt Service Framework allows clients to discover and instantiate
arbitrary services.
\tableofcontents
\section1 Introduction
The Qt Service Framework defines a unified way of finding, implementing and
accessing services across multiple platforms.
Due to the service frameworks knowledge of service interfaces, their
versions, and QObject-based introspection, it may even be used to unify and
access multiple platform specific service implementations via the same
Qt-based client application.
\section1 Getting Started
To load the Qt Service Framework module into your .qml files, add the following
\qml
import QtServiceFramework 5.0
\endqml
For C++ files you will need to add the directive
\code
#include <QtServiceFramework>
\endcode
And for linking against the module add this to your qmake .pro file
\code
QT += serviceframework
\endcode
\section1 Overview
A service is an independent component that allows a client to perform a
well-defined operation. Clients can find services based on their name and
version as well as the interface that is implemented by the service object.
Once the service has been identified the framework starts the service and
returns a pointer to it. QServiceManager is the main interface through
which clients can access the mentioned framework functionality. In
addition services themselves may also act as clients to the service
framework by requesting other services installed on the system.
Service provider are implemented via plug-ins. QServicePluginInterface
defines the main interface for each plug-in.
In order to avoid that clients have to link against service specific
libraries each service object must be derived from QObject. Therefore the
QMetaObject system can be used to dynamically discover and invoke the
service's capabilities.
To achieve the best level of access via the Qt meta object system services
should be implemented in such a way that their entire functionality is
accessible via signals, slots, properties or invokable functions
(see Q_INVOKABLE macro for more details).
Each service plug-in implements one service only but can provide multiple
implementations for multiple interfaces.
Therefore a service (plug-in) can retain a certain level of backwards
compatibility even if the main service interface breaks in such a way that
a new interface name has to be used. Existing clients can still use the
previous version of service interface whereas new clients can utilize the
new interface.
Services can also include remote processes. By registering with the
service manager processes can communicate via signals, slots,
invokable functions and properties as if they were local objects.
Services can choose to be either shared between all clients, or
unique to that client.
\section1 Using the Framework
This section assumes that the user wants to access the \e FileStorage
service which offers an implementation for the \e com.nokia.qt.examples.FileStorage
interface The service framework enables multiple ways of accessing those
implementations.
QServiceManager is the main class to lookup and instantiate services.
Services can be found by constraining the search via service meta data or
by using the default lookup mechanism.
\section2 Verbose Lookup
The client code has precise knowledge of the service and its interfaces.
\code
QServiceManager manager;
QServiceFilter filter("com.nokia.qt.examples.FileStorage");
filter.setServiceName("FileStorage");
// find services complying with filter
QList<QServiceInterfaceDescriptor> foundServices;
foundServices = manager.findInterfaces(filter);
Q_ASSERT(foundServices.count());
// instantiate the FileStorage object
QObject *fileStorage;
fileStorage = manager.loadInterface(foundServices.at(0));
\endcode
\section2 Default Lookup
It is assumed that the client has knowledge of the interface but does not really care
about the specific type or version of the service implementing the interface. In such cases the default
service lookup can be utilized to create a service object instance.
\code
QServiceManager manager;
manager.setInterfaceDefault("FileStorageService", "com.nokia.qt.examples.FileStorage");
\endcode
The above call to \l QServiceManager::setInterfaceDefault() registers the \e FileStorageService as default implementation.
Whenever a client asks for an implementation of \e com.nokia.qt.examples.FileStorage the \e FileStorageService
service will be loaded. If (at the time of this call) the \e FileStorageService provides multiple registered implementations/versions for the
same interface the latest version becomes the default. Therefore subsequent versions of the same interface
must always be binary compatible to previous versions.
The current scope of the service manager object determines whether the default assignment is valid for all users
or whether it is valid for the current user only. The system default is used if the user
scope has not been defined. This enables users to customize their personal preferences.
By default the first service installing a so far unknown interface becomes the system wide default selection.
\section3 \b{QObject based services}
This is the most common way of interacting with services.
\code
storage = manager.loadInterface("com.nokia.qt.examples.FileStorage");
if (storage)
QMetaObject::invokeMethod(storage, "deleteFile", Q_ARG(QString, "/tmp/readme.txt"));
\endcode
The above invocation of the file storage object's deleteFile() function is done via the service's
QMetaObject. The client does not require any knowledge of the objects actual type and therefore
does not have to link against a service specific library.
\section3 \b{Typed services}
So far all lookup mechanism returned a QObject pointer. This pointer can be
utilized by introspecting the object, using Qt's meta object system.
However in some use cases it may be more convenient to
directly interact with the service object by including the service header
and/or linking against the service provider. The main advantage is compile time checking.
Its disadvantage is that client and service must share the implementation of the service object via a library
they link against or via a common header file. Note that such sharing breaks the fundamental ServiceFramework
principle of separating clients from service as changes of the service type may require changes to both, services and clients.
The subsequent code snippet demonstrates how this may look like:
\code
#include <filestorage.h>
...
QServiceManager manager;
FileStorage *storage = 0;
...
storage = manager.loadLocalTypedInterface<FileStorage>("com.nokia.qt.examples.FileStorage");
if (storage)
storage->deleteFile("/tmp/readme.txt");
\endcode
\section1 Service Scope
The QServiceManager operates in either \l{QService::UserScope}{User scope}
or \l{QService::SystemScope}{System scope}. By default, it operates
in user scope. The choice of scope affects whether registered services are
available system-wide or only to the current user, and whether service and
interface lookups are limited to system-wide service or whether the current
user's together with system service configurations are considered.
\section2 User Scope
In user scope, services are registered in a storage location specific to
the current user. When a default service is set for an interface using
\l{QServiceManager::setInterfaceDefault()}{setInterfaceDefault()}, the
referenced service can be either a user-specific or system-wide service.
For service and interface lookups, a manager will first search the
user-specific services; if the requested component is not found, the
manager then searches the system-wide services, if the user has
sufficient permissions to do so.
The \l{QServiceManager::serviceAdded()} and \l{QServiceManager::serviceRemoved()}
notifications are emitted when services are added or removed from either
the user-specific or system-wide services. These signals have a \c scope
parameter to indicate the scope in which the service was added or removed.
(Note the system-wide service notifications are only available if the user
has sufficient permissions to access the system-wide service storage.)
\section2 System Scope
In system scope, services are registered in a system-wide storage location.
The manager does not access user-specific services for any operations.
Service and interface lookups fail if the requested services are not found
in the system-wide service storage. Service registration is performed in
the system-wide storage.
If \l{QServiceManager::setInterfaceDefault()}{setInterfaceDefault()} is
called for a user-specific service, the operation fails.
Also, the \l{QServiceManager::serviceAdded()} and \l{QServiceManager::serviceRemoved()}
notifications are only emitted for system-wide services.
\section1 Adding and Removing of Services
New services can be installed and removed at runtime. An XML file is used
to describe the service meta data and links the service code to its meta
description.
\section2 XML Format
Services are installed via an XML file which describes the meta data and
location of the service. The XML file can be described via the following
DTD:
\code
<!ELEMENT SFW ( service ) >
<!ATTLIST SFW version (1.0|1.1) #REQUIRED >
<!ELEMENT service ( name, filepath | ipcaddress, description?, interface+ ) >
<!ELEMENT description ( #CDATA ) >
<!ELEMENT filepath ( #PCDATA ) >
<!ELEMENT ipcaddress ( #PCDATA ) >
<!ELEMENT interface ( name, version, description?, capabilities?, customproperty* ) >
<!ELEMENT capabilities ( #PCDATA ) >
<!ELEMENT name ( #PCDATA ) >
<!ELEMENT version ( #PCDATA ) >
<!ELEMENT customproperty ( #CDATA ) >
<!ATTLIST customproperty key NMTOKEN #REQUIRED >
\endcode
The elements and attributes have the following meanings:
\table
\header
\li Element \li SubElement \li Description
\row
\li SFW
\li
\li The service framework XML version tag that encapsulates the service XML. Must provide the
version attribute that follows the \e major.minor notation and must equate to supported
Qt Service Framework versions. This means the minimum version is 1.0 however users are
recommended to always specify the highest available version.
\row
\li service
\li
\li The \e service tag can contain an arbitrary number of \e interface tags and one description tag.
\row
\li "
\li description
\li A user readable description of the purpose of the service.
\row
\li "
\li filepath
\li The absolute path and name of the plug-in to be loaded when this
service is requested. Alternatively if the plug-in name only is
provided the standard library paths (see QCoreApplication::libraryPaths())
are used to find the plug-in.
Note that if the plugin name is given only, platform specific
parts such as the suffix ".dll" and ".so" or plugin prefix "lib"
should be removed to enable cross platform resolution. QLibrary
is used to determine the platform specific parts of the plugin.
\row
\li "
\li ipcaddress
\li The socket name or path that the inter-process service will be published
on that will provide clients with remote access. Should be the same name
as the executable for the service without any suffix such as ".exe" etc.
\row
\li "
\li name
\li The name of the service.
\row
\li interface
\li
\li The \e interface describes the properties of the interface.
\row
\li "
\li capabilities
\li This property is a list of arbitrary strings which are
interpreted as permissions/capabilities. The list elements are
comma-separated and spaces after commas are not permitted.
This list can be empty.
\row
\li "
\li name
\li The name of the interface using the Java class name notation. (e.g. com.nokia.qt.TestService)
\row
\li "
\li version
\li This property contains the interface and implementation version.
The version tag follows the \e major.minor notation. The major
version indicates the interface version the minor version the
implementation version.
The version number \b must be greater than 1.0. The version
cannot be less than 1.0 because the Service Framework is
dependent on the fact that services must be binary compatible
between major versions, and services with versions less than 1.0
are unlikely to be binary compatible with later versions.
\row
\li "
\li description
\li A user readable description of the purpose of the interface.
\row
\li "
\li customproperty
\li An implementation specific key value pair which can be used for
filtering or as description.
\endtable
An example for a valid XML service description could be the following \e TestService:
\code
<?xml version="1.0" encoding="utf-8" ?>
<SFW version="1.1">
<service>
<name>TestService</name>
<filepath>testserviceplugin</filepath>
<description>Test service description</description>
<interface>
<name>com.nokia.qt.ILocation</name>
<version>1.4</version>
<capabilities></capabilities>
<description>Interface that provides location support</description>
</interface>
<interface>
<name>com.nokia.qt.ILocation</name>
<version>1.5</version>
<capabilities></capabilities>
<description>Interface that provides location support</description>
</interface>
<interface>
<name>com.nokia.qt.ISysInfo</name>
<capabilities>ReadUserData</capabilities>
<version>2.3</version>
<description>Interface that provides system information support</description>
<customproperty key="key1">value1</customproperty>
<customproperty key="key2">value2</customproperty>
</interface>
</service>
</SFW>
\endcode
\section1 Tools for XML Generation
The framework includes a GUI tool under \tt tools/servicexmlgen for
generating and inspecting service XML files. This makes it easy to enter
service metadata and interface details and generate the appropriate XML to
describe the plugin or IPC based service. It can also be used to load and
inspect existing service XML files.
Note that the tool will default to the highest known existing Qt Service Framework
version as the XML version attribute and subsequent saves on loaded files will
enforce this default version.
Here is a screenshot of the application, loaded with the \e TestService XML
description provided above.
\image servicexmlgen.png
\section1 Installing the Service at Runtime
New services can be added and removed at any time via QServiceManager::addService()
and QServiceManager::removeService().
\section1 Identifying Services
Each implementation is identified by a service name, an interface name and
its version. This information is encapsulated by
QServiceInterfaceDescriptor which can be used to request references to
service objects.
QServiceFilter simplifies the lookup of already installed services.
Developers specifies the criteria used during the meta data lookup.
The subsequent example demonstrates the interaction between
QServiceInterfaceDescriptor and QServiceFilter by creating references to
all services that implement the interface \e com.nokia.qt.ILocation:
\code
QServiceManager mgr;
QServiceFilter filter;
filter.setInterface("com.nokia.qt.ILocation");
QList<QServiceInterfaceDescriptor> list = mgr.findInterfaces(filter);
for(int i = 0; i < list.size(); i++) {
QObject *serviceObject;
serviceObject = mgr.loadInterface(list[i]);
// returned object owned by client
if (serviceObject)
serviceObject->setParent(this);
}
\endcode
\section2 Upgrading Services
There are two ways in which to upgrade a service. The first is an
incremental approach whereby QServiceManager::addService() is used to
register an XML descriptor whose service name already exists but defines
new interface implementations. For example an already existing service,
"ovi" may define version 1.0 of interface,"IDownload".
QServiceManager::addService() is then called with an XML descriptor that
declares itself as belonging the "ovi" service, but implements version 1.1
of the interface "IDownload". Both implementation versions will be
available for use.
The second method is a replacement approach whereby an existing service is
completely removed and replaced by a new service.
As an example the already existing "ovi" service may implement interface
"IDownload" version 1.0, the new "ovi" service may implement "IDownload"
version 1.0 and version 1.1. In this case the old service implementation
must be first be removed using QServiceManager::removeService() to make
way for the new service implementation.
\section1 Out of Process Services
Qt Service Framework provides a mechanism for out of process services
so that clients can remotely load interfaces. These inter-process
services are deployed similarly to local services, using the IPC address
tag from the XML description and calling QRemoteServiceRegister::publishEntries()
to add the service to the remote services manager. Clients access services
via the metaobject similarly to in-process services and each remote service
is represented as a QRemoteServiceRegister::Entry by using
QRemoteServiceRegister::createEntry(). The remote dialer service example
demonstrates using a out of process service.
Inter-process services are deployed using a variety of different IPC mechanisms
available on the current platform and as such may inherit several limitations. For
some linux environments services can published using QtDBus otherwise it
falls back on QLocalSocket for inter-process communication.
\section2 D-Bus Services
The QtDBus module is used to provide IPC in correspondence to the Qt Service
Framework architecture and provides access to signals, slots, invokable methods
and properties.
The D-Bus protocol requires concept identifiers that represent D-Bus objects:
service names, object paths, and interfaces. D-Bus objects are registered using
a combination of the service description supplied in the service XML file. An
example of this, using the previous sample XML description, is provided below.
\table 90%
\header \li D-Bus Concept \li Derived Name
\row \li Service Name \li "com.qtmobility.sfw.TestService"
\row \li Object Path \li "/com/nokia/qt/ILocation/1/4/"
\row \li Interface \li ""
\endtable
\section3 Limitations
When using integer types for arguments to signals and slots,
bass types as defined by http://doc.qt.nokia.com/4.7/qdbustypesystem.html.
For example, quint64 is generally equivalent to qulonglong, but
all unsigned 64 bit values must be defined as qulonglong or they will
not work with the dbus implementation. For more details and the current
state of the limitation please refer to bug
\l {http://bugreports.qt.io/browse/QTMOBILITY-1694}{QTMOBILITY-1694}.
A current known limitation for Qt Service Framework using QtDBus for IPC is
that enumerators cannot be read due to lack of support on D-Bus. This will be
added in future versions once the QtDBus module enables enumerator support. A
current known workaround is to manually define and use integers as demonstrated
in the \l{Service Framework using QML Example}{Declarative Serviceframework
Dialer} example. Furthermore, due to the nature of IPC, pointers to objects
cannot be passed between services and clients. Unfortunately, this also means
that anything wrapped in a typedef macro cannot be communicated effectively
between processes.
\section3 Service Autostart
D-Bus services inherit automatic start support by providing .service files to the
D-Bus daemon search paths. Aside from producing these files manually, the
servicefw tool provides an option to generate the corresponding files inside
the local user D-Bus folder for convenience. This will allow all client
requests to automatically startup the service if it isn't already running.
Consequently, once every client has closed its service instance the service will
be automatically terminated after invoking any slots connected to notification signals.
Running the following command will enable rendezvous for D-Bus IPC.
\code
./servicefw dbusservice <service-xml-file> <service-file>
\endcode
The .service files will typically be generated in the $home/.local/share/dbus-1/services
directory unless the $$XDG_DATA_HOME environment variable is set. If the --system
option is used the tool will generate the file inside /usr/share/dbus-1/services if
the user permissions are met.
Note that in order for the autostart feature to function correctly, the service
needs to be either pre-registered or registered at run-time so that clients can use
a QServiceManager to discover the IPC interfaces that invoke the D-Bus service files.
This is usually done on deployment by adding services through the servicefw tool.
\section2 Local Socket
On platforms that do not provide D-Bus or do not use it, the
underlying IPC mechanism utilized is a local socket based protocol.
\section3 Limitations
Similar to the other IPC mechanisms, passing object pointers or typedefs will not
work on local socket. Local socket also requires the executable for the service to
be installed somewhere in your PATH for autostart to work. Not all platforms support
all fields on the QRemoteServiceRegisterCredentials and will return -1 in unsupported
fields.
\section3 Service Autostart
This mechanism provides automatic service startup. The <ipcaddress> tag
must be set to the executable filename. For example
<ipcaddress>xyzabc</ipcaddress> must be used if the executable is xyzabc,
or xyzabc.exe on windows systems. The PATH is searched for the executable.
If the executable is not found, or the service does not start, then
the error is reported to the client.
\section3 Service Registration
All services must be registered. The 'servicefw' tool registers xml
files. It must be run before a service can be used. For example:
\code
servicefw add <service xml file>
\endcode
\section3 Service Security
Service objects can filter the clients that are allowed to connect to them.
This is done by creating an invokable constructor that has a
QServiceClientCredentials as its first and only paramter. For example:
\code
class ExampleService : public QObject
{
Q_OBJECT
public:
ExampleService(QObject* parent = 0)
: QObject(parent)
{
// this constructor will not be called
}
Q_INVOKABLE ExampleService(QServiceClientCredentials *creds)
: QObject(0)
{
if (creds->getUserIdentifier() == 0)
creds->setClientAccepted(true);
else
creds->setClientAccepted(false);
}
};
\endcode
The new invokable constructor will be called instead of the default
constructor. Client credentials are passed in via the QServiceClientCredetials
class. If the client wishes to authorize the connection it must call either
setClientAccepted(true) or call setClientAccepted(false) to reject the client.
If the client is rejected the constructor should return immediatly, and object
will be destroyed.
If the object is a global object multiple clients can connect to the same
object. On construction the secure constructor will be called. For subsequent
client connections the invokable method "void
verifyNewServiceClientCredentials(QServiceClientCredentials *creds)"
will be called to authenticate new client connections. For example a global
class maybe defined as:
\code
class GlobalService : public QObject
{
Q_OBJECT
public:
GlobalService(QObject* parent = 0)
: QObject(parent)
{
// this constructor will not be called
}
Q_INVOKABLE GlobalService(QServiceClientCredentials *creds)
: QObject(0)
{
if (creds->getUserIdentifier() == 0)
creds->setClientAccepted(true);
else
creds->setClientAccepted(false);
}
Q_INVOKABLE void verifyNewServiceClientCredentials(QServiceClientCredentials *creds)
{
if (creds->getUserIdentifier() == 0)
creds->setClientAccepted(true);
else
creds->setClientAccepted(false);
}
};
\endcode
For global objects, when the first client connects the secure
constructor is called. Subsequent connections will result in
the verifyNewServiceClientCredentials being called. When the
last client disconnected the object will be destroyed, and
the constructor will be called when the next client connects.
\section3 Service Security Filters
The service can install a security filter to reject connections from
some clients on initial connection. Service security described above allows
this to be controlled per object. This is implemented on D-Bus and
local socket implementations of IPC.
\code
void securityFilter(QServiceClientCredentials *creds)
{
if (creds->getUserIdentifier() == 0) {
creds->setClientAccepted(true); // accept the connection
} else {
creds->setClientAccepted(false); // reject the connection
}
}
\endcode
By calling QServiceClientCredentials::setClientAccepted the connection
can be terminated or accepted. Certain platforms do not provide all
the results, and undefined values are set to -1. Registration of the filter is done by
calling QRemoteServiceRegister::setSecurityFilter(). Only 1 filter maybe installed
at one time.
\section2 Error handling
Out of process services behave similarly to local services, with one
exception. There can be IPC errors, or the remote service can
terminate unexpectedly. QObjects returned by the service manager for
out of process services have an additional signal created,
errorUnrecoverableIPCFault(QService::UnrecoverableIPCError) which the
client must connect to. If an error occurs the object must be
destroyed; no further calls can be made. The error recovery is left up to
the client application.
\section1 Main Classes
\annotatedlist servicefw
\section1 QML Elements
The Qt Service Framework offers discovery and selection of services through declarative
UI by providing service and service list elements. Detailed information can be found
at \l{QML Service Framework Plugin}.
\annotatedlist qml-serviceframework
\section1 Examples
\list
\li \l{dialer}{Declarative Serviceframework Dialer}
\endlist
*/
|