Commit 24af63ec authored by Aurindam Jana's avatar Aurindam Jana Committed by hjk

Android: Add QML profiling

Change-Id: Ie06c0b49707f8ec549f180f41c565fd223240186
Reviewed-by: default avatarChristiaan Janssen <christiaan.janssen@digia.com>
Reviewed-by: default avatarhjk <hjk121@nokiamail.com>
parent c9d1c5b3
......@@ -44,7 +44,8 @@ enum StartMode
{
StartLocal = -1,
StartRemote = -2,
StartQml = -3
StartQml = -3,
StartQmlAndroid = -4 // TODO: remove this enum and make it generic
};
namespace Constants {
......
......@@ -38,6 +38,7 @@
#include <projectexplorer/taskhub.h>
#include <QDebug>
#include <QAction>
using namespace ProjectExplorer;
......@@ -85,6 +86,8 @@ AnalyzerRunControl::AnalyzerRunControl(IAnalyzerTool *tool,
SLOT(addTask(ProjectExplorer::Task::TaskType,QString,QString,int)));
connect(d->m_engine, SIGNAL(finished()),
SLOT(engineFinished()));
connect(AnalyzerManager::stopAction(), SIGNAL(triggered()), SLOT(stopIt()));
}
AnalyzerRunControl::~AnalyzerRunControl()
......@@ -159,6 +162,11 @@ QIcon AnalyzerRunControl::icon() const
return QIcon(QLatin1String(":/images/analyzer_start_small.png"));
}
IAnalyzerEngine *AnalyzerRunControl::engine() const
{
return d->m_engine;
}
void AnalyzerRunControl::receiveOutput(const QString &text, Utils::OutputFormat format)
{
appendMessage(text, format);
......
......@@ -40,6 +40,7 @@ namespace Analyzer {
class AnalyzerStartParameters;
class IAnalyzerTool;
class IAnalyzerEngine;
class ANALYZER_EXPORT AnalyzerRunControl : public ProjectExplorer::RunControl
{
......@@ -57,6 +58,8 @@ public:
QString displayName() const;
QIcon icon() const;
IAnalyzerEngine *engine() const;
private slots:
void stopIt();
void receiveOutput(const QString &, Utils::OutputFormat format);
......
......@@ -71,7 +71,6 @@ RunControl *AnalyzerRunControlFactory::create(RunConfiguration *runConfiguration
sp.toolId = tool->id();
AnalyzerRunControl *rc = new AnalyzerRunControl(tool, sp, runConfiguration);
QObject::connect(AnalyzerManager::stopAction(), SIGNAL(triggered()), rc, SLOT(stopIt()));
return rc;
}
......
......@@ -83,6 +83,11 @@ public:
IAnalyzerTool *tool() const { return m_tool; }
StartMode mode() const { return m_sp.startMode; }
virtual void notifyRemoteSetupDone(quint16) {}
public slots:
virtual void logApplicationMessage(const QString &, Utils::OutputFormat) {}
signals:
/// Should be emitted when the debuggee outputted something.
void outputReceived(const QString &, Utils::OutputFormat format);
......
......@@ -54,6 +54,7 @@ Id IAnalyzerTool::defaultActionId(const IAnalyzerTool *tool, StartMode mode)
case StartRemote:
return id.withSuffix(".Remote");
case StartQml:
case StartQmlAndroid:
return id.withSuffix(".Qml");
}
return Id();
......
......@@ -34,7 +34,9 @@ HEADERS += \
androidplugin.h \
androiddevicefactory.h \
androiddevice.h \
androidgdbserverkitinformation.h
androidgdbserverkitinformation.h \
androidanalyzesupport.h \
androidrunsupport.h
SOURCES += \
androidconfigurations.cpp \
......@@ -63,7 +65,9 @@ SOURCES += \
androidplugin.cpp \
androiddevicefactory.cpp \
androiddevice.cpp \
androidgdbserverkitinformation.cpp
androidgdbserverkitinformation.cpp \
androidanalyzesupport.cpp \
androidrunsupport.cpp
FORMS += \
androidsettingswidget.ui \
......
......@@ -20,6 +20,8 @@ QtcPlugin {
files: [
"addnewavddialog.ui",
"android.qrc",
"androidanalyzesupport.cpp",
"androidanalyzesupport.h",
"androidconfigurations.cpp",
"androidconfigurations.h",
"androidconstants.h",
......@@ -71,6 +73,8 @@ QtcPlugin {
"androidrunfactories.h",
"androidrunner.cpp",
"androidrunner.h",
"androidrunsupport.cpp",
"androidrunsupport.h",
"androidsettingspage.cpp",
"androidsettingspage.h",
"androidsettingswidget.cpp",
......
......@@ -3,4 +3,5 @@ QTC_PLUGIN_DEPENDS += \
coreplugin \
debugger \
projectexplorer \
qt4projectmanager
qt4projectmanager \
analyzerbase
/****************************************************************************
**
** 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 "androidanalyzesupport.h"
#include "androidrunner.h"
#include "androidmanager.h"
#include "analyzerbase/ianalyzertool.h"
#include "analyzerbase/ianalyzerengine.h"
#include "analyzerbase/analyzermanager.h"
#include "analyzerbase/analyzerruncontrol.h"
#include "analyzerbase/analyzerstartparameters.h"
#include <projectexplorer/target.h>
#include <projectexplorer/project.h>
#include <qtsupport/qtkitinformation.h>
#include <QDir>
#include <QTcpServer>
using namespace Analyzer;
using namespace ProjectExplorer;
namespace Android {
namespace Internal {
RunControl *AndroidAnalyzeSupport::createAnalyzeRunControl(AndroidRunConfiguration *runConfig,
RunMode runMode, QString *errorMessage)
{
IAnalyzerTool *tool = AnalyzerManager::toolFromRunMode(runMode);
if (!tool) {
if (errorMessage)
*errorMessage = tr("No analyzer tool selected");
return 0;
}
AnalyzerStartParameters params;
params.toolId = tool->id();
params.startMode = StartQmlAndroid;
Target *target = runConfig->target();
params.displayName = AndroidManager::packageName(target);
params.sysroot = SysRootKitInformation::sysRoot(target->kit()).toString();
// TODO: Not sure if these are the right paths.
params.workingDirectory = target->project()->projectDirectory();
if (runMode == ProjectExplorer::QmlProfilerRunMode) {
QTcpServer server;
QTC_ASSERT(server.listen(QHostAddress::LocalHost)
|| server.listen(QHostAddress::LocalHostIPv6), return 0);
params.analyzerHost = server.serverAddress().toString();
}
AnalyzerRunControl * const analyzerRunControl = new AnalyzerRunControl(tool, params, runConfig);
new AndroidAnalyzeSupport(runConfig, analyzerRunControl);
return analyzerRunControl;
}
AndroidAnalyzeSupport::AndroidAnalyzeSupport(AndroidRunConfiguration *runConfig,
AnalyzerRunControl *runControl)
: AndroidRunSupport(runConfig, runControl),
m_engine(0)
{
if (runControl) {
m_engine = runControl->engine();
if (m_engine) {
connect(m_engine, SIGNAL(starting(const Analyzer::IAnalyzerEngine*)),
m_runner, SLOT(start()));
}
}
}
void AndroidAnalyzeSupport::handleRemoteProcessStarted(int qmlPort)
{
if (m_engine)
m_engine->notifyRemoteSetupDone(qmlPort);
}
void AndroidAnalyzeSupport::handleRemoteOutput(const QByteArray &output)
{
if (m_engine)
m_engine->logApplicationMessage(QString::fromUtf8(output), Utils::StdOutFormatSameLine);
else
AndroidRunSupport::handleRemoteOutput(output);
}
void AndroidAnalyzeSupport::handleRemoteErrorOutput(const QByteArray &output)
{
if (m_engine)
m_engine->logApplicationMessage(QString::fromUtf8(output), Utils::StdErrFormatSameLine);
else
AndroidRunSupport::handleRemoteErrorOutput(output);
}
} // namespace Internal
} // namespace Android
/****************************************************************************
**
** 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.
**
****************************************************************************/
#ifndef ANDROIDANALYZESUPPORT_H
#define ANDROIDANALYZESUPPORT_H
#include "androidrunsupport.h"
namespace Analyzer {
class IAnalyzerEngine;
class AnalyzerRunControl;
}
namespace ProjectExplorer { class RunControl; }
namespace Android {
namespace Internal {
class AndroidRunConfiguration;
class AndroidRunner;
class AndroidAnalyzeSupport : public AndroidRunSupport
{
Q_OBJECT
public:
static ProjectExplorer::RunControl *createAnalyzeRunControl(AndroidRunConfiguration *runConfig,
ProjectExplorer::RunMode runMode,
QString *errorMessage);
AndroidAnalyzeSupport(AndroidRunConfiguration *runConfig,
Analyzer::AnalyzerRunControl *runControl);
private slots:
void handleRemoteProcessStarted(int qmlPort);
void handleRemoteOutput(const QByteArray &output);
void handleRemoteErrorOutput(const QByteArray &output);
private:
Analyzer::IAnalyzerEngine *m_engine;
};
} // namespace Internal
} // namespace Android
#endif // ANDROIDANALYZESUPPORT_H
......@@ -133,68 +133,70 @@ RunControl *AndroidDebugSupport::createDebugRunControl(AndroidRunConfiguration *
AndroidDebugSupport::AndroidDebugSupport(AndroidRunConfiguration *runConfig,
DebuggerRunControl *runControl)
: QObject(runControl), m_runControl(runControl),
m_runner(new AndroidRunner(this, runConfig, true))
: AndroidRunSupport(runConfig, runControl),
m_engine(0)
{
Debugger::DebuggerRunConfigurationAspect *aspect
= runConfig->extraAspect<Debugger::DebuggerRunConfigurationAspect>();
Q_ASSERT(aspect->useCppDebugger() || aspect->useQmlDebugger());
connect(m_runControl->engine(), SIGNAL(requestRemoteSetup()),
m_runner, SLOT(start()));
connect(m_runControl, SIGNAL(finished()),
m_runner, SLOT(stop()));
connect(m_runControl->engine(), SIGNAL(aboutToNotifyInferiorSetupOk()),
m_runner, SLOT(handleRemoteDebuggerRunning()));
connect(m_runner, SIGNAL(remoteServerRunning(QByteArray,int)),
SLOT(handleRemoteServerRunning(QByteArray,int)));
connect(m_runner, SIGNAL(remoteProcessStarted(int,int)),
SLOT(handleRemoteProcessStarted(int,int)));
connect(m_runner, SIGNAL(remoteProcessFinished(QString)),
SLOT(handleRemoteProcessFinished(QString)));
connect(m_runner, SIGNAL(remoteErrorOutput(QByteArray)),
SLOT(handleRemoteErrorOutput(QByteArray)));
connect(m_runner, SIGNAL(remoteOutput(QByteArray)),
SLOT(handleRemoteOutput(QByteArray)));
if (runControl)
m_engine = runControl->engine();
if (m_engine) {
connect(m_engine, SIGNAL(requestRemoteSetup()),
m_runner, SLOT(start()));
connect(m_engine, SIGNAL(aboutToNotifyInferiorSetupOk()),
m_runner, SLOT(handleRemoteDebuggerRunning()));
}
}
void AndroidDebugSupport::handleRemoteServerRunning(const QByteArray &serverChannel, int pid)
{
m_runControl->engine()->notifyEngineRemoteServerRunning(serverChannel, pid);
if (m_engine)
m_engine->notifyEngineRemoteServerRunning(serverChannel, pid);
}
void AndroidDebugSupport::handleRemoteProcessStarted(int gdbServerPort, int qmlPort)
{
disconnect(m_runner, SIGNAL(remoteProcessStarted(int,int)),
this, SLOT(handleRemoteProcessStarted(int,int)));
m_runControl->engine()->notifyEngineRemoteSetupDone(gdbServerPort, qmlPort);
if (m_engine)
m_engine->notifyEngineRemoteSetupDone(gdbServerPort, qmlPort);
}
void AndroidDebugSupport::handleRemoteProcessFinished(const QString &errorMsg)
{
if (m_runControl)
m_runControl->showMessage(errorMsg, AppStuff);
DebuggerRunControl *runControl = qobject_cast<DebuggerRunControl *>(m_runControl);
if (runControl)
runControl->showMessage(errorMsg, AppStuff);
else
AndroidRunSupport::handleRemoteProcessFinished(errorMsg);
}
void AndroidDebugSupport::handleRemoteOutput(const QByteArray &output)
{
if (m_runControl) {
if (m_runControl->engine())
m_runControl->engine()->showMessage(QString::fromUtf8(output), AppOutput);
if (m_engine) {
m_engine->showMessage(QString::fromUtf8(output), AppOutput);
} else {
DebuggerRunControl *runControl = qobject_cast<DebuggerRunControl *>(m_runControl);
if (runControl)
runControl->showMessage(QString::fromUtf8(output), AppOutput);
else
m_runControl->showMessage(QString::fromUtf8(output), AppOutput);
AndroidRunSupport::handleRemoteOutput(output);
}
}
void AndroidDebugSupport::handleRemoteErrorOutput(const QByteArray &output)
{
if (m_runControl) {
if (m_runControl->engine())
m_runControl->engine()->showMessage(QString::fromUtf8(output), AppError);
if (m_engine) {
m_engine->showMessage(QString::fromUtf8(output), AppError);
} else {
DebuggerRunControl *runControl = qobject_cast<DebuggerRunControl *>(m_runControl);
if (runControl)
runControl->showMessage(QString::fromUtf8(output), AppError);
else
m_runControl->showMessage(QString::fromUtf8(output), AppError);
AndroidRunSupport::handleRemoteErrorOutput(output);
}
}
......
......@@ -30,9 +30,12 @@
#ifndef ANDROIDDEBUGSUPPORT_H
#define ANDROIDDEBUGSUPPORT_H
#include "androidrunconfiguration.h"
#include "androidrunsupport.h"
namespace Debugger { class DebuggerRunControl; }
namespace Debugger {
class DebuggerEngine;
class DebuggerRunControl;
}
namespace ProjectExplorer { class RunControl; }
namespace Android {
......@@ -41,7 +44,7 @@ namespace Internal {
class AndroidRunConfiguration;
class AndroidRunner;
class AndroidDebugSupport : public QObject
class AndroidDebugSupport : public AndroidRunSupport
{
Q_OBJECT
......@@ -61,9 +64,7 @@ private slots:
void handleRemoteErrorOutput(const QByteArray &output);
private:
Debugger::DebuggerRunControl* m_runControl;
AndroidRunner * const m_runner;
const QString m_dumperLib;
Debugger::DebuggerEngine *m_engine;
};
} // namespace Internal
......
......@@ -45,7 +45,7 @@ namespace Internal {
AndroidRunControl::AndroidRunControl(AndroidRunConfiguration *rc)
: RunControl(rc, NormalRunMode)
, m_runner(new AndroidRunner(this, rc, false))
, m_runner(new AndroidRunner(this, rc, NormalRunMode))
, m_running(false)
{
}
......
......@@ -31,6 +31,7 @@
#include "androidconstants.h"
#include "androiddebugsupport.h"
#include "androidanalyzesupport.h"
#include "androidrunconfiguration.h"
#include "androidruncontrol.h"
#include "androidmanager.h"
......@@ -150,7 +151,7 @@ AndroidRunControlFactory::AndroidRunControlFactory(QObject *parent)
bool AndroidRunControlFactory::canRun(RunConfiguration *runConfiguration,
ProjectExplorer::RunMode mode) const
{
if (mode != NormalRunMode && mode != DebugRunMode)
if (mode != NormalRunMode && mode != DebugRunMode && mode != QmlProfilerRunMode)
return false;
return qobject_cast<AndroidRunConfiguration *>(runConfiguration);
}
......@@ -161,10 +162,21 @@ RunControl *AndroidRunControlFactory::create(RunConfiguration *runConfig,
Q_ASSERT(canRun(runConfig, mode));
AndroidRunConfiguration *rc = qobject_cast<AndroidRunConfiguration *>(runConfig);
Q_ASSERT(rc);
if (mode == NormalRunMode)
switch (mode) {
case NormalRunMode:
return new AndroidRunControl(rc);
else
case DebugRunMode:
return AndroidDebugSupport::createDebugRunControl(rc, errorMessage);
case QmlProfilerRunMode:
return AndroidAnalyzeSupport::createAnalyzeRunControl(rc, mode, errorMessage);
case NoRunMode:
case DebugRunModeWithBreakOnMain:
case CallgrindRunMode:
case MemcheckRunMode:
default:
QTC_CHECK(false); // The other run modes are not supported
}
return 0;
}
} // namespace Internal
......
......@@ -49,19 +49,23 @@ namespace Internal {
typedef QLatin1String _;
AndroidRunner::AndroidRunner(QObject *parent, AndroidRunConfiguration *runConfig, bool debuggingMode)
AndroidRunner::AndroidRunner(QObject *parent,
AndroidRunConfiguration *runConfig,
ProjectExplorer::RunMode runMode)
: QThread(parent)
{
m_wasStarted = false;
Debugger::DebuggerRunConfigurationAspect *aspect
= runConfig->extraAspect<Debugger::DebuggerRunConfigurationAspect>();
const bool debuggingMode = runMode == ProjectExplorer::DebugRunMode;
m_useCppDebugger = debuggingMode && aspect->useCppDebugger();
m_useQmlDebugger = debuggingMode && aspect->useQmlDebugger();
QString channel = runConfig->remoteChannel();
QTC_CHECK(channel.startsWith(QLatin1Char(':')));
m_localGdbServerPort = channel.mid(1).toUShort();
QTC_CHECK(m_localGdbServerPort);
if (m_useQmlDebugger) {
m_useQmlProfiler = runMode == ProjectExplorer::QmlProfilerRunMode;
if (m_useQmlDebugger || m_useQmlProfiler) {
QTcpServer server;
QTC_ASSERT(server.listen(QHostAddress::LocalHost)
|| server.listen(QHostAddress::LocalHostIPv6),
......@@ -220,7 +224,8 @@ void AndroidRunner::asyncStart()
args << _("-e") << _("gdbserver_command") << m_gdbserverCommand;
args << _("-e") << _("gdbserver_socket") << m_gdbserverSocket;
}
if (m_useQmlDebugger) {
if (m_useQmlDebugger || m_useQmlProfiler) {
// currently forward to same port on device and host
const QString port = QString::fromLatin1("tcp:%1").arg(m_qmlPort);
QProcess adb;
......@@ -304,6 +309,8 @@ void AndroidRunner::asyncStart()
// gdb. Afterwards this ends up in handleRemoteDebuggerRunning() below.
QByteArray serverChannel = QByteArray::number(m_qmlPort);
emit remoteServerRunning(serverChannel, m_processPID);
} else if (m_useQmlProfiler) {
emit remoteProcessStarted(m_qmlPort);
} else {
// Start without debugging.
emit remoteProcessStarted(-1, -1);
......
......@@ -32,6 +32,8 @@
#include "androidconfigurations.h"
#include <projectexplorer/projectexplorerconstants.h>
#include <QObject>
#include <QTimer>
#include <QThread>
......@@ -48,7 +50,8 @@ class AndroidRunner : public QThread
Q_OBJECT
public:
AndroidRunner(QObject *parent, AndroidRunConfiguration *runConfig, bool debuggingMode);
AndroidRunner(QObject *parent, AndroidRunConfiguration *runConfig,
ProjectExplorer::RunMode runMode);
~AndroidRunner();
QString displayName() const;
......@@ -61,6 +64,7 @@ public slots:
signals:
void remoteServerRunning(const QByteArray &serverChannel, int pid);
void remoteProcessStarted(int gdbServerPort, int qmlPort);
void remoteProcessStarted(int qmlPort);
void remoteProcessFinished(const QString &errString = QString());
void remoteOutput(const QByteArray &output);
......@@ -92,6 +96,7 @@ private:
qint64 m_processPID;
bool m_useCppDebugger;
bool m_useQmlDebugger;
bool m_useQmlProfiler;
ushort m_localGdbServerPort; // Local end of forwarded debug socket.
quint16 m_qmlPort;
bool m_useLocalQtLibs;
......
/****************************************************************************
**
** 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 "androidrunsupport.h"
#include "androidrunner.h"