From 6b1c6cb2f84f5824d765da1d7a54ea81eb0389f8 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Thu, 18 Sep 2014 17:50:36 +0200 Subject: Fix timing issues in wifi library There is a timing issue on a device startup if the default application calls Wifi.Interface.wifiSupported() before qconnectivity service has finished initialize wifi firmware/driver. This results in wifiSupported() returing false on nexus 2013, even if this device supports wifi. The solution is to move firmware/driver initialization to Qt Wifi library. Change-Id: If5b4650181f8b7237bd19f3fc3afbd2c75f759e8 Task-number: QTEE-770 Reviewed-by: Eirik Aavitsland --- src/imports/wifi/pluginmain.cpp | 66 ++----------------------------- src/imports/wifi/qwifiinterface.cpp | 77 +++++++++++++++++++++++++++++++++++++ src/imports/wifi/qwifiinterface.h | 40 +++++++++++++++++++ src/imports/wifi/qwifimanager.cpp | 5 +++ src/imports/wifi/wifi.pro | 6 ++- src/qconnectivity/main.cpp | 15 ++------ 6 files changed, 133 insertions(+), 76 deletions(-) create mode 100644 src/imports/wifi/qwifiinterface.cpp create mode 100644 src/imports/wifi/qwifiinterface.h (limited to 'src') diff --git a/src/imports/wifi/pluginmain.cpp b/src/imports/wifi/pluginmain.cpp index 51a2e7c..a779e44 100644 --- a/src/imports/wifi/pluginmain.cpp +++ b/src/imports/wifi/pluginmain.cpp @@ -17,74 +17,14 @@ ** ****************************************************************************/ #include "qwifimanager.h" +#include "qwifiinterface.h" -#include -#include -#include #include #include -#ifdef Q_OS_ANDROID -#include -#endif -/*! - \qmltype Interface - \inqmlmodule Qt.labs.wifi - \ingroup wifi-qmltypes - \brief The Interface element provides the module API. - - This element cannot be directly created. It can only be accessed via a namespace import. - - \code - import Qt.labs.wifi 0.1 - import Qt.labs.wifi 0.1 as Wifi - - Component.onCompleted: { - if (Wifi.Interface.wifiSupported()) { - var component = Qt.createComponent("WifiMenu.qml") - } else { - print("WiFi functionality not available on this device.") - } - } - \endcode -*/ - -/*! - \qmlmethod bool Interface::wifiSupported() - - Returns true if the device is WiFi capable (provides a WiFi driver), otherwise returns false. -*/ - - -class QWifiGlobal : public QObject -{ - Q_OBJECT -public: - explicit QWifiGlobal(QObject *parent = 0) - : QObject(parent) {} - ~QWifiGlobal() {} - - Q_INVOKABLE bool wifiSupported() const - { - bool hasInterface = QDir().exists(QStringLiteral("/sys/class/net/wlan0")); - if (!hasInterface) - qWarning() << "QWifiGlobal: could not find wifi interface in /sys/class/net/"; -#ifdef Q_OS_ANDROID - if (hasInterface && wifi_load_driver() == 0 && wifi_start_supplicant(0) == 0) { - return true; - } else { - qWarning() << "QWifiGlobal: wifi driver is not available"; - return false; - } -#else - return hasInterface; -#endif - } -}; - static QObject *global_object_wifi(QQmlEngine *, QJSEngine *) { - return new QWifiGlobal; + return new QWifiInterface; } class QWifiPlugin : public QQmlExtensionPlugin @@ -99,7 +39,7 @@ public: qmlRegisterType(uri, 0, 1, "WifiManager"); qmlRegisterType(); - qmlRegisterSingletonType(uri, 0, 1, "Interface", global_object_wifi); + qmlRegisterSingletonType(uri, 0, 1, "Interface", global_object_wifi); } }; diff --git a/src/imports/wifi/qwifiinterface.cpp b/src/imports/wifi/qwifiinterface.cpp new file mode 100644 index 0000000..2922866 --- /dev/null +++ b/src/imports/wifi/qwifiinterface.cpp @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use the contact form at +** http://qt.digia.com/ +** +** This file is part of Qt Enterprise Embedded. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** the contact form at http://qt.digia.com/ +** +****************************************************************************/ +#include "qwifiinterface.h" + +/*! + \qmltype Interface + \inqmlmodule Qt.labs.wifi + \ingroup wifi-qmltypes + \brief The Interface element provides the module API. + + This element cannot be directly created. It can only be accessed via a namespace import. + + \code + import Qt.labs.wifi 0.1 + import Qt.labs.wifi 0.1 as Wifi + + Component.onCompleted: { + if (Wifi.Interface.wifiSupported()) { + var component = Qt.createComponent("WifiMenu.qml") + } else { + print("WiFi functionality not available on this device.") + } + } + \endcode +*/ + +/*! + \qmlmethod bool Interface::wifiSupported() + + Returns true if the device is WiFi capable (provides a WiFi driver), otherwise returns false. +*/ + +bool QWifiInterface::wifiSupported() const +{ +#ifdef Q_OS_ANDROID + const char *fwpath = 0; + // reload wifi firmware + fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_STA); + if (!fwpath) { + qWarning() << "QWifiInterface: failed to get firmware path"; + return false; + } + if (wifi_change_fw_path((const char *)fwpath)) { + qWarning() << "QWifiInterface: failed to change firmware path"; + return false; + } +#endif + const bool hasInterface = QDir().exists(QStringLiteral("/sys/class/net/wlan0")); + if (!hasInterface) + qWarning() << "QWifiInterface: could not find wifi interface in /sys/class/net/"; +#ifdef Q_OS_ANDROID + if (hasInterface && wifi_load_driver() == 0 && wifi_start_supplicant(0) == 0) { + return true; + } else { + qWarning() << "QWifiInterface: wifi driver is not available"; + return false; + } +#else + return hasInterface; +#endif +} diff --git a/src/imports/wifi/qwifiinterface.h b/src/imports/wifi/qwifiinterface.h new file mode 100644 index 0000000..da7750e --- /dev/null +++ b/src/imports/wifi/qwifiinterface.h @@ -0,0 +1,40 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use the contact form at +** http://qt.digia.com/ +** +** This file is part of Qt Enterprise Embedded. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** the contact form at http://qt.digia.com/ +** +****************************************************************************/ +#ifndef QWIFIINTERFACE_H +#define QWIFIINTERFACE_H + +#include +#include +#ifdef Q_OS_ANDROID +#include +#include +#endif + +class QWifiInterface : public QObject +{ + Q_OBJECT +public: + explicit QWifiInterface(QObject *parent = 0) + : QObject(parent) {} + ~QWifiInterface() {} + + Q_INVOKABLE bool wifiSupported() const; +}; + +#endif // QWIFIHELPERS_H diff --git a/src/imports/wifi/qwifimanager.cpp b/src/imports/wifi/qwifimanager.cpp index 8eec3e0..165abfd 100644 --- a/src/imports/wifi/qwifimanager.cpp +++ b/src/imports/wifi/qwifimanager.cpp @@ -17,6 +17,7 @@ ** ****************************************************************************/ #include "qwifimanager.h" +#include "qwifiinterface.h" #include #ifdef Q_OS_ANDROID @@ -422,6 +423,10 @@ QWifiManager::QWifiManager() , m_startingUp(true) , m_network(0) { + if (!QWifiInterface().wifiSupported()) + // give a warning about API misuse + qWarning() << "WifiManager may not work as expected on this device. Use the API provided by QtWifi " + "library to verify if device has support for Wi-Fi before creating an instance of WifiManager!"; #ifdef Q_OS_ANDROID char interface[PROPERTY_VALUE_MAX]; property_get(WIFI_INTERFACE, interface, NULL); diff --git a/src/imports/wifi/wifi.pro b/src/imports/wifi/wifi.pro index fcb6cdd..dabf8cb 100644 --- a/src/imports/wifi/wifi.pro +++ b/src/imports/wifi/wifi.pro @@ -7,13 +7,15 @@ IMPORT_VERSION = 0.1 HEADERS += \ qwifimanager.h \ qwifinetwork.h \ - qwifinetworklistmodel.h + qwifinetworklistmodel.h \ + qwifiinterface.h SOURCES += \ pluginmain.cpp \ qwifimanager.cpp \ qwifinetwork.cpp \ - qwifinetworklistmodel.cpp + qwifinetworklistmodel.cpp \ + qwifiinterface.cpp android: { LIBS += -lhardware_legacy -lcutils diff --git a/src/qconnectivity/main.cpp b/src/qconnectivity/main.cpp index 97f9582..e9ded93 100644 --- a/src/qconnectivity/main.cpp +++ b/src/qconnectivity/main.cpp @@ -163,7 +163,7 @@ QConnectivityDaemon::QConnectivityDaemon() m_linkUp(false), m_leaseTimer(0), m_isEmulator(isEmulator()), - m_attemptCount(12) + m_attemptCount(50) { qDebug() << "starting QConnectivityDaemon..."; if (!m_isEmulator) { @@ -213,9 +213,9 @@ void QConnectivityDaemon::initNetdConnection() connect(m_netdSocket, SIGNAL(error(QLocalSocket::LocalSocketError)), this, SLOT(handleError(QLocalSocket::LocalSocketError))); } else { - qWarning() << "QConnectivityDaemon: failed to connect to netd socket"; + qWarning() << "QConnectivityDaemon: failed to connect to netd socket, reattempting..."; if (--m_attemptCount != 0) - QTimer::singleShot(2000, this, SLOT(initNetdConnection())); + QTimer::singleShot(200, this, SLOT(initNetdConnection())); return; } if (ethernetSupported()) { @@ -224,11 +224,6 @@ void QConnectivityDaemon::initNetdConnection() sendCommand(QByteArray("0 interface setcfg ").append(m_ethInterface).append(" down").constData()); sendCommand(QByteArray("0 interface setcfg ").append(m_ethInterface).append(" up").constData()); } - char wifiInterface[PROPERTY_VALUE_MAX]; - property_get("wifi.interface", wifiInterface, NULL); - if (wifiInterface) - // reload wifi firmware - sendCommand(QByteArray("0 softap fwreload ").append(wifiInterface).append(" STA").constData()); // disable firewall - this setting seems to be enabled only when using "Always-on VPN" // mode on Android phones, see setLockdownTracker() in ConnectivityService.java sendCommand("0 firewall disable"); @@ -271,10 +266,8 @@ void QConnectivityDaemon::sendCommand(const char *command) const void QConnectivityDaemon::handleInterfaceChange(const QList &message) { // Format: "Code Iface linkstate " - if (message.size() < 5) { - qWarning() << "QConnectivityDaemon: broken command"; + if (message.size() < 5) return; - } if (message.at(2) == "linkstate" && message.at(3) == m_ethInterface) { if (message.at(4) == "up") { -- cgit v1.2.3