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 | |
15 | QT_BEGIN_NAMESPACE |
16 | |
17 | typedef QHash<QByteArray,QSensorBackendFactory*> FactoryForIdentifierMap; |
18 | typedef QHash<QByteArray,FactoryForIdentifierMap> BackendIdentifiersForTypeMap; |
19 | |
20 | Q_LOGGING_CATEGORY(lcSensorManager, "qt.sensors" ); |
21 | |
22 | class QSensorManagerPrivate : public QObject |
23 | { |
24 | friend class QSensorManager; |
25 | |
26 | Q_OBJECT |
27 | public: |
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 | |
105 | Q_SIGNALS: |
106 | void availableSensorsChanged(); |
107 | |
108 | public 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 | |
140 | Q_GLOBAL_STATIC(QSensorManagerPrivate, sensorManagerPrivate) |
141 | |
142 | static 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 | |
173 | void 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 | */ |
223 | void 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 | */ |
258 | void 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 | */ |
301 | QSensorBackend *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 | */ |
364 | bool 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 | */ |
383 | void 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 | */ |
396 | QList<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 | */ |
409 | QList<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 | */ |
435 | QByteArray 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 | |
459 | void 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 | */ |
484 | QSensorBackendFactory::~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 | |
497 | QT_END_NAMESPACE |
498 | |
499 | #include "qsensormanager.moc" |
500 | |