1/****************************************************************************
2**
3** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtSystems module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL21$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 or version 3 as published by the Free
20** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22** following information to ensure the GNU Lesser General Public License
23** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25**
26** As a special exception, The Qt Company gives you certain additional
27** rights. These rights are described in The Qt Company LGPL Exception
28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29**
30** $QT_END_LICENSE$
31**
32****************************************************************************/
33
34#include "qdeviceinfo_linux_p.h"
35
36#if !defined(QT_NO_OFONO)
37#include "qofonowrapper_p.h"
38#endif // QT_NO_OFONO
39
40#if defined(QT_USE_SSU)
41#include <ssudeviceinfo.h>
42#endif // QT_USE_SSU
43
44#include "qscreensaver_linux_p.h"
45#include <QNetworkInfo>
46
47#include <QtCore/qdir.h>
48#include <QtCore/qmetaobject.h>
49#include <QtCore/qprocess.h>
50#include <QtCore/qregularexpression.h>
51#include <QtCore/qtextstream.h>
52#include <QtCore/qtimer.h>
53#include <QtCore/qstandardpaths.h>
54
55#include <fcntl.h>
56#include <linux/videodev2.h>
57#include <sys/ioctl.h>
58#include <sys/types.h>
59#include <sys/stat.h>
60#include <QUuid>
61#include <QCryptographicHash>
62
63#if !defined(QT_NO_DBUS)
64#include <QtDBus/QDBusInterface>
65#include <QtDBus/QDBusReply>
66#include <QtDBus/QDBusConnection>
67#include <QtDBus/QDBusAbstractInterface>
68#include <QtDBus/QDBusError>
69#include <QtDBus/QDBusMessage>
70#endif
71
72QT_BEGIN_NAMESPACE
73
74QDeviceInfoPrivate::QDeviceInfoPrivate(QDeviceInfo *parent)
75 : QObject(parent)
76#if !defined(QT_SIMULATOR)
77 , q_ptr(parent)
78#endif // QT_SIMULATOR
79 , watchThermalState(false)
80 , imeiBuffer(QStringList())
81 , uniqueDeviceIDBuffer(QString())
82 , timer(0)
83 , boardNameString(QString())
84 , osName(QString())
85#if !defined(QT_NO_OFONO)
86 , ofonoWrapper(0)
87#endif // QT_NO_OFONO
88 ,connectedBtPower(0)
89 ,btPowered(0)
90{
91}
92
93bool QDeviceInfoPrivate::hasFeature(QDeviceInfo::Feature feature)
94{
95 switch (feature) {
96 case QDeviceInfo::BluetoothFeature:
97 if (QDir(QStringLiteral("/sys/class/bluetooth/")).entryList(filters: QDir::Dirs | QDir::NoDotAndDotDot).size() > 0)
98 return true;
99 return false;
100
101 case QDeviceInfo::CameraFeature: {
102 const QString devfsPath(QStringLiteral("/dev/"));
103 const QStringList dirs = QDir(devfsPath).entryList(nameFilters: QStringList() << QStringLiteral("video*"), filters: QDir::System);
104 foreach (const QString &dir, dirs) {
105 QFile dev(devfsPath + dir);
106 if (!dev.open(flags: QIODevice::ReadWrite))
107 continue;
108 struct v4l2_capability capability;
109 memset(s: &capability, c: 0, n: sizeof(struct v4l2_capability));
110 if (ioctl(fd: dev.handle(), VIDIOC_QUERYCAP, &capability) != -1
111 && (capability.capabilities & V4L2_CAP_VIDEO_CAPTURE) == V4L2_CAP_VIDEO_CAPTURE) {
112 return true;
113 }
114 }
115 return false;
116 }
117
118 case QDeviceInfo::FmRadioFeature:
119 if (QDir(QStringLiteral("/sys/class/video4linux/")).entryList(nameFilters: QStringList() << QStringLiteral("radio*")).size() > 0)
120 return true;
121 return false;
122
123 case QDeviceInfo::FmTransmitterFeature: {
124 const QString devfsPath(QStringLiteral("/dev/"));
125 const QStringList dirs = QDir(devfsPath).entryList(nameFilters: QStringList() << QStringLiteral("radio*"), filters: QDir::System);
126 foreach (const QString &dir, dirs) {
127 QFile dev(devfsPath + dir);
128 if (!dev.open(flags: QIODevice::ReadWrite))
129 continue;
130 struct v4l2_capability capability;
131 memset(s: &capability, c: 0, n: sizeof(struct v4l2_capability));
132 if (ioctl(fd: dev.handle(), VIDIOC_QUERYCAP, &capability) != -1
133 && (capability.capabilities & (V4L2_CAP_RADIO | V4L2_CAP_MODULATOR)) == (V4L2_CAP_RADIO | V4L2_CAP_MODULATOR)) {
134 return true;
135 }
136 }
137 return false;
138 }
139
140 case QDeviceInfo::InfraredFeature:
141 // TODO: find the kernel interface for this
142 return false;
143
144 case QDeviceInfo::LedFeature:
145 if (QDir(QStringLiteral("/sys/class/leds/")).entryList(filters: QDir::Dirs | QDir::NoDotAndDotDot).size() > 0)
146 return true;
147 return false;
148
149 case QDeviceInfo::MemoryCardFeature:
150 if (QDir(QStringLiteral("/sys/class/mmc_host/")).entryList(nameFilters: QStringList() << QStringLiteral("mmc*")).size() > 0)
151 return true;
152 return false;
153
154 case QDeviceInfo::UsbFeature:
155 if (QDir(QStringLiteral("/sys/bus/usb/devices/")).entryList(nameFilters: QStringList() << QStringLiteral("usb*")).size() > 0)
156 return true;
157 return false;
158
159 case QDeviceInfo::VibrationFeature:
160 if (QDir(QStringLiteral("/sys/bus/platform/devices/")).entryList(nameFilters: QStringList() << QStringLiteral("*vib*")).size() > 0)
161 return true;
162 return false;
163
164 case QDeviceInfo::WlanFeature:
165 if ((QDir(QStringLiteral("/sys/class/ieee80211/")).entryList(filters: QDir::Dirs | QDir::NoDotAndDotDot).size() > 0)
166 || (QDir(QStringLiteral("/sys/class/net/")).entryList(nameFilters: QStringList() << QStringLiteral("wlan*")).size() > 0))
167 return true;
168 return false;
169
170 case QDeviceInfo::SimFeature:
171#if !defined(QT_NO_OFONO)
172 if (QOfonoWrapper::isOfonoAvailable()) {
173 if (!ofonoWrapper)
174 ofonoWrapper = new QOfonoWrapper(this);
175 return (ofonoWrapper->allModems().size() > 0);
176 }
177#endif
178 return false;
179
180 case QDeviceInfo::PositioningFeature:
181 // TODO: find the kernel interface for this
182 if (QDir(QStringLiteral("/sys/class/misc/")).entryList(nameFilters: QStringList() << QStringLiteral("*nmea*")).size() > 0)
183 return true;
184 return false;
185
186 case QDeviceInfo::VideoOutFeature: {
187 const QString devfsPath(QStringLiteral("/dev/"));
188 const QStringList dirs = QDir(devfsPath).entryList(nameFilters: QStringList() << QStringLiteral("video*"), filters: QDir::System);
189 foreach (const QString &dir, dirs) {
190 QFile dev(devfsPath + dir);
191 if (!dev.open(flags: QIODevice::ReadWrite))
192 continue;
193 struct v4l2_capability capability;
194 memset(s: &capability, c: 0, n: sizeof(struct v4l2_capability));
195 if (ioctl(fd: dev.handle(), VIDIOC_QUERYCAP, &capability) != -1
196 && (capability.capabilities & V4L2_CAP_VIDEO_OUTPUT) == V4L2_CAP_VIDEO_OUTPUT) {
197 return true;
198 }
199 }
200 if (QDir(QStringLiteral("/sys/class/video_output/")).entryList(filters: QDir::Dirs | QDir::NoDotAndDotDot).size() > 0)
201 return true;
202 return false;
203 }
204
205 case QDeviceInfo::HapticsFeature:
206 if (QDir(QStringLiteral("/sys/class/haptic/")).entryList(filters: QDir::Dirs | QDir::NoDotAndDotDot).size() > 0)
207 return true;
208 return false;
209
210 case QDeviceInfo::NfcFeature:
211 // As of now, it's the only supported NFC device in the kernel
212 return QFile::exists(QStringLiteral("/dev/pn544"));
213 }
214
215 return false;
216}
217
218QDeviceInfo::LockTypeFlags QDeviceInfoPrivate::activatedLocks()
219{
220 return QDeviceInfo::NoLock;
221}
222
223QDeviceInfo::LockTypeFlags QDeviceInfoPrivate::enabledLocks()
224{
225 QDeviceInfo::LockTypeFlags enabledLocks = QDeviceInfo::NoLock;
226
227 QScreenSaverPrivate screenSaver(0);
228 if (screenSaver.screenSaverEnabled())
229 enabledLocks = QDeviceInfo::TouchOrKeyboardLock;
230
231 return enabledLocks;
232}
233
234QDeviceInfo::ThermalState QDeviceInfoPrivate::thermalState()
235{
236 if (watchThermalState)
237 return currentThermalState;
238 else
239 return getThermalState();
240}
241
242int QDeviceInfoPrivate::imeiCount()
243{
244 if (imeiBuffer.size() == 0)
245 imei(interface: 0);
246
247 return imeiBuffer.size();
248}
249
250QString QDeviceInfoPrivate::imei(int interfaceNumber)
251{
252#if !defined(QT_NO_OFONO)
253 imeiBuffer.clear();
254 if (QOfonoWrapper::isOfonoAvailable()) {
255 if (!ofonoWrapper)
256 ofonoWrapper = new QOfonoWrapper(this);
257 QStringList modems = ofonoWrapper->allModems();
258 foreach (const QString &modem, modems) {
259 if (!modem.isEmpty())
260 imeiBuffer += ofonoWrapper->imei(modem);
261 }
262 }
263#else
264 Q_UNUSED(interfaceNumber)
265#endif
266 if (interfaceNumber >= 0 && interfaceNumber < imeiBuffer.size())
267 return imeiBuffer[interfaceNumber];
268 else
269 return QString();
270}
271
272QString QDeviceInfoPrivate::manufacturer()
273{
274#if defined(QT_USE_SSU)
275 if (manufacturerBuffer.isEmpty()) {
276 manufacturerBuffer = SsuDeviceInfo().displayName(Ssu::DeviceManufacturer);
277 }
278#endif
279 if (manufacturerBuffer.isEmpty()) {
280 // for dmi enabled kernels
281 QFile file(QStringLiteral("/sys/devices/virtual/dmi/id/sys_vendor"));
282 if (file.open(flags: QIODevice::ReadOnly))
283 manufacturerBuffer = QString::fromLocal8Bit(str: file.readAll().simplified().data());
284 }
285 if (manufacturerBuffer.isEmpty()) {
286 QStringList releaseFies = QDir(QStringLiteral("/etc/")).entryList(nameFilters: QStringList() << QStringLiteral("*-release"));
287 foreach (const QString &file, releaseFies) {
288 if (!manufacturerBuffer.isEmpty())
289 continue;
290 QFile release(QStringLiteral("/etc/") + file);
291 if (release.open(flags: QIODevice::ReadOnly)) {
292 QTextStream stream(&release);
293 QString line;
294 do {
295 line = stream.readLine();
296 // this seems to be mer specific
297 if (line.startsWith(QStringLiteral("BUILD"))) {
298 manufacturerBuffer = line.split(QStringLiteral(":")).at(i: 1).simplified().split(QStringLiteral("-")).at(i: 0);
299 break;
300 }
301 } while (!line.isNull());
302 release.close();
303 }
304 }
305 }
306 if (manufacturerBuffer.isEmpty()) {
307 manufacturerBuffer = findInRelease(QStringLiteral("BUILD"));
308 }
309 return manufacturerBuffer;
310}
311
312QString QDeviceInfoPrivate::model()
313{
314#if defined(QT_USE_SSU)
315 if (modelBuffer.isEmpty()) {
316 modelBuffer = SsuDeviceInfo().displayName(Ssu::DeviceModel);
317 }
318#endif
319 if (modelBuffer.isEmpty()) {
320 modelBuffer = findInRelease(QStringLiteral("NAME"),QStringLiteral("hw-release"));
321 }
322 // for dmi enabled kernels
323 if (modelBuffer.isEmpty()) {
324 QFile file(QStringLiteral("/sys/devices/virtual/dmi/id/product_name"));
325 if (file.open(flags: QIODevice::ReadOnly))
326 modelBuffer = QString::fromLocal8Bit(str: file.readAll().simplified().data());
327 }
328 if (modelBuffer.isEmpty()) {
329 QStringList releaseFies = QDir(QStringLiteral("/etc/")).entryList(nameFilters: QStringList() << QStringLiteral("*-release"));
330 foreach (const QString &file, releaseFies) {
331 if (!modelBuffer.isEmpty())
332 continue;
333 QFile release(QStringLiteral("/etc/") + file);
334 if (release.open(flags: QIODevice::ReadOnly)) {
335 QTextStream stream(&release);
336 QString line;
337 do {
338 line = stream.readLine();
339 // this seems to be mer specific
340 if (line.startsWith(QStringLiteral("BUILD"))) {
341 modelBuffer = line.split(QStringLiteral(":")).at(i: 1).split(QStringLiteral("-")).at(i: 3);
342 break;
343 }
344 } while (!line.isNull());
345 release.close();
346 }
347 }
348 }
349 return modelBuffer;
350}
351
352QString QDeviceInfoPrivate::productName()
353{
354#if defined(QT_USE_SSU)
355 if (productNameBuffer.isEmpty()) {
356 productNameBuffer = SsuDeviceInfo().displayName(Ssu::DeviceDesignation);
357 }
358#endif
359
360 if (productNameBuffer.isEmpty()) {
361 productNameBuffer = findInRelease(QStringLiteral("PRETTY_NAME")).remove(QStringLiteral("\""));
362 }
363
364 if (productNameBuffer.isEmpty()) {
365 QProcess lsbRelease;
366 lsbRelease.start(QStringLiteral("/usr/bin/lsb_release"),
367 arguments: QStringList() << QStringLiteral("-c"));
368 if (lsbRelease.waitForFinished()) {
369 QString buffer(QString::fromLocal8Bit(str: lsbRelease.readAllStandardOutput().constData()));
370 productNameBuffer = buffer.section(asep: QChar::fromLatin1(c: '\t'), astart: 1, aend: 1).simplified();
371 }
372 }
373
374 return productNameBuffer;
375}
376
377QString QDeviceInfoPrivate::uniqueDeviceID()
378{
379 if (uniqueDeviceIDBuffer.isEmpty()) {
380 // for dmi enabled kernels
381 QFile file(QStringLiteral("/sys/devices/virtual/dmi/id/product_uuid"));
382 if (file.open(flags: QIODevice::ReadOnly)) {
383 QString id = QString::fromLocal8Bit(str: file.readAll().simplified().data());
384 if (id.length() == 36) {
385 if (isUuid(id)) {
386 uniqueDeviceIDBuffer = id;
387 }
388 }
389 }
390 }
391
392 if (uniqueDeviceIDBuffer.isEmpty()) {
393 QFile file(QStringLiteral("/etc/unique-id"));
394 if (file.open(flags: QIODevice::ReadOnly)) {
395 QString id = QString::fromLocal8Bit(str: file.readAll().simplified().data());
396 if (id.length() == 32) {
397 id = id.insert(i: 8,c: '-').insert(i: 13,c: '-').insert(i: 18,c: '-').insert(i: 23,c: '-');
398 if (isUuid(id)) {
399 uniqueDeviceIDBuffer = id;
400 }
401 file.close();
402 }
403 }
404 }
405
406 if (uniqueDeviceIDBuffer.isEmpty()) { //try wifi mac address
407 QNetworkInfo netinfo;
408 QString macaddy;
409 macaddy = netinfo.macAddress(mode: QNetworkInfo::WlanMode,interfaceDevice: 0);
410 if (macaddy.isEmpty())
411 macaddy = netinfo.macAddress(mode: QNetworkInfo::EthernetMode,interfaceDevice: 0);
412 if (!macaddy.isEmpty()) {
413 QCryptographicHash hash2(QCryptographicHash::Sha1);
414 hash2.addData(data: macaddy.toLocal8Bit());
415
416 QUuid id = QUuid::fromRfc4122(hash2.result().left(len: 16));
417 if (!id.isNull())
418 uniqueDeviceIDBuffer = id.toString();
419 }
420 }
421 if (uniqueDeviceIDBuffer.isEmpty()) {
422 QFile file(QStringLiteral("/etc/machine-id"));
423 if (file.open(flags: QIODevice::ReadOnly)) {
424 QString id = QString::fromLocal8Bit(str: file.readAll().simplified().data());
425 if (id.length() == 32) {
426 id = id.insert(i: 8,c: '-').insert(i: 13,c: '-').insert(i: 18,c: '-').insert(i: 23,c: '-');
427 if (isUuid(id)) {
428 uniqueDeviceIDBuffer = id;
429 }
430 }
431 file.close();
432 }
433 }
434
435//last ditch effort
436 if (uniqueDeviceIDBuffer.isEmpty()) {
437 QFile file(QStringLiteral("/var/lib/dbus/machine-id"));
438
439 if (file.open(flags: QIODevice::ReadOnly)) {
440 QString id = QString::fromLocal8Bit(str: file.readAll().simplified().data());
441 if (id.length() == 32) {
442 id = id.insert(i: 8,c: '-').insert(i: 13,c: '-').insert(i: 18,c: '-').insert(i: 23,c: '-');
443 if (isUuid(id)) {
444 uniqueDeviceIDBuffer = id;
445 }
446 }
447 file.close();
448 }
449 }
450
451
452 return uniqueDeviceIDBuffer;
453}
454
455bool QDeviceInfoPrivate::isUuid(const QString &id)
456{
457 QUuid uid(id); //make sure this can be made into a valid QUUid
458 return !uid.isNull();
459}
460
461QString QDeviceInfoPrivate::version(QDeviceInfo::Version type)
462{
463 switch (type) {
464 case QDeviceInfo::Os:
465
466 if (versionBuffer[0].isEmpty()) {
467 versionBuffer[0] = findInRelease(QStringLiteral("VERSION_ID"),
468 QStringLiteral("os-release"));
469 }
470
471 if (versionBuffer[0].isEmpty()) {
472 versionBuffer[0] = findInRelease(QStringLiteral("VERSION_ID"));
473 }
474
475 if (versionBuffer[0].isEmpty() && QFile::exists(QStringLiteral("/usr/bin/lsb_release"))) {
476 QProcess lsbRelease;
477 lsbRelease.start(QStringLiteral("/usr/bin/lsb_release"),
478 arguments: QStringList() << QStringLiteral("-r"));
479 if (lsbRelease.waitForFinished()) {
480 QString buffer(QString::fromLocal8Bit(str: lsbRelease.readAllStandardOutput().constData()));
481 versionBuffer[0] = buffer.section(asep: QChar::fromLatin1(c: '\t'), astart: 1, aend: 1).simplified();
482 }
483 }
484
485 return versionBuffer[0];
486
487 case QDeviceInfo::Firmware:
488 // Try to read hardware adaptation version first.
489 if (versionBuffer[1].isEmpty()) {
490 versionBuffer[1] = findInRelease(QStringLiteral("VERSION_ID"),
491 QStringLiteral("hw-release"));
492 }
493
494 if (versionBuffer[1].isEmpty()) {
495 QFile file(QStringLiteral("/proc/sys/kernel/osrelease"));
496 if (file.open(flags: QIODevice::ReadOnly)) {
497 versionBuffer[1] = QString::fromLocal8Bit(str: file.readAll().simplified().data());
498 file.close();
499 }
500 }
501 return versionBuffer[1];
502 }
503
504 return QString();
505}
506
507QString QDeviceInfoPrivate::operatingSystemName()
508{
509 if (osName.isEmpty()) {
510 osName = findInRelease(QStringLiteral("NAME="), QStringLiteral("os-release"));
511 }
512 if (osName.isEmpty()) {
513 osName = findInRelease(QStringLiteral("NAME="));
514 }
515
516 return osName;
517}
518
519QString QDeviceInfoPrivate::boardName()
520{
521 if (boardNameString.isEmpty()) {
522 QFile boardfile(QStringLiteral("/etc/boardname"));
523 if (boardfile.open(flags: QIODevice::ReadOnly))
524 boardNameString = QString::fromLocal8Bit(str: boardfile.readAll().simplified().data());
525 }
526
527 if (boardNameString.isEmpty()) {
528 // for dmi enabled kernels
529 QFile file(QStringLiteral("/sys/devices/virtual/dmi/id/board_name"));
530 if (file.open(flags: QIODevice::ReadOnly))
531 boardNameString = QString::fromLocal8Bit(str: file.readAll().simplified().data());
532 }
533 return boardNameString;
534}
535
536QString QDeviceInfoPrivate::findInRelease(const QString &searchTerm, const QString &file)
537{
538 QString result;
539 QStringList releaseFiles;
540 if (file.isEmpty()) {
541 releaseFiles = QDir(QStringLiteral("/etc/")).entryList(nameFilters: QStringList() << QStringLiteral("*-release"));
542 } else {
543 releaseFiles.append(t: file);
544 }
545
546 foreach (const QString &file, releaseFiles) {
547 if (!result.isEmpty())
548 continue;
549 QFile release(QStringLiteral("/etc/") + file);
550 if (release.open(flags: QIODevice::ReadOnly)) {
551 QTextStream stream(&release);
552 QString line;
553 do {
554 line = stream.readLine();
555 if (line.left(n: searchTerm.size()) == searchTerm) {
556 result = line.split(QStringLiteral("=")).at(i: 1).simplified();
557 // Remove optional quotation marks.
558 result.remove(re: QRegularExpression(QStringLiteral("^\"|\"$")));
559 break;
560 }
561 } while (!line.isNull());
562 release.close();
563 }
564 }
565 return result;
566}
567
568#if !defined(QT_NO_DBUS)
569void QDeviceInfoPrivate::bluezPropertyChanged(const QString &str, QDBusVariant v)
570{
571
572 if (str == QStringLiteral("Powered")) {
573 if (btPowered != v.variant().toBool()) {
574 btPowered = !btPowered;
575 Q_EMIT bluetoothStateChanged(on: btPowered);
576 }
577 } else if (str == QStringLiteral("Adapters")) {
578 bool oldPoweredState = btPowered;
579 if (oldPoweredState != currentBluetoothPowerState())
580 Q_EMIT bluetoothStateChanged(on: btPowered);
581 }
582}
583
584void QDeviceInfoPrivate::connectBtPowered()
585{
586 if (connectedBtPower) {
587 QDBusInterface *connectionInterface;
588 connectionInterface = new QDBusInterface(QStringLiteral("org.bluez"), QStringLiteral("/"),
589 QStringLiteral("org.bluez.Manager"),
590 QDBusConnection::systemBus(), this);
591 if (connectionInterface->isValid()) {
592 QDBusReply <QDBusObjectPath> reply = connectionInterface->call(QStringLiteral("DefaultAdapter"));
593 if (reply.isValid() && !reply.value().path().isEmpty()) {
594 if (!QDBusConnection::systemBus().connect(QStringLiteral("org.bluez"), path: reply.value().path(),
595 QStringLiteral("org.bluez.Adapter"),
596 QStringLiteral("PropertyChanged"),
597 receiver: this,
598 SLOT(bluezPropertyChanged(QString,QDBusVariant)))) {
599 }
600 }
601 }
602 connectedBtPower = true;
603 }
604}
605#endif
606
607bool QDeviceInfoPrivate::currentBluetoothPowerState()
608{
609 bool powered = false;
610#ifndef QT_NO_DBUS
611 QDBusInterface *connectionInterface = new QDBusInterface(QStringLiteral("org.bluez"),
612 QStringLiteral("/"),
613 QStringLiteral("org.bluez.Manager"),
614 QDBusConnection::systemBus(), this);
615 if (connectionInterface->isValid()) {
616 QDBusReply<QDBusObjectPath> reply = connectionInterface->call(QStringLiteral("DefaultAdapter"));
617 if (reply.isValid() && !reply.value().path().isEmpty()) {
618 QDBusInterface *adapterInterface = new QDBusInterface(QStringLiteral("org.bluez"),
619 reply.value().path(),
620 QStringLiteral("org.bluez.Adapter"),
621 QDBusConnection::systemBus(), this);
622 if (adapterInterface->isValid()) {
623 QDBusReply<QVariantMap> reply = adapterInterface->call(QStringLiteral("GetProperties"));
624 QVariantMap map = reply.value();
625 QString property = QStringLiteral("Powered");
626 if (map.contains(akey: property))
627 powered = map.value(akey: property).toBool();
628 } else {
629 powered = false;
630 }
631 } else {
632 powered = false;
633 }
634 }
635#endif
636 return btPowered = powered;
637}
638
639extern QMetaMethod proxyToSourceSignal(const QMetaMethod &, QObject *);
640
641void QDeviceInfoPrivate::connectNotify(const QMetaMethod &signal)
642{
643 if (timer == 0) {
644 timer = new QTimer(this);
645 timer->setInterval(2000);
646 connect(sender: timer, SIGNAL(timeout()), receiver: this, SLOT(onTimeout()));
647 }
648
649 if (!timer->isActive())
650 timer->start();
651
652 static const QMetaMethod thermalStateChangedSignal = QMetaMethod::fromSignal(signal: &QDeviceInfoPrivate::thermalStateChanged);
653 if (signal == thermalStateChangedSignal) {
654 watchThermalState = true;
655 currentThermalState = getThermalState();
656 }
657
658 static const QMetaMethod bluetoothStateChanged = QMetaMethod::fromSignal(signal: &QDeviceInfoPrivate::bluetoothStateChanged);
659 if (signal == bluetoothStateChanged) {
660#if !defined(QT_NO_DBUS)
661 connectBtPowered();
662#endif
663 }
664}
665
666void QDeviceInfoPrivate::disconnectNotify(const QMetaMethod &signal)
667{
668 static const QMetaMethod thermalStateChangedSignal = QMetaMethod::fromSignal(signal: &QDeviceInfoPrivate::thermalStateChanged);
669 if (signal == thermalStateChangedSignal) {
670 watchThermalState = false;
671 currentThermalState = QDeviceInfo::UnknownThermal;
672 }
673
674 if (!watchThermalState)
675 timer->stop();
676}
677
678void QDeviceInfoPrivate::onTimeout()
679{
680 if (watchThermalState) {
681 QDeviceInfo::ThermalState newState = getThermalState();
682 if (newState != currentThermalState) {
683 currentThermalState = newState;
684 emit thermalStateChanged(state: currentThermalState);
685 }
686 }
687}
688
689QDeviceInfo::ThermalState QDeviceInfoPrivate::getThermalState()
690{
691 QDeviceInfo::ThermalState state = QDeviceInfo::UnknownThermal;
692
693 const QString hwmonRoot(QStringLiteral("/sys/class/hwmon/"));
694 const QStringList hwmonDirs(QDir(hwmonRoot).entryList(nameFilters: QStringList() << QStringLiteral("hwmon*")));
695 foreach (const QString &dir, hwmonDirs) {
696 int index = 1;
697 const QString input(hwmonRoot + dir + QDir::separator() + QStringLiteral("temp%1_input"));
698 const QString critical(hwmonRoot + dir + QDir::separator() + QStringLiteral("temp%1_crit"));
699 const QString emergency(hwmonRoot + dir + QDir::separator() + QStringLiteral("temp%1_emergency"));
700 while (true) {
701 QFile file(input.arg(a: index));
702 if (!file.open(flags: QIODevice::ReadOnly))
703 break;
704 bool ok(false);
705 int currentTemp = file.readAll().simplified().toInt(ok: &ok);
706 if (ok) {
707 if (state == QDeviceInfo::UnknownThermal)
708 state = QDeviceInfo::NormalThermal;
709
710 // Only check if we are below WarningThermal
711 if (state < QDeviceInfo::WarningThermal) {
712 file.close();
713 file.setFileName(critical.arg(a: index));
714 if (file.open(flags: QIODevice::ReadOnly)) {
715 int criticalTemp = file.readAll().simplified().toInt(ok: &ok);
716 if (ok && currentTemp > criticalTemp)
717 state = QDeviceInfo::WarningThermal;
718 }
719 }
720
721 // Only check if we are below AlertThermal
722 if (state < QDeviceInfo::AlertThermal) {
723 file.close();
724 file.setFileName(emergency.arg(a: index));
725 if (file.open(flags: QIODevice::ReadOnly)) {
726 int emergencyTemp = file.readAll().simplified().toInt(ok: &ok);
727 if (ok && currentTemp > emergencyTemp) {
728 state = QDeviceInfo::AlertThermal;
729 break; // No need for further checking, as we can't get the ErrorThermal state
730 }
731 }
732 }
733 } else {
734 break;
735 }
736
737 ++index;
738 }
739 }
740
741 return state;
742}
743
744QT_END_NAMESPACE
745

source code of qtsystems/src/systeminfo/linux/qdeviceinfo_linux.cpp