1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qsensormanager.h"
5#include <QDebug>
6#include <private/qfactoryloader_p.h>
7#include <QPluginLoader>
8#include "qsensorplugin.h"
9#include <QStandardPaths>
10#include "sensorlog_p.h"
11#include <QTimer>
12#include <QFile>
13#include <QLoggingCategory>
14
15QT_BEGIN_NAMESPACE
16
17typedef QHash<QByteArray,QSensorBackendFactory*> FactoryForIdentifierMap;
18typedef QHash<QByteArray,FactoryForIdentifierMap> BackendIdentifiersForTypeMap;
19
20Q_LOGGING_CATEGORY(lcSensorManager, "qt.sensors");
21
22class QSensorManagerPrivate : public QObject
23{
24 friend class QSensorManager;
25
26 Q_OBJECT
27public:
28 enum PluginLoadingState {
29 NotLoaded,
30 Loading,
31 Loaded
32 };
33 QSensorManagerPrivate()
34 : loadExternalPlugins(true)
35 , pluginLoadingState(NotLoaded)
36 , loader(new QFactoryLoader("com.qt-project.Qt.QSensorPluginInterface/1.0", QLatin1String("/sensors")))
37 , defaultIdentifierForTypeLoaded(false)
38 , sensorsChanged(false)
39 {
40 QByteArray env = qgetenv(varName: "QT_SENSORS_LOAD_PLUGINS");
41 if (env == "0") {
42 loadExternalPlugins = false;
43 }
44 }
45 bool loadExternalPlugins;
46 PluginLoadingState pluginLoadingState;
47 QFactoryLoader *loader;
48 void loadPlugins();
49
50 // Holds a mapping from type to available identifiers (and from there to the factory)
51 BackendIdentifiersForTypeMap backendsByType;
52
53 // Holds the default identifier
54 QHash<QByteArray, QByteArray> defaultIdentifierForType;
55 bool defaultIdentifierForTypeLoaded;
56 void readConfigFile()
57 {
58 defaultIdentifierForTypeLoaded = true;
59#ifdef QTSENSORS_CONFIG_PATH
60 QString config = QString::fromLocal8Bit(QTSENSORS_CONFIG_PATH);
61#else
62 QStringList configs = QStandardPaths::standardLocations(type: QStandardPaths::ConfigLocation);
63 QString config;
64 for (const QString& c : configs) {
65 config = c + QLatin1String("/QtProject/Sensors.conf");
66 if (QFile::exists(fileName: config))
67 break;
68 }
69#endif
70 qCDebug(lcSensorManager) << "Loading config from" << config;
71 if (!QFile::exists(fileName: config)) {
72 qCDebug(lcSensorManager) << "There is no config file" << config;
73 return;
74 }
75 QFile cfgfile(config);
76 if (!cfgfile.open(flags: QFile::ReadOnly)) {
77 qCWarning(lcSensorManager) << "Can't open config file" << config;
78 return;
79 }
80
81 QTextStream stream(&cfgfile);
82 QString line;
83 bool isconfig = false;
84 while (!stream.atEnd()) {
85 line = stream.readLine();
86 if (!isconfig && line == QLatin1String("[Default]"))
87 isconfig = true;
88 else if (isconfig) {
89 //read out setting line
90 line.remove(s: QLatin1String(" "));
91 QStringList pair = line.split(QStringLiteral("="));
92 if (pair.size() == 2)
93 defaultIdentifierForType.insert(key: pair[0].toLatin1(), value: pair[1].toLatin1());
94 }
95 }
96 }
97
98 // Holds the first identifier for each type
99 QHash<QByteArray, QByteArray> firstIdentifierForType;
100
101 bool sensorsChanged;
102 QList<QSensorChangesInterface*> changeListeners;
103 QSet <QObject *> seenPlugins;
104
105Q_SIGNALS:
106 void availableSensorsChanged();
107
108public Q_SLOTS:
109 void emitSensorsChanged()
110 {
111 static bool alreadyRunning = false;
112 if (pluginLoadingState != QSensorManagerPrivate::Loaded || alreadyRunning) {
113 // We're busy.
114 // Just note that a registration changed and exit.
115 // Someone up the call stack will deal with this.
116 sensorsChanged = true;
117 return;
118 }
119
120 // Set a flag so any recursive calls doesn't cause a loop.
121 alreadyRunning = true;
122
123 // Since one [un]registration may cause other [un]registrations and since
124 // the order in which we do things matters we just do a cascading update
125 // until things stop changing.
126 do {
127 sensorsChanged = false;
128 for (QSensorChangesInterface *changes : changeListeners)
129 changes->sensorsChanged();
130 } while (sensorsChanged);
131
132 // We're going away now so clear the flag
133 alreadyRunning = false;
134
135 // Notify the client of the changes
136 Q_EMIT availableSensorsChanged();
137 }
138};
139
140Q_GLOBAL_STATIC(QSensorManagerPrivate, sensorManagerPrivate)
141
142static void initPlugin(QObject *o, bool warnOnFail = true)
143{
144 qCDebug(lcSensorManager) << "Init plugin" << o;
145 if (!o) {
146 qCWarning(lcSensorManager) << "Null plugin" << o;
147 return;
148 }
149
150 QSensorManagerPrivate *d = sensorManagerPrivate();
151 if (!d) return; // hardly likely but just in case...
152
153 if (d->seenPlugins.contains(value: o)) {
154 qCDebug(lcSensorManager) << "Plugin is seen" << o;
155 return;
156 }
157
158 QSensorChangesInterface *changes = qobject_cast<QSensorChangesInterface*>(object: o);
159 if (changes)
160 d->changeListeners << changes;
161
162 QSensorPluginInterface *plugin = qobject_cast<QSensorPluginInterface*>(object: o);
163
164 if (plugin) {
165 qCDebug(lcSensorManager) << "Register sensors for " << plugin;
166 d->seenPlugins.insert(value: o);
167 plugin->registerSensors();
168 } else if (warnOnFail) {
169 qCWarning(lcSensorManager) << "Can't cast to plugin" << o;
170 }
171}
172
173void QSensorManagerPrivate::loadPlugins()
174{
175 QSensorManagerPrivate *d = this;
176 if (d->pluginLoadingState != QSensorManagerPrivate::NotLoaded) return;
177 d->pluginLoadingState = QSensorManagerPrivate::Loading;
178
179 SENSORLOG() << "initializing static plugins";
180 // Qt-style static plugins
181 for (QObject *plugin : QPluginLoader::staticInstances())
182 initPlugin(o: plugin, warnOnFail: false /*do not warn on fail*/);
183 if (d->loadExternalPlugins) {
184 SENSORLOG() << "initializing plugins";
185 QList<QPluginParsedMetaData> meta = d->loader->metaData();
186 for (qsizetype i = 0; i < meta.size(); i++) {
187 QObject *plugin = d->loader->instance(index: i);
188 initPlugin(o: plugin);
189 }
190 }
191
192 d->pluginLoadingState = QSensorManagerPrivate::Loaded;
193
194 if (d->sensorsChanged) {
195 // Notify the app that the available sensor list has changed.
196 // This may cause recursive calls!
197 d->emitSensorsChanged();
198 }
199}
200
201// =====================================================================
202
203/*!
204 \class QSensorManager
205 \ingroup sensors_backend
206 \inmodule QtSensors
207
208 \brief The QSensorManager class handles registration and creation of sensor backends.
209
210 Sensor plugins register backends using the registerBackend() function.
211
212 When QSensor::connectToBackend() is called, the createBackend() function will be called.
213*/
214
215/*!
216 Register a sensor for \a type. The \a identifier must be unique.
217
218 The \a factory will be asked to create instances of the backend.
219
220 Sensor identifiers starting with \c generic or \c dummy are given lower
221 priority when choosing the default sensor if other sensors are found.
222*/
223void QSensorManager::registerBackend(const QByteArray &type, const QByteArray &identifier, QSensorBackendFactory *factory)
224{
225 Q_ASSERT(type.size());
226 Q_ASSERT(identifier.size());
227 Q_ASSERT(factory);
228 QSensorManagerPrivate *d = sensorManagerPrivate();
229 if (!d) return; // hardly likely but just in case...
230 if (!d->backendsByType.contains(key: type)) {
231 (void)d->backendsByType[type];
232 d->firstIdentifierForType[type] = identifier;
233 } else if (d->firstIdentifierForType[type].startsWith(bv: "generic.") ||
234 d->firstIdentifierForType[type].startsWith(bv: "dummy.")) {
235 // Don't let a generic or dummy backend be the default when some other backend exists!
236 d->firstIdentifierForType[type] = identifier;
237 }
238 FactoryForIdentifierMap &factoryByIdentifier = d->backendsByType[type];
239 if (factoryByIdentifier.contains(key: identifier)) {
240 qWarning() << "A backend with type" << type << "and identifier" << identifier << "has already been registered!";
241 return;
242 }
243 SENSORLOG() << "registering backend for type" << type << "identifier" << identifier;// << "factory" << QString().sprintf("0x%08x", (unsigned int)factory);
244 factoryByIdentifier[identifier] = factory;
245
246 // Notify the app that the available sensor list has changed.
247 // This may cause recursive calls!
248 d->emitSensorsChanged();
249}
250
251/*!
252 Unregister the backend for \a type with \a identifier.
253
254 Note that this only prevents new instance of the backend from being created. It does not
255 invalidate the existing instances of the backend. The backend code should handle the
256 disappearance of the underlying hardware itself.
257*/
258void QSensorManager::unregisterBackend(const QByteArray &type, const QByteArray &identifier)
259{
260 QSensorManagerPrivate *d = sensorManagerPrivate();
261 if (!d) return; // hardly likely but just in case...
262 if (!d->backendsByType.contains(key: type)) {
263 qWarning() << "No backends of type" << type << "are registered";
264 return;
265 }
266 FactoryForIdentifierMap &factoryByIdentifier = d->backendsByType[type];
267 if (!factoryByIdentifier.contains(key: identifier)) {
268 qWarning() << "Identifier" << identifier << "is not registered";
269 return;
270 }
271
272 (void)factoryByIdentifier.take(key: identifier); // we don't own this pointer anyway
273 if (d->firstIdentifierForType[type] == identifier) {
274 if (factoryByIdentifier.size()) {
275 d->firstIdentifierForType[type] = factoryByIdentifier.begin().key();
276 if (d->firstIdentifierForType[type].startsWith(bv: "generic.")) {
277 // Don't let a generic backend be the default when some other backend exists!
278 for (FactoryForIdentifierMap::const_iterator it = factoryByIdentifier.begin()++; it != factoryByIdentifier.end(); ++it) {
279 const QByteArray &identifier(it.key());
280 if (!identifier.startsWith(bv: "generic.")) {
281 d->firstIdentifierForType[type] = identifier;
282 break;
283 }
284 }
285 }
286 } else {
287 (void)d->firstIdentifierForType.take(key: type);
288 }
289 }
290 if (!factoryByIdentifier.size())
291 (void)d->backendsByType.take(key: type);
292
293 // Notify the app that the available sensor list has changed.
294 // This may cause recursive calls!
295 d->emitSensorsChanged();
296}
297
298/*!
299 Create a backend for \a sensor. Returns null if no suitable backend exists.
300*/
301QSensorBackend *QSensorManager::createBackend(QSensor *sensor)
302{
303 Q_ASSERT(sensor);
304
305 QSensorManagerPrivate *d = sensorManagerPrivate();
306 if (!d) return 0; // hardly likely but just in case...
307 d->loadPlugins();
308
309 SENSORLOG() << "QSensorManager::createBackend" << "type" << sensor->type() << "identifier" << sensor->identifier();
310
311 if (!d->backendsByType.contains(key: sensor->type())) {
312 SENSORLOG() << "no backends of type" << sensor->type() << "have been registered.";
313 return 0;
314 }
315
316 const FactoryForIdentifierMap &factoryByIdentifier = d->backendsByType[sensor->type()];
317 QSensorBackendFactory *factory;
318 QSensorBackend *backend;
319
320 if (sensor->identifier().isEmpty()) {
321 QByteArray defaultIdentifier = QSensor::defaultSensorForType(type: sensor->type());
322 SENSORLOG() << "Trying the default" << defaultIdentifier;
323 // No identifier set, try the default
324 factory = factoryByIdentifier[defaultIdentifier];
325 //SENSORLOG() << "factory" << QString().sprintf("0x%08x", (unsigned int)factory);
326 sensor->setIdentifier(defaultIdentifier); // the factory requires this
327 backend = factory->createBackend(sensor);
328 if (backend) return backend; // Got it!
329
330 // The default failed to instantiate so try any other registered sensors for this type
331 for (const QByteArray &identifier : factoryByIdentifier.keys()) {
332 SENSORLOG() << "Trying" << identifier;
333 if (identifier == defaultIdentifier) continue; // Don't do the default one again
334 factory = factoryByIdentifier[identifier];
335 //SENSORLOG() << "factory" << QString().sprintf("0x%08x", (unsigned int)factory);
336 sensor->setIdentifier(identifier); // the factory requires this
337 backend = factory->createBackend(sensor);
338 if (backend) return backend; // Got it!
339 }
340 SENSORLOG() << "FAILED";
341 sensor->setIdentifier(QByteArray()); // clear the identifier
342 } else {
343 if (!factoryByIdentifier.contains(key: sensor->identifier())) {
344 SENSORLOG() << "no backend with identifier" << sensor->identifier() << "for type" << sensor->type();
345 return 0;
346 }
347
348 // We were given an explicit identifier so don't substitute other backends if it fails to instantiate
349 factory = factoryByIdentifier[sensor->identifier()];
350 //SENSORLOG() << "factory" << QString().sprintf("0x%08x", (unsigned int)factory);
351 backend = factory->createBackend(sensor);
352 if (backend) return backend; // Got it!
353 }
354
355 SENSORLOG() << "no suitable backend found for requested identifier" << sensor->identifier() << "and type" << sensor->type();
356 return 0;
357}
358
359/*!
360 Returns true if the backend identified by \a type and \a identifier is registered.
361
362 This is a convenience method that helps out plugins doing dynamic registration.
363*/
364bool QSensorManager::isBackendRegistered(const QByteArray &type, const QByteArray &identifier)
365{
366 QSensorManagerPrivate *d = sensorManagerPrivate();
367 if (!d) return false; // hardly likely but just in case...
368 d->loadPlugins();
369
370 if (!d->backendsByType.contains(key: type))
371 return false;
372
373 const FactoryForIdentifierMap &factoryByIdentifier = d->backendsByType[type];
374 if (!factoryByIdentifier.contains(key: identifier))
375 return false;
376
377 return true;
378}
379
380/*!
381 Sets or overwrite the sensor \a type with the backend \a identifier.
382*/
383void QSensorManager::setDefaultBackend(const QByteArray &type, const QByteArray &identifier)
384{
385 QSensorManagerPrivate *d = sensorManagerPrivate();
386 if (!d) return; // hardly likely but just in case...
387 d->defaultIdentifierForType.insert(key: type, value: identifier);
388}
389
390
391// =====================================================================
392
393/*!
394 Returns a list of all sensor types.
395*/
396QList<QByteArray> QSensor::sensorTypes()
397{
398 QSensorManagerPrivate *d = sensorManagerPrivate();
399 if (!d) return QList<QByteArray>(); // hardly likely but just in case...
400 d->loadPlugins();
401
402 return d->backendsByType.keys();
403}
404
405/*!
406 Returns a list of ids for each of the sensors for \a type.
407 If there are no sensors of that type available the list will be empty.
408*/
409QList<QByteArray> QSensor::sensorsForType(const QByteArray &type)
410{
411 QSensorManagerPrivate *d = sensorManagerPrivate();
412 if (!d) return QList<QByteArray>(); // hardly likely but just in case...
413 d->loadPlugins();
414
415 // no sensors of that type exist
416 if (!d->backendsByType.contains(key: type))
417 return QList<QByteArray>();
418
419 return d->backendsByType[type].keys();
420}
421
422/*!
423 Returns the default sensor identifier for \a type.
424 This is set in a config file and can be overridden if required.
425 If no default is available the system will return the first registered
426 sensor for \a type.
427
428 Note that there is special case logic to prevent the generic plugin's backends from becoming the
429 default when another backend is registered for the same type. This logic means that a backend
430 identifier starting with \c{generic.} will only be the default if no other backends have been
431 registered for that type or if it is specified in \c{Sensors.conf}.
432
433 \sa {Determining the default sensor for a type}
434*/
435QByteArray QSensor::defaultSensorForType(const QByteArray &type)
436{
437 QSensorManagerPrivate *d = sensorManagerPrivate();
438 if (!d) return QByteArray(); // hardly likely but just in case...
439 d->loadPlugins();
440
441 // no sensors of that type exist
442 if (!d->backendsByType.contains(key: type))
443 return QByteArray();
444
445 //check if we need to read the config setting file
446 if (!d->defaultIdentifierForTypeLoaded)
447 d->readConfigFile();
448
449 QHash<QByteArray, QByteArray>::const_iterator i = d->defaultIdentifierForType.find(key: type);
450 if (i != d->defaultIdentifierForType.end() && i.key() == type) {
451 if (d->backendsByType[type].contains(key: i.value())) // Don't return a value that we can't use!
452 return i.value();
453 }
454
455 // This is our fallback
456 return d->firstIdentifierForType[type];
457}
458
459void QSensor::registerInstance()
460{
461 QSensorManagerPrivate *d = sensorManagerPrivate();
462 if (!d) return; // hardly likely but just in case...
463 connect(sender: d, SIGNAL(availableSensorsChanged()), receiver: this, SIGNAL(availableSensorsChanged()));
464}
465
466// =====================================================================
467
468/*!
469 \class QSensorBackendFactory
470 \ingroup sensors_backend
471 \inmodule QtSensors
472
473 \brief The QSensorBackendFactory class instantiates instances of
474 QSensorBackend.
475
476 This interface must be implemented in order to register a sensor backend.
477
478 \sa {Creating a sensor plugin}
479*/
480
481/*!
482 \internal
483*/
484QSensorBackendFactory::~QSensorBackendFactory()
485{
486}
487
488/*!
489 \fn QSensorBackendFactory::createBackend(QSensor *sensor)
490
491 Instantiate a backend. If the factory handles multiple identifiers
492 it should check with the \a sensor to see which one is requested.
493
494 If the factory cannot create a backend it should return 0.
495*/
496
497QT_END_NAMESPACE
498
499#include "qsensormanager.moc"
500

source code of qtsensors/src/sensors/qsensormanager.cpp