QmlProfiler: Add some sanity to the client manager

Remove the PIMPL pattern, use smart pointers, add asserts for
important preconditions, add a timeout also to the local server case,
make sure all signal/slot connections to the old connection objects are
cleared when retrying to connect, make retry intervals configurable.

Change-Id: Ica7df0eaddc48778f13905795871d522401617ed
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Ulf Hermann
2016-07-14 09:41:04 +02:00
parent 9fd5d64194
commit 62b1217818
3 changed files with 269 additions and 236 deletions

View File

@@ -25,286 +25,282 @@
#include "qmlprofilerclientmanager.h" #include "qmlprofilerclientmanager.h"
#include "qmlprofilertool.h" #include "qmlprofilertool.h"
#include "qmlprofilerplugin.h"
#include "qmlprofilertraceclient.h"
#include "qmlprofilermodelmanager.h" #include "qmlprofilermodelmanager.h"
#include "qmlprofilerstatemanager.h"
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QPointer>
#include <QTimer>
using namespace Core;
namespace QmlProfiler { namespace QmlProfiler {
namespace Internal { namespace Internal {
class QmlProfilerClientManager::QmlProfilerClientManagerPrivate QmlProfilerClientManager::QmlProfilerClientManager(QObject *parent) : QObject(parent)
{
public:
QmlProfilerStateManager *profilerState;
QmlDebug::QmlDebugConnection *connection;
QPointer<QmlProfilerTraceClient> qmlclientplugin;
QTimer connectionTimer;
int connectionAttempts;
QString localSocket;
QString tcpHost;
Utils::Port tcpPort;
QString sysroot;
quint32 flushInterval;
bool aggregateTraces;
QmlProfilerModelManager *modelManager;
};
QmlProfilerClientManager::QmlProfilerClientManager(QObject *parent) :
QObject(parent), d(new QmlProfilerClientManagerPrivate)
{ {
setObjectName(QLatin1String("QML Profiler Connections")); setObjectName(QLatin1String("QML Profiler Connections"));
d->profilerState = 0;
d->connection = 0;
d->connectionAttempts = 0;
d->flushInterval = 0;
d->aggregateTraces = true;
d->modelManager = 0;
d->connectionTimer.setInterval(200);
connect(&d->connectionTimer, &QTimer::timeout, this, &QmlProfilerClientManager::tryToConnect);
}
QmlProfilerClientManager::~QmlProfilerClientManager()
{
delete d->connection;
delete d->qmlclientplugin.data();
delete d;
} }
void QmlProfilerClientManager::setModelManager(QmlProfilerModelManager *m) void QmlProfilerClientManager::setModelManager(QmlProfilerModelManager *m)
{ {
d->modelManager = m; QTC_ASSERT(m_connection.isNull() && m_qmlclientplugin.isNull(), disconnectClient());
m_modelManager = m;
} }
void QmlProfilerClientManager::setFlushInterval(quint32 flushInterval) void QmlProfilerClientManager::setFlushInterval(quint32 flushInterval)
{ {
d->flushInterval = flushInterval; m_flushInterval = flushInterval;
} }
bool QmlProfilerClientManager::aggregateTraces() const bool QmlProfilerClientManager::aggregateTraces() const
{ {
return d->aggregateTraces; return m_aggregateTraces;
} }
void QmlProfilerClientManager::setAggregateTraces(bool aggregateTraces) void QmlProfilerClientManager::setAggregateTraces(bool aggregateTraces)
{ {
d->aggregateTraces = aggregateTraces; m_aggregateTraces = aggregateTraces;
}
void QmlProfilerClientManager::setRetryParams(int interval, int maxAttempts)
{
m_retryInterval = interval;
m_maximumRetries = maxAttempts;
} }
void QmlProfilerClientManager::setTcpConnection(QString host, Utils::Port port) void QmlProfilerClientManager::setTcpConnection(QString host, Utils::Port port)
{ {
d->tcpHost = host; if (!m_localSocket.isEmpty() || m_tcpHost != host || m_tcpPort != port) {
d->tcpPort = port; m_tcpHost = host;
d->localSocket.clear(); m_tcpPort = port;
m_localSocket.clear();
disconnectClient(); disconnectClient();
// Wait for the application to announce the port before connecting. stopConnectionTimer();
}
} }
void QmlProfilerClientManager::setLocalSocket(QString file) void QmlProfilerClientManager::setLocalSocket(QString file)
{ {
d->localSocket = file; if (m_localSocket != file || !m_tcpHost.isEmpty() || m_tcpPort.isValid()) {
d->tcpHost.clear(); m_localSocket = file;
d->tcpPort = Utils::Port(); m_tcpHost.clear();
m_tcpPort = Utils::Port();
disconnectClient(); disconnectClient();
// We open the server and the application connects to it, so let's do that right away. stopConnectionTimer();
connectLocalClient(file); }
}
void QmlProfilerClientManager::clearConnection()
{
m_localSocket.clear();
m_tcpHost.clear();
m_tcpPort = Utils::Port();
disconnectClient();
stopConnectionTimer();
} }
void QmlProfilerClientManager::clearBufferedData() void QmlProfilerClientManager::clearBufferedData()
{ {
if (d->qmlclientplugin) if (m_qmlclientplugin)
d->qmlclientplugin.data()->clearData(); m_qmlclientplugin->clearData();
} }
void QmlProfilerClientManager::connectTcpClient(Utils::Port port) void QmlProfilerClientManager::connectToTcpServer()
{ {
if (d->connection) { if (m_connection.isNull()) {
if (port == d->tcpPort) { QTC_ASSERT(m_qmlclientplugin.isNull(), disconnectClient());
tryToConnect(); createConnection();
return; QTC_ASSERT(m_connection, emit connectionFailed(); return);
m_connection->connectToHost(m_tcpHost, m_tcpPort.number());
}
// Calling this again when we're already trying means "reset the retry timer". This is
// useful in cases where we have to parse the port from the output. We might waste retries
// on an initial guess for the port.
stopConnectionTimer();
connect(&m_connectionTimer, &QTimer::timeout, this, [this]{
QTC_ASSERT(!isConnected(), return);
if (++(m_numRetries) < m_maximumRetries) {
if (m_connection.isNull()) {
// If the previous connection failed, recreate it.
createConnection();
m_connection->connectToHost(m_tcpHost, m_tcpPort.number());
} else if (m_numRetries < 3
&& m_connection->socketState() != QAbstractSocket::ConnectedState) {
// If we don't get connected in the first retry interval, drop the socket and try
// with a new one. On some operating systems (maxOS) the very first connection to a
// TCP server takes a very long time to get established and this helps.
// On other operating systems (windows) every connection takes forever to get
// established. So, after tearing down and rebuilding the socket twice, just
// keep trying with the same one.
m_connection->connectToHost(m_tcpHost, m_tcpPort.number());
} // Else leave it alone and wait for hello.
} else { } else {
delete d->connection; // On final timeout, clear the connection.
} stopConnectionTimer();
} if (m_connection)
createConnection();
d->connectionTimer.start();
d->tcpPort = port;
d->connection->connectToHost(d->tcpHost, d->tcpPort.number());
}
void QmlProfilerClientManager::connectLocalClient(const QString &file)
{
if (d->connection) {
if (file == d->localSocket)
return;
else
delete d->connection;
}
createConnection();
d->localSocket = file;
d->connection->startLocalServer(file);
}
void QmlProfilerClientManager::createConnection()
{
d->connection = new QmlDebug::QmlDebugConnection;
QTC_ASSERT(d->profilerState, return);
disconnectClientSignals(); disconnectClientSignals();
d->profilerState->setServerRecording(false); // false by default (will be set to true when connected) m_qmlclientplugin.reset();
delete d->qmlclientplugin.data(); m_connection.reset();
d->profilerState->setRecordedFeatures(0); emit connectionFailed();
d->qmlclientplugin = new QmlProfilerTraceClient(d->connection, }
d->modelManager->qmlModel(), });
d->profilerState->requestedFeatures()); m_connectionTimer.start(m_retryInterval);
d->qmlclientplugin->setFlushInterval(d->flushInterval); }
connectClientSignals();
connect(d->connection, &QmlDebug::QmlDebugConnection::connected,
this, &QmlProfilerClientManager::qmlDebugConnectionOpened);
connect(d->connection, &QmlDebug::QmlDebugConnection::disconnected,
this, &QmlProfilerClientManager::qmlDebugConnectionClosed);
connect(d->connection, &QmlDebug::QmlDebugConnection::connectionFailed,
this, &QmlProfilerClientManager::qmlDebugConnectionFailed);
connect(d->connection, &QmlDebug::QmlDebugConnection::logError, void QmlProfilerClientManager::startLocalServer()
this, &QmlProfilerClientManager::logState); {
connect(d->connection, &QmlDebug::QmlDebugConnection::logStateChange, if (m_connection.isNull()) {
this, &QmlProfilerClientManager::logState); // Otherwise, reuse the same one
QTC_ASSERT(m_qmlclientplugin.isNull(), disconnectClient());
createConnection();
QTC_ASSERT(m_connection, emit connectionFailed(); return);
m_connection->startLocalServer(m_localSocket);
}
stopConnectionTimer();
connect(&m_connectionTimer, &QTimer::timeout, this, [this]() {
QTC_ASSERT(!isConnected(), return);
// We leave the server running as some application might currently be trying to
// connect. Don't cut this off, or the application might hang on the hello mutex.
// qmlConnectionFailed() might drop the connection, which is fatal. We detect this
// here and signal it accordingly.
if (!m_connection || ++(m_numRetries) >= m_maximumRetries) {
stopConnectionTimer();
emit connectionFailed();
}
});
m_connectionTimer.start(m_retryInterval);
} }
void QmlProfilerClientManager::retryConnect() void QmlProfilerClientManager::retryConnect()
{ {
if (!m_localSocket.isEmpty()) {
startLocalServer();
} else if (!m_tcpHost.isEmpty() && m_tcpPort.isValid()) {
disconnectClient(); disconnectClient();
if (!d->localSocket.isEmpty()) connectToTcpServer();
connectLocalClient(d->localSocket); } else {
else if (!d->tcpHost.isEmpty() && d->tcpPort.isValid())
connectTcpClient(d->tcpPort);
else
emit connectionFailed(); emit connectionFailed();
} }
}
void QmlProfilerClientManager::createConnection()
{
QTC_ASSERT(m_profilerState, return);
QTC_ASSERT(m_modelManager, return);
QTC_ASSERT(m_connection.isNull() && m_qmlclientplugin.isNull(), disconnectClient());
m_connection.reset(new QmlDebug::QmlDebugConnection);
// false by default (will be set to true when connected)
m_profilerState->setServerRecording(false);
m_profilerState->setRecordedFeatures(0);
m_qmlclientplugin.reset(new QmlProfilerTraceClient(m_connection.data(),
m_modelManager->qmlModel(),
m_profilerState->requestedFeatures()));
m_qmlclientplugin->setFlushInterval(m_flushInterval);
connectClientSignals();
}
void QmlProfilerClientManager::connectClientSignals() void QmlProfilerClientManager::connectClientSignals()
{ {
QTC_ASSERT(d->profilerState, return); QTC_ASSERT(m_connection, return);
if (d->qmlclientplugin) { QObject::connect(m_connection.data(), &QmlDebug::QmlDebugConnection::connected,
connect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::complete, this, &QmlProfilerClientManager::qmlDebugConnectionOpened);
QObject::connect(m_connection.data(), &QmlDebug::QmlDebugConnection::disconnected,
this, &QmlProfilerClientManager::qmlDebugConnectionClosed);
QObject::connect(m_connection.data(), &QmlDebug::QmlDebugConnection::connectionFailed,
this, &QmlProfilerClientManager::qmlDebugConnectionFailed);
QObject::connect(m_connection.data(), &QmlDebug::QmlDebugConnection::logStateChange,
this, &QmlProfilerClientManager::logState);
QObject::connect(m_connection.data(), &QmlDebug::QmlDebugConnection::logError,
this, &QmlProfilerClientManager::logState);
QTC_ASSERT(m_qmlclientplugin, return);
QObject::connect(m_qmlclientplugin.data(), &QmlProfilerTraceClient::complete,
this, &QmlProfilerClientManager::qmlComplete); this, &QmlProfilerClientManager::qmlComplete);
connect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::newEngine, QObject::connect(m_qmlclientplugin.data(), &QmlProfilerTraceClient::newEngine,
this, &QmlProfilerClientManager::qmlNewEngine); this, &QmlProfilerClientManager::qmlNewEngine);
connect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::traceFinished,
d->modelManager->traceTime(), &QmlProfilerTraceTime::increaseEndTime); QTC_ASSERT(m_modelManager, return);
connect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::traceStarted, QObject::connect(m_qmlclientplugin.data(), &QmlProfilerTraceClient::traceFinished,
d->modelManager->traceTime(), &QmlProfilerTraceTime::decreaseStartTime); m_modelManager->traceTime(), &QmlProfilerTraceTime::increaseEndTime);
connect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::recordingChanged, QObject::connect(m_qmlclientplugin.data(), &QmlProfilerTraceClient::traceStarted,
d->profilerState, &QmlProfilerStateManager::setServerRecording); m_modelManager->traceTime(), &QmlProfilerTraceTime::decreaseStartTime);
connect(d->profilerState, &QmlProfilerStateManager::requestedFeaturesChanged,
d->qmlclientplugin.data(), &QmlProfilerTraceClient::setRequestedFeatures); QTC_ASSERT(m_profilerState, return);
connect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::recordedFeaturesChanged, QObject::connect(m_qmlclientplugin.data(), &QmlProfilerTraceClient::recordingChanged,
d->profilerState, &QmlProfilerStateManager::setRecordedFeatures); m_profilerState, &QmlProfilerStateManager::setServerRecording);
} QObject::connect(m_profilerState, &QmlProfilerStateManager::requestedFeaturesChanged,
m_qmlclientplugin.data(), &QmlProfilerTraceClient::setRequestedFeatures);
QObject::connect(m_qmlclientplugin.data(), &QmlProfilerTraceClient::recordedFeaturesChanged,
m_profilerState, &QmlProfilerStateManager::setRecordedFeatures);
} }
void QmlProfilerClientManager::disconnectClientSignals() void QmlProfilerClientManager::disconnectClientSignals()
{ {
if (d->qmlclientplugin) { QTC_ASSERT(m_connection, return);
disconnect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::complete, m_connection->disconnect();
this, &QmlProfilerClientManager::qmlComplete);
disconnect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::newEngine, QTC_ASSERT(m_qmlclientplugin, return);
this, &QmlProfilerClientManager::qmlNewEngine); m_qmlclientplugin->disconnect();
disconnect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::traceFinished,
d->modelManager->traceTime(), &QmlProfilerTraceTime::increaseEndTime); QTC_ASSERT(m_profilerState, return);
disconnect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::traceStarted, QObject::disconnect(m_profilerState, &QmlProfilerStateManager::requestedFeaturesChanged,
d->modelManager->traceTime(), &QmlProfilerTraceTime::decreaseStartTime); m_qmlclientplugin.data(), &QmlProfilerTraceClient::setRequestedFeatures);
disconnect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::recordingChanged,
d->profilerState, &QmlProfilerStateManager::setServerRecording);
disconnect(d->profilerState, &QmlProfilerStateManager::requestedFeaturesChanged,
d->qmlclientplugin.data(), &QmlProfilerTraceClient::setRequestedFeatures);
disconnect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::recordedFeaturesChanged,
d->profilerState, &QmlProfilerStateManager::setRecordedFeatures);
}
} }
bool QmlProfilerClientManager::isConnected() const bool QmlProfilerClientManager::isConnected() const
{ {
return d->connection && d->connection->isConnected(); return m_connection && m_connection->isConnected();
} }
void QmlProfilerClientManager::disconnectClient() void QmlProfilerClientManager::disconnectClient()
{ {
// this might be actually be called indirectly by QDDConnectionPrivate::readyRead(), therefore allow // This might be called indirectly by QDebugConnectionPrivate::readyRead().
// function to complete before deleting object // Therefore, allow the function to complete before deleting the object.
if (d->connection) { if (m_connection) {
d->connection->deleteLater(); // Don't receive any more signals from the connection or the client
d->connection = 0; disconnectClientSignals();
}
}
void QmlProfilerClientManager::tryToConnect() QTC_ASSERT(m_connection && m_qmlclientplugin, return);
{ m_qmlclientplugin.take()->deleteLater();
++d->connectionAttempts; m_connection.take()->deleteLater();
if (d->connection && d->connection->isConnected()) {
d->connectionTimer.stop();
d->connectionAttempts = 0;
} else if (d->connection && d->connection->socketState() != QAbstractSocket::ConnectedState) {
if (d->connectionAttempts < 3) {
// Replace the connection after trying for some time. On some operating systems (OSX) the
// very first connection to a TCP server takes a very long time to get established.
// delete directly here, so that any pending events aren't delivered. We don't want the
// connection first to be established and then torn down again.
delete d->connection;
d->connection = 0;
connectTcpClient(d->tcpPort);
} else if (!d->connection->isConnecting()) {
d->connection->connectToHost(d->tcpHost, d->tcpPort.number());
}
} else if (d->connectionAttempts == 50) {
d->connectionTimer.stop();
d->connectionAttempts = 0;
delete d->connection; // delete directly.
d->connection = 0;
emit connectionFailed();
} }
} }
void QmlProfilerClientManager::qmlDebugConnectionOpened() void QmlProfilerClientManager::qmlDebugConnectionOpened()
{ {
logState(tr("Debug connection opened")); logState(tr("Debug connection opened"));
QTC_ASSERT(m_connection && m_qmlclientplugin, return);
QTC_ASSERT(m_connection->isConnected(), return);
stopConnectionTimer();
clientRecordingChanged(); clientRecordingChanged();
emit connectionOpened();
} }
void QmlProfilerClientManager::qmlDebugConnectionClosed() void QmlProfilerClientManager::qmlDebugConnectionClosed()
{ {
logState(tr("Debug connection closed")); logState(tr("Debug connection closed"));
QTC_ASSERT(m_connection && m_qmlclientplugin, return);
QTC_ASSERT(!m_connection->isConnected(), return);
disconnectClient(); disconnectClient();
emit connectionClosed(); emit connectionClosed();
} }
void QmlProfilerClientManager::qmlDebugConnectionFailed() void QmlProfilerClientManager::qmlDebugConnectionFailed()
{ {
if (d->connection->isConnected()) { logState(tr("Debug connection failed"));
QTC_ASSERT(m_connection && m_qmlclientplugin, return);
QTC_ASSERT(!m_connection->isConnected(), /**/);
disconnectClient(); disconnectClient();
emit connectionClosed(); // The retry handler, driven by m_connectionTimer should decide to retry or signal a failure.
} else {
disconnectClient(); QTC_ASSERT(m_connectionTimer.isActive(), emit connectionFailed());
}
} }
void QmlProfilerClientManager::logState(const QString &msg) void QmlProfilerClientManager::logState(const QString &msg)
@@ -314,51 +310,56 @@ void QmlProfilerClientManager::logState(const QString &msg)
void QmlProfilerClientManager::qmlComplete(qint64 maximumTime) void QmlProfilerClientManager::qmlComplete(qint64 maximumTime)
{ {
if (d->profilerState->currentState() == QmlProfilerStateManager::AppStopRequested) QTC_ASSERT(m_profilerState && m_modelManager, return);
d->profilerState->setCurrentState(QmlProfilerStateManager::Idle); if (m_profilerState->currentState() == QmlProfilerStateManager::AppStopRequested)
d->modelManager->traceTime()->increaseEndTime(maximumTime); m_profilerState->setCurrentState(QmlProfilerStateManager::Idle);
if (d->modelManager && !d->aggregateTraces) m_modelManager->traceTime()->increaseEndTime(maximumTime);
d->modelManager->acquiringDone(); if (m_modelManager && !m_aggregateTraces)
m_modelManager->acquiringDone();
} }
void QmlProfilerClientManager::qmlNewEngine(int engineId) void QmlProfilerClientManager::qmlNewEngine(int engineId)
{ {
if (d->qmlclientplugin->isRecording() != d->profilerState->clientRecording()) QTC_ASSERT(m_connection && m_qmlclientplugin, return);
d->qmlclientplugin->setRecording(d->profilerState->clientRecording()); if (m_qmlclientplugin->isRecording() != m_profilerState->clientRecording())
m_qmlclientplugin->setRecording(m_profilerState->clientRecording());
else else
d->qmlclientplugin->sendRecordingStatus(engineId); m_qmlclientplugin->sendRecordingStatus(engineId);
} }
void QmlProfilerClientManager::setProfilerStateManager(QmlProfilerStateManager *profilerState) void QmlProfilerClientManager::setProfilerStateManager(QmlProfilerStateManager *profilerState)
{ {
if (d->profilerState) { // Don't do this while connecting
disconnect(d->profilerState, &QmlProfilerStateManager::stateChanged, QTC_ASSERT(m_connection.isNull() && m_qmlclientplugin.isNull(), disconnectClient());
if (m_profilerState) {
disconnect(m_profilerState, &QmlProfilerStateManager::stateChanged,
this, &QmlProfilerClientManager::profilerStateChanged); this, &QmlProfilerClientManager::profilerStateChanged);
disconnect(d->profilerState, &QmlProfilerStateManager::clientRecordingChanged, disconnect(m_profilerState, &QmlProfilerStateManager::clientRecordingChanged,
this, &QmlProfilerClientManager::clientRecordingChanged); this, &QmlProfilerClientManager::clientRecordingChanged);
} }
d->profilerState = profilerState; m_profilerState = profilerState;
// connect // connect
if (d->profilerState) { if (m_profilerState) {
connect(d->profilerState, &QmlProfilerStateManager::stateChanged, connect(m_profilerState, &QmlProfilerStateManager::stateChanged,
this, &QmlProfilerClientManager::profilerStateChanged); this, &QmlProfilerClientManager::profilerStateChanged);
connect(d->profilerState, &QmlProfilerStateManager::clientRecordingChanged, connect(m_profilerState, &QmlProfilerStateManager::clientRecordingChanged,
this, &QmlProfilerClientManager::clientRecordingChanged); this, &QmlProfilerClientManager::clientRecordingChanged);
} }
} }
void QmlProfilerClientManager::profilerStateChanged() void QmlProfilerClientManager::profilerStateChanged()
{ {
QTC_ASSERT(d->profilerState, return); QTC_ASSERT(m_profilerState, return);
switch (d->profilerState->currentState()) { switch (m_profilerState->currentState()) {
case QmlProfilerStateManager::AppStopRequested : case QmlProfilerStateManager::AppStopRequested :
if (d->profilerState->serverRecording()) { if (m_profilerState->serverRecording()) {
if (d->qmlclientplugin) if (m_qmlclientplugin)
d->qmlclientplugin.data()->setRecording(false); m_qmlclientplugin->setRecording(false);
} else { } else {
d->profilerState->setCurrentState(QmlProfilerStateManager::Idle); m_profilerState->setCurrentState(QmlProfilerStateManager::Idle);
} }
break; break;
default: default:
@@ -368,9 +369,16 @@ void QmlProfilerClientManager::profilerStateChanged()
void QmlProfilerClientManager::clientRecordingChanged() void QmlProfilerClientManager::clientRecordingChanged()
{ {
QTC_ASSERT(d->profilerState, return); QTC_ASSERT(m_profilerState, return);
if (d->qmlclientplugin) if (m_qmlclientplugin)
d->qmlclientplugin->setRecording(d->profilerState->clientRecording()); m_qmlclientplugin->setRecording(m_profilerState->clientRecording());
}
void QmlProfilerClientManager::stopConnectionTimer()
{
m_connectionTimer.stop();
m_connectionTimer.disconnect();
m_numRetries = 0;
} }
} // namespace Internal } // namespace Internal

View File

@@ -25,16 +25,19 @@
#pragma once #pragma once
#include "qmlprofilerstatemanager.h" #include "qmlprofilertraceclient.h"
#include "qmleventlocation.h"
#include <qmldebug/qmldebugclient.h>
#include <utils/port.h> #include <utils/port.h>
#include <QPointer>
#include <QTimer>
#include <QObject> #include <QObject>
#include <QStringList> #include <QVector>
#include <QAbstractSocket>
namespace QmlProfiler { namespace QmlProfiler {
class QmlProfilerModelManager; class QmlProfilerModelManager;
class QmlProfilerStateManager;
namespace Internal { namespace Internal {
@@ -43,11 +46,11 @@ class QmlProfilerClientManager : public QObject
Q_OBJECT Q_OBJECT
public: public:
explicit QmlProfilerClientManager(QObject *parent = 0); explicit QmlProfilerClientManager(QObject *parent = 0);
~QmlProfilerClientManager();
void setProfilerStateManager(QmlProfilerStateManager *profilerState); void setProfilerStateManager(QmlProfilerStateManager *profilerState);
void setTcpConnection(QString host, Utils::Port port); void setTcpConnection(QString host, Utils::Port port);
void setLocalSocket(QString file); void setLocalSocket(QString file);
void clearConnection();
void clearBufferedData(); void clearBufferedData();
bool isConnected() const; bool isConnected() const;
@@ -58,18 +61,38 @@ public:
bool aggregateTraces() const; bool aggregateTraces() const;
void setAggregateTraces(bool aggregateTraces); void setAggregateTraces(bool aggregateTraces);
void setRetryParams(int interval, int maxAttempts);
void retryConnect();
void connectToTcpServer();
void startLocalServer();
signals: signals:
void connectionOpened();
void connectionFailed(); void connectionFailed();
void connectionClosed(); void connectionClosed();
public slots: private:
void retryConnect(); QPointer<QmlProfilerStateManager> m_profilerState;
void connectTcpClient(Utils::Port port); QPointer<QmlProfilerModelManager> m_modelManager;
void connectLocalClient(const QString &file); QScopedPointer<QmlDebug::QmlDebugConnection> m_connection;
void disconnectClient(); QScopedPointer<QmlProfilerTraceClient> m_qmlclientplugin;
QTimer m_connectionTimer;
QString m_localSocket;
QString m_tcpHost;
Utils::Port m_tcpPort;
quint32 m_flushInterval = 0;
int m_retryInterval = 200;
int m_maximumRetries = 50;
int m_numRetries = 0;
bool m_aggregateTraces = true;
void disconnectClient();
void stopConnectionTimer();
private slots:
void tryToConnect();
void qmlDebugConnectionOpened(); void qmlDebugConnectionOpened();
void qmlDebugConnectionClosed(); void qmlDebugConnectionClosed();
void qmlDebugConnectionFailed(); void qmlDebugConnectionFailed();
@@ -82,15 +105,9 @@ private slots:
void profilerStateChanged(); void profilerStateChanged();
void clientRecordingChanged(); void clientRecordingChanged();
private:
class QmlProfilerClientManagerPrivate;
QmlProfilerClientManagerPrivate *d;
void createConnection(); void createConnection();
void connectClientSignals(); void connectClientSignals();
void disconnectClientSignals(); void disconnectClientSignals();
void stopClientsRecording();
}; };
} // namespace Internal } // namespace Internal

View File

@@ -353,10 +353,13 @@ void QmlProfilerTool::finalizeRunControl(QmlProfilerRunControl *runControl)
QTC_ASSERT(runControl->connection().is<AnalyzerConnection>(), return); QTC_ASSERT(runControl->connection().is<AnalyzerConnection>(), return);
// FIXME: Check that there's something sensible in sp.connParams // FIXME: Check that there's something sensible in sp.connParams
auto connection = runControl->connection().as<AnalyzerConnection>(); auto connection = runControl->connection().as<AnalyzerConnection>();
if (!connection.analyzerSocket.isEmpty()) if (!connection.analyzerSocket.isEmpty()) {
clientManager->setLocalSocket(connection.analyzerSocket); clientManager->setLocalSocket(connection.analyzerSocket);
else // We open the server and the application connects to it, so let's do that right away.
clientManager->startLocalServer();
} else {
clientManager->setTcpConnection(connection.analyzerHost, connection.analyzerPort); clientManager->setTcpConnection(connection.analyzerHost, connection.analyzerPort);
}
// //
// Initialize m_projectFinder // Initialize m_projectFinder
@@ -370,9 +373,14 @@ void QmlProfilerTool::finalizeRunControl(QmlProfilerRunControl *runControl)
populateFileFinder(projectDirectory, sysroot(runConfiguration)); populateFileFinder(projectDirectory, sysroot(runConfiguration));
} }
if (connection.analyzerSocket.isEmpty()) if (connection.analyzerSocket.isEmpty()) {
QString host = connection.analyzerHost;
connect(runControl, &QmlProfilerRunControl::processRunning, connect(runControl, &QmlProfilerRunControl::processRunning,
d->m_profilerConnections, &QmlProfilerClientManager::connectTcpClient); clientManager, [clientManager, host](Utils::Port port) {
clientManager->setTcpConnection(host, port);
clientManager->connectToTcpServer();
});
}
connect(clientManager, &QmlProfilerClientManager::connectionFailed, connect(clientManager, &QmlProfilerClientManager::connectionFailed,
runControl, [this, clientManager, runControl]() { runControl, [this, clientManager, runControl]() {
QMessageBox *infoBox = new QMessageBox(ICore::mainWindow()); QMessageBox *infoBox = new QMessageBox(ICore::mainWindow());