| 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 | |