aboutsummaryrefslogtreecommitdiffstats
path: root/plugins/qmlprofiler/qmlprofilerclientmanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/qmlprofiler/qmlprofilerclientmanager.cpp')
-rw-r--r--plugins/qmlprofiler/qmlprofilerclientmanager.cpp431
1 files changed, 431 insertions, 0 deletions
diff --git a/plugins/qmlprofiler/qmlprofilerclientmanager.cpp b/plugins/qmlprofiler/qmlprofilerclientmanager.cpp
new file mode 100644
index 0000000000..e1855fad95
--- /dev/null
+++ b/plugins/qmlprofiler/qmlprofilerclientmanager.cpp
@@ -0,0 +1,431 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "qmlprofilerclientmanager.h"
+#include "qmlprofilertool.h"
+#include "qmlprofilerplugin.h"
+
+#include <qmldebug/qmldebugclient.h>
+#include <qmldebug/qmlprofilertraceclient.h>
+#include <qmldebug/qv8profilerclient.h>
+
+#include <utils/qtcassert.h>
+#include <QPointer>
+#include <QTimer>
+#include <QMessageBox>
+
+using namespace QmlDebug;
+using namespace Core;
+
+namespace QmlProfiler {
+namespace Internal {
+
+class QmlProfilerClientManager::QmlProfilerClientManagerPrivate {
+public:
+ QmlProfilerClientManagerPrivate(QmlProfilerClientManager *qq) { Q_UNUSED(qq); }
+
+ QmlProfilerStateManager* profilerState;
+
+ QmlDebugConnection *connection;
+ QPointer<QmlProfilerTraceClient> qmlclientplugin;
+ QPointer<QV8ProfilerClient> v8clientplugin;
+
+ QTimer connectionTimer;
+ int connectionAttempts;
+
+ enum ConnectMode {
+ TcpConnection, OstConnection
+ };
+ ConnectMode connectMode;
+ QString tcpHost;
+ quint64 tcpPort;
+ QString ostDevice;
+ QString sysroot;
+
+ bool v8DataReady;
+ bool qmlDataReady;
+};
+
+QmlProfilerClientManager::QmlProfilerClientManager(QObject *parent) :
+ QObject(parent), d(new QmlProfilerClientManagerPrivate(this))
+{
+ setObjectName(QLatin1String("QML Profiler Connections"));
+
+ d->profilerState = 0;
+
+ d->connection = 0;
+ d->connectionAttempts = 0;
+ d->v8DataReady = false;
+ d->qmlDataReady = false;
+
+ d->connectionTimer.setInterval(200);
+ connect(&d->connectionTimer, SIGNAL(timeout()), SLOT(tryToConnect()));
+}
+
+QmlProfilerClientManager::~QmlProfilerClientManager()
+{
+ disconnectClientSignals();
+ delete d->connection;
+ delete d->qmlclientplugin.data();
+ delete d->v8clientplugin.data();
+
+ delete d;
+}
+////////////////////////////////////////////////////////////////
+// Interface
+void QmlProfilerClientManager::setTcpConnection(QString host, quint64 port)
+{
+ d->connectMode = QmlProfilerClientManagerPrivate::TcpConnection;
+ d->tcpHost = host;
+ d->tcpPort = port;
+}
+
+void QmlProfilerClientManager::setOstConnection(QString ostDevice)
+{
+ d->connectMode = QmlProfilerClientManagerPrivate::OstConnection;
+ d->ostDevice = ostDevice;
+}
+
+void QmlProfilerClientManager::clearBufferedData()
+{
+ if (d->qmlclientplugin)
+ d->qmlclientplugin.data()->clearData();
+ if (d->v8clientplugin)
+ d->v8clientplugin.data()->clearData();
+}
+
+void QmlProfilerClientManager::discardPendingData()
+{
+ if (d->connection)
+ d->connection->flush();
+ clearBufferedData();
+}
+
+////////////////////////////////////////////////////////////////
+// Internal
+void QmlProfilerClientManager::connectClient(quint16 port)
+{
+ if (d->connection)
+ delete d->connection;
+ d->connection = new QmlDebugConnection;
+ enableServices();
+ connect(d->connection, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
+ this, SLOT(connectionStateChanged()));
+ d->connectionTimer.start();
+ d->tcpPort = port;
+}
+
+void QmlProfilerClientManager::enableServices()
+{
+ QTC_ASSERT(d->profilerState, return);
+
+ disconnectClientSignals();
+ d->profilerState->setServerRecording(false); // false by default (will be set to true when connected)
+ delete d->qmlclientplugin.data();
+ d->qmlclientplugin = new QmlProfilerTraceClient(d->connection);
+ delete d->v8clientplugin.data();
+ d->v8clientplugin = new QV8ProfilerClient(d->connection);
+ connectClientSignals();
+}
+
+void QmlProfilerClientManager::connectClientSignals()
+{
+ QTC_ASSERT(d->profilerState, return);
+ if (d->qmlclientplugin) {
+ connect(d->qmlclientplugin.data(), SIGNAL(complete()),
+ this, SLOT(qmlComplete()));
+ connect(d->qmlclientplugin.data(),
+ SIGNAL(range(int,int,qint64,qint64,QStringList,QmlDebug::QmlEventLocation)),
+ this,
+ SIGNAL(addRangedEvent(int,int,qint64,qint64,QStringList,QmlDebug::QmlEventLocation)));
+ connect(d->qmlclientplugin.data(), SIGNAL(traceFinished(qint64)),
+ this, SIGNAL(traceFinished(qint64)));
+ connect(d->qmlclientplugin.data(), SIGNAL(traceStarted(qint64)),
+ this, SIGNAL(traceStarted(qint64)));
+ connect(d->qmlclientplugin.data(), SIGNAL(frame(qint64,int,int)),
+ this, SIGNAL(addFrameEvent(qint64,int,int)));
+ connect(d->qmlclientplugin.data(), SIGNAL(enabledChanged()),
+ d->qmlclientplugin.data(), SLOT(sendRecordingStatus()));
+ // fixme: this should be unified for both clients
+ connect(d->qmlclientplugin.data(), SIGNAL(recordingChanged(bool)),
+ d->profilerState, SLOT(setServerRecording(bool)));
+ }
+ if (d->v8clientplugin) {
+ connect(d->v8clientplugin.data(), SIGNAL(complete()), this, SLOT(v8Complete()));
+ connect(d->v8clientplugin.data(),
+ SIGNAL(v8range(int,QString,QString,int,double,double)),
+ this,
+ SIGNAL(addV8Event(int,QString,QString,int,double,double)));
+ connect(d->v8clientplugin.data(), SIGNAL(enabledChanged()),
+ d->v8clientplugin.data(), SLOT(sendRecordingStatus()));
+ }
+}
+
+void QmlProfilerClientManager::disconnectClientSignals()
+{
+ if (d->qmlclientplugin) {
+ disconnect(d->qmlclientplugin.data(), SIGNAL(complete()),
+ this, SLOT(qmlComplete()));
+ disconnect(d->qmlclientplugin.data(),
+ SIGNAL(range(int,int,qint64,qint64,QStringList,QmlDebug::QmlEventLocation)),
+ this,
+ SIGNAL(addRangedEvent(int,int,qint64,qint64,QStringList,QmlDebug::QmlEventLocation)));
+ disconnect(d->qmlclientplugin.data(), SIGNAL(traceFinished(qint64)),
+ this, SIGNAL(traceFinished(qint64)));
+ disconnect(d->qmlclientplugin.data(), SIGNAL(traceStarted(qint64)),
+ this, SIGNAL(traceStarted(qint64)));
+ disconnect(d->qmlclientplugin.data(), SIGNAL(frame(qint64,int,int)),
+ this, SIGNAL(addFrameEvent(qint64,int,int)));
+ disconnect(d->qmlclientplugin.data(), SIGNAL(enabledChanged()),
+ d->qmlclientplugin.data(), SLOT(sendRecordingStatus()));
+ // fixme: this should be unified for both clients
+ disconnect(d->qmlclientplugin.data(), SIGNAL(recordingChanged(bool)),
+ d->profilerState, SLOT(setServerRecording(bool)));
+ }
+ if (d->v8clientplugin) {
+ disconnect(d->v8clientplugin.data(), SIGNAL(complete()), this, SLOT(v8Complete()));
+ disconnect(d->v8clientplugin.data(),
+ SIGNAL(v8range(int,QString,QString,int,double,double)),
+ this,
+ SIGNAL(addV8Event(int,QString,QString,int,double,double)));
+ disconnect(d->v8clientplugin.data(), SIGNAL(enabledChanged()),
+ d->v8clientplugin.data(), SLOT(sendRecordingStatus()));
+ }
+}
+
+void QmlProfilerClientManager::connectToClient()
+{
+ if (!d->connection || d->connection->state() != QAbstractSocket::UnconnectedState)
+ return;
+
+ QmlProfilerTool::logStatus(QString::fromLatin1("QML Profiler: Connecting to %1:%2 ...")
+ .arg(d->tcpHost, QString::number(d->tcpPort)));
+ d->connection->connectToHost(d->tcpHost, d->tcpPort);
+}
+
+bool QmlProfilerClientManager::isConnected() const
+{
+ return d->connection && d->connection->isConnected();
+}
+
+void QmlProfilerClientManager::disconnectClient()
+{
+ // this might be actually be called indirectly by QDDConnectionPrivate::readyRead(), therefore allow
+ // method to complete before deleting object
+ if (d->connection) {
+ d->connection->deleteLater();
+ d->connection = 0;
+ }
+}
+
+void QmlProfilerClientManager::tryToConnect()
+{
+ ++d->connectionAttempts;
+
+ if (d->connection && d->connection->isConnected()) {
+ d->connectionTimer.stop();
+ d->connectionAttempts = 0;
+ } else if (d->connectionAttempts == 50) {
+ d->connectionTimer.stop();
+ d->connectionAttempts = 0;
+
+ QMessageBox *infoBox = QmlProfilerTool::requestMessageBox();
+ infoBox->setIcon(QMessageBox::Critical);
+ infoBox->setWindowTitle(tr("Qt Creator"));
+ infoBox->setText(tr("Could not connect to the in-process QML profiler.\n"
+ "Do you want to retry?"));
+ infoBox->setStandardButtons(QMessageBox::Retry |
+ QMessageBox::Cancel |
+ QMessageBox::Help);
+ infoBox->setDefaultButton(QMessageBox::Retry);
+ infoBox->setModal(true);
+
+ connect(infoBox, SIGNAL(finished(int)),
+ this, SLOT(retryMessageBoxFinished(int)));
+
+ infoBox->show();
+ } else {
+ connectToClient();
+ }
+}
+
+void QmlProfilerClientManager::connectionStateChanged()
+{
+ if (!d->connection)
+ return;
+ switch (d->connection->state()) {
+ case QAbstractSocket::UnconnectedState:
+ {
+ if (QmlProfilerPlugin::debugOutput)
+ qWarning("QML Profiler: disconnected");
+ disconnectClient();
+ emit connectionClosed();
+ break;
+ }
+ case QAbstractSocket::HostLookupState:
+ break;
+ case QAbstractSocket::ConnectingState: {
+ if (QmlProfilerPlugin::debugOutput)
+ qWarning("QML Profiler: Connecting to debug server ...");
+ break;
+ }
+ case QAbstractSocket::ConnectedState:
+ {
+ if (QmlProfilerPlugin::debugOutput)
+ qWarning("QML Profiler: connected and running");
+ // notify the client recording status
+ clientRecordingChanged();
+ break;
+ }
+ case QAbstractSocket::ClosingState:
+ if (QmlProfilerPlugin::debugOutput)
+ qWarning("QML Profiler: closing ...");
+ break;
+ case QAbstractSocket::BoundState:
+ case QAbstractSocket::ListeningState:
+ break;
+ }
+}
+
+void QmlProfilerClientManager::retryMessageBoxFinished(int result)
+{
+ switch (result) {
+ case QMessageBox::Retry: {
+ d->connectionAttempts = 0;
+ d->connectionTimer.start();
+ break;
+ }
+ case QMessageBox::Help: {
+ QmlProfilerTool::handleHelpRequest(QLatin1String("qthelp://org.qt-project.qtcreator/doc/creator-debugging-qml.html"));
+ // fall through
+ }
+ default: {
+ if (d->connection)
+ QmlProfilerTool::logStatus(QLatin1String("QML Profiler: Failed to connect! ") + d->connection->errorString());
+ else
+ QmlProfilerTool::logStatus(QLatin1String("QML Profiler: Failed to connect!"));
+
+ emit connectionFailed();
+ break;
+ }
+ }
+}
+
+void QmlProfilerClientManager::qmlComplete()
+{
+ d->qmlDataReady = true;
+ if (!d->v8clientplugin || d->v8clientplugin.data()->status() != QmlDebug::Enabled || d->v8DataReady) {
+ emit dataReadyForProcessing();
+ // once complete is sent, reset the flags
+ d->qmlDataReady = false;
+ d->v8DataReady = false;
+ }
+}
+
+void QmlProfilerClientManager::v8Complete()
+{
+ d->v8DataReady = true;
+ if (!d->qmlclientplugin || d->qmlclientplugin.data()->status() != QmlDebug::Enabled || d->qmlDataReady) {
+ emit dataReadyForProcessing();
+ // once complete is sent, reset the flags
+ d->v8DataReady = false;
+ d->qmlDataReady = false;
+ }
+}
+
+void QmlProfilerClientManager::stopClientsRecording()
+{
+ if (d->qmlclientplugin)
+ d->qmlclientplugin.data()->setRecording(false);
+ if (d->v8clientplugin)
+ d->v8clientplugin.data()->setRecording(false);
+}
+
+////////////////////////////////////////////////////////////////
+// Profiler State
+void QmlProfilerClientManager::registerProfilerStateManager( QmlProfilerStateManager *profilerState )
+{
+ if (d->profilerState) {
+ disconnect(d->profilerState, SIGNAL(stateChanged()),
+ this, SLOT(profilerStateChanged()));
+ disconnect(d->profilerState, SIGNAL(clientRecordingChanged()),
+ this, SLOT(clientRecordingChanged()));
+ disconnect(d->profilerState, SIGNAL(serverRecordingChanged()),
+ this, SLOT(serverRecordingChanged()));
+ }
+
+ d->profilerState = profilerState;
+
+ // connect
+ if (d->profilerState) {
+ connect(d->profilerState, SIGNAL(stateChanged()),
+ this, SLOT(profilerStateChanged()));
+ connect(d->profilerState, SIGNAL(clientRecordingChanged()),
+ this, SLOT(clientRecordingChanged()));
+ connect(d->profilerState, SIGNAL(serverRecordingChanged()),
+ this, SLOT(serverRecordingChanged()));
+ }
+}
+
+void QmlProfilerClientManager::profilerStateChanged()
+{
+ QTC_ASSERT(d->profilerState, return);
+ switch (d->profilerState->currentState()) {
+ case QmlProfilerStateManager::AppStopRequested :
+ if (d->profilerState->serverRecording())
+ stopClientsRecording();
+ else
+ d->profilerState->setCurrentState(QmlProfilerStateManager::AppReadyToStop);
+ break;
+ default:
+ break;
+ }
+}
+
+void QmlProfilerClientManager::clientRecordingChanged()
+{
+ QTC_ASSERT(d->profilerState, return);
+ if (d->profilerState->currentState() == QmlProfilerStateManager::AppRunning) {
+ if (d->qmlclientplugin)
+ d->qmlclientplugin.data()->setRecording(d->profilerState->clientRecording());
+ if (d->v8clientplugin)
+ d->v8clientplugin.data()->setRecording(d->profilerState->clientRecording());
+ }
+}
+
+void QmlProfilerClientManager::serverRecordingChanged()
+{
+ if (d->profilerState->serverRecording()) {
+ d->v8DataReady = false;
+ d->qmlDataReady = false;
+ }
+}
+
+} // namespace Internal
+} // namespace QmlProfiler