forked from qt-creator/qt-creator
Android: Setup QML debugging
Change-Id: Ida96411f9710bd9a968d4b934fb50f69bf3666fc Reviewed-by: Kai Koehne <kai.koehne@digia.com> Reviewed-by: Aurindam Jana <aurindam.jana@digia.com>
This commit is contained in:
@@ -49,6 +49,7 @@
|
|||||||
#include <qtsupport/qtkitinformation.h>
|
#include <qtsupport/qtkitinformation.h>
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QTcpServer>
|
||||||
|
|
||||||
using namespace Debugger;
|
using namespace Debugger;
|
||||||
using namespace ProjectExplorer;
|
using namespace ProjectExplorer;
|
||||||
@@ -113,8 +114,11 @@ RunControl *AndroidDebugSupport::createDebugRunControl(AndroidRunConfiguration *
|
|||||||
}
|
}
|
||||||
if (aspect->useQmlDebugger()) {
|
if (aspect->useQmlDebugger()) {
|
||||||
params.languages |= QmlLanguage;
|
params.languages |= QmlLanguage;
|
||||||
params.qmlServerAddress = QLatin1String("localhost");
|
QTcpServer server;
|
||||||
params.qmlServerPort = aspect->qmlDebugServerPort();
|
QTC_ASSERT(server.listen(QHostAddress::LocalHost)
|
||||||
|
|| server.listen(QHostAddress::LocalHostIPv6), return 0);
|
||||||
|
params.qmlServerAddress = server.serverAddress().toString();
|
||||||
|
params.remoteSetupNeeded = true;
|
||||||
//TODO: Not sure if these are the right paths.
|
//TODO: Not sure if these are the right paths.
|
||||||
params.projectSourceDirectory = project->projectDirectory();
|
params.projectSourceDirectory = project->projectDirectory();
|
||||||
params.projectSourceFiles = project->files(Qt4Project::ExcludeGeneratedFiles);
|
params.projectSourceFiles = project->files(Qt4Project::ExcludeGeneratedFiles);
|
||||||
@@ -141,7 +145,7 @@ AndroidDebugSupport::AndroidDebugSupport(AndroidRunConfiguration *runConfig,
|
|||||||
connect(m_runControl, SIGNAL(finished()),
|
connect(m_runControl, SIGNAL(finished()),
|
||||||
m_runner, SLOT(stop()));
|
m_runner, SLOT(stop()));
|
||||||
connect(m_runControl->engine(), SIGNAL(aboutToNotifyInferiorSetupOk()),
|
connect(m_runControl->engine(), SIGNAL(aboutToNotifyInferiorSetupOk()),
|
||||||
m_runner, SLOT(handleGdbRunning()));
|
m_runner, SLOT(handleRemoteDebuggerRunning()));
|
||||||
|
|
||||||
connect(m_runner, SIGNAL(remoteServerRunning(QByteArray,int)),
|
connect(m_runner, SIGNAL(remoteServerRunning(QByteArray,int)),
|
||||||
SLOT(handleRemoteServerRunning(QByteArray,int)));
|
SLOT(handleRemoteServerRunning(QByteArray,int)));
|
||||||
|
@@ -84,6 +84,11 @@ void AndroidDevice::executeAction(Core::Id actionId, QWidget *parent) const
|
|||||||
Q_UNUSED(parent)
|
Q_UNUSED(parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AndroidDevice::canAutoDetectPorts() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
IDevice::Ptr AndroidDevice::clone() const
|
IDevice::Ptr AndroidDevice::clone() const
|
||||||
{
|
{
|
||||||
return IDevice::Ptr(new AndroidDevice(*this));
|
return IDevice::Ptr(new AndroidDevice(*this));
|
||||||
|
@@ -46,6 +46,7 @@ public:
|
|||||||
QList<Core::Id> actionIds() const;
|
QList<Core::Id> actionIds() const;
|
||||||
QString displayNameForActionId(Core::Id actionId) const;
|
QString displayNameForActionId(Core::Id actionId) const;
|
||||||
void executeAction(Core::Id actionId, QWidget *parent = 0) const;
|
void executeAction(Core::Id actionId, QWidget *parent = 0) const;
|
||||||
|
bool canAutoDetectPorts() const;
|
||||||
|
|
||||||
ProjectExplorer::IDevice::Ptr clone() const;
|
ProjectExplorer::IDevice::Ptr clone() const;
|
||||||
|
|
||||||
|
@@ -42,6 +42,7 @@
|
|||||||
#include <QTime>
|
#include <QTime>
|
||||||
#include <QtConcurrentRun>
|
#include <QtConcurrentRun>
|
||||||
#include <QTemporaryFile>
|
#include <QTemporaryFile>
|
||||||
|
#include <QTcpServer>
|
||||||
|
|
||||||
namespace Android {
|
namespace Android {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
@@ -60,7 +61,13 @@ AndroidRunner::AndroidRunner(QObject *parent, AndroidRunConfiguration *runConfig
|
|||||||
QTC_CHECK(channel.startsWith(QLatin1Char(':')));
|
QTC_CHECK(channel.startsWith(QLatin1Char(':')));
|
||||||
m_localGdbServerPort = channel.mid(1).toUShort();
|
m_localGdbServerPort = channel.mid(1).toUShort();
|
||||||
QTC_CHECK(m_localGdbServerPort);
|
QTC_CHECK(m_localGdbServerPort);
|
||||||
m_qmlPort = aspect->qmlDebugServerPort();
|
if (m_useQmlDebugger) {
|
||||||
|
QTcpServer server;
|
||||||
|
QTC_ASSERT(server.listen(QHostAddress::LocalHost)
|
||||||
|
|| server.listen(QHostAddress::LocalHostIPv6),
|
||||||
|
qDebug() << tr("No free ports available on host for QML debugging."));
|
||||||
|
m_qmlPort = server.serverPort();
|
||||||
|
}
|
||||||
ProjectExplorer::Target *target = runConfig->target();
|
ProjectExplorer::Target *target = runConfig->target();
|
||||||
AndroidDeployStep *ds = runConfig->deployStep();
|
AndroidDeployStep *ds = runConfig->deployStep();
|
||||||
if ((m_useLocalQtLibs = ds->useLocalQtLibs())) {
|
if ((m_useLocalQtLibs = ds->useLocalQtLibs())) {
|
||||||
@@ -81,7 +88,6 @@ AndroidRunner::AndroidRunner(QObject *parent, AndroidRunConfiguration *runConfig
|
|||||||
m_gdbserverSocket = packageDir + _("/debug-socket");
|
m_gdbserverSocket = packageDir + _("/debug-socket");
|
||||||
m_gdbserverPath = packageDir + _("/lib/gdbserver");
|
m_gdbserverPath = packageDir + _("/lib/gdbserver");
|
||||||
m_gdbserverCommand = m_gdbserverPath + _(" --multi +") + m_gdbserverSocket;
|
m_gdbserverCommand = m_gdbserverPath + _(" --multi +") + m_gdbserverSocket;
|
||||||
|
|
||||||
// Detect busybox, as we need to pass -w to ps to get wide output.
|
// Detect busybox, as we need to pass -w to ps to get wide output.
|
||||||
QProcess psProc;
|
QProcess psProc;
|
||||||
psProc.start(m_adb, selector() << _("shell") << _("readlink") << _("$(which ps)"));
|
psProc.start(m_adb, selector() << _("shell") << _("readlink") << _("$(which ps)"));
|
||||||
@@ -216,7 +222,7 @@ void AndroidRunner::asyncStart()
|
|||||||
}
|
}
|
||||||
if (m_useQmlDebugger) {
|
if (m_useQmlDebugger) {
|
||||||
// currently forward to same port on device and host
|
// currently forward to same port on device and host
|
||||||
QString port = QString::fromLatin1("tcp:%1").arg(m_qmlPort);
|
const QString port = QString::fromLatin1("tcp:%1").arg(m_qmlPort);
|
||||||
QProcess adb;
|
QProcess adb;
|
||||||
adb.start(m_adb, selector() << _("forward") << port << port);
|
adb.start(m_adb, selector() << _("forward") << port << port);
|
||||||
if (!adb.waitForStarted()) {
|
if (!adb.waitForStarted()) {
|
||||||
@@ -228,9 +234,8 @@ void AndroidRunner::asyncStart()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
args << _("-e") << _("qml_debug") << _("true");
|
args << _("-e") << _("qml_debug") << _("true");
|
||||||
args << _("-e") << _("qmljsdebugger") << QString::fromLatin1("port:%1").arg(m_qmlPort);
|
args << _("-e") << _("qmljsdebugger") << QString::fromLatin1("port:%1,block").arg(m_qmlPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_useLocalQtLibs) {
|
if (m_useLocalQtLibs) {
|
||||||
args << _("-e") << _("use_local_qt_libs") << _("true");
|
args << _("-e") << _("use_local_qt_libs") << _("true");
|
||||||
args << _("-e") << _("libs_prefix") << _("/data/local/tmp/qt/");
|
args << _("-e") << _("libs_prefix") << _("/data/local/tmp/qt/");
|
||||||
@@ -252,7 +257,7 @@ void AndroidRunner::asyncStart()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_useCppDebugger || m_useQmlDebugger) {
|
if (m_useCppDebugger) {
|
||||||
|
|
||||||
// Handling ping.
|
// Handling ping.
|
||||||
for (int i = 0; ; ++i) {
|
for (int i = 0; ; ++i) {
|
||||||
@@ -289,19 +294,25 @@ void AndroidRunner::asyncStart()
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_wasStarted = true;
|
m_wasStarted = true;
|
||||||
if (m_useCppDebugger || m_useQmlDebugger) {
|
if (m_useCppDebugger) {
|
||||||
// This will be funneled to the engine to actually start and attach
|
// This will be funneled to the engine to actually start and attach
|
||||||
// gdb. Afterwards this ends up in handleGdbRunning() below.
|
// gdb. Afterwards this ends up in handleRemoteDebuggerRunning() below.
|
||||||
QByteArray serverChannel = ':' + QByteArray::number(m_localGdbServerPort);
|
QByteArray serverChannel = ':' + QByteArray::number(m_localGdbServerPort);
|
||||||
emit remoteServerRunning(serverChannel, m_processPID);
|
emit remoteServerRunning(serverChannel, m_processPID);
|
||||||
|
} else if (m_useQmlDebugger) {
|
||||||
|
// This will be funneled to the engine to actually start and attach
|
||||||
|
// gdb. Afterwards this ends up in handleRemoteDebuggerRunning() below.
|
||||||
|
QByteArray serverChannel = QByteArray::number(m_qmlPort);
|
||||||
|
emit remoteServerRunning(serverChannel, m_processPID);
|
||||||
} else {
|
} else {
|
||||||
// Start without debugging.
|
// Start without debugging.
|
||||||
emit remoteProcessStarted(-1, -1);
|
emit remoteProcessStarted(-1, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidRunner::handleGdbRunning()
|
void AndroidRunner::handleRemoteDebuggerRunning()
|
||||||
{
|
{
|
||||||
|
if (m_useCppDebugger) {
|
||||||
QTemporaryFile tmp(_("pingpong"));
|
QTemporaryFile tmp(_("pingpong"));
|
||||||
tmp.open();
|
tmp.open();
|
||||||
|
|
||||||
@@ -310,7 +321,8 @@ void AndroidRunner::handleGdbRunning()
|
|||||||
process.waitForFinished();
|
process.waitForFinished();
|
||||||
|
|
||||||
QTC_CHECK(m_processPID != -1);
|
QTC_CHECK(m_processPID != -1);
|
||||||
emit remoteProcessStarted(m_localGdbServerPort, -1);
|
}
|
||||||
|
emit remoteProcessStarted(m_localGdbServerPort, m_qmlPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidRunner::stop()
|
void AndroidRunner::stop()
|
||||||
|
@@ -56,7 +56,7 @@ public:
|
|||||||
public slots:
|
public slots:
|
||||||
void start();
|
void start();
|
||||||
void stop();
|
void stop();
|
||||||
void handleGdbRunning();
|
void handleRemoteDebuggerRunning();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void remoteServerRunning(const QByteArray &serverChannel, int pid);
|
void remoteServerRunning(const QByteArray &serverChannel, int pid);
|
||||||
@@ -93,7 +93,7 @@ private:
|
|||||||
bool m_useCppDebugger;
|
bool m_useCppDebugger;
|
||||||
bool m_useQmlDebugger;
|
bool m_useQmlDebugger;
|
||||||
ushort m_localGdbServerPort; // Local end of forwarded debug socket.
|
ushort m_localGdbServerPort; // Local end of forwarded debug socket.
|
||||||
uint m_qmlPort;
|
quint16 m_qmlPort;
|
||||||
bool m_useLocalQtLibs;
|
bool m_useLocalQtLibs;
|
||||||
QString m_pingFile;
|
QString m_pingFile;
|
||||||
QString m_pongFile;
|
QString m_pongFile;
|
||||||
|
@@ -345,6 +345,12 @@ QmlEngine::~QmlEngine()
|
|||||||
Core::EditorManager::instance()->closeEditors(editorsToClose);
|
Core::EditorManager::instance()->closeEditors(editorsToClose);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QmlEngine::notifyInferiorSetupOk()
|
||||||
|
{
|
||||||
|
emit aboutToNotifyInferiorSetupOk();
|
||||||
|
DebuggerEngine::notifyInferiorSetupOk();
|
||||||
|
}
|
||||||
|
|
||||||
void QmlEngine::setupInferior()
|
void QmlEngine::setupInferior()
|
||||||
{
|
{
|
||||||
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
|
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
|
||||||
@@ -620,6 +626,25 @@ void QmlEngine::notifyEngineRemoteSetupFailed(const QString &message)
|
|||||||
notifyEngineSetupFailed();
|
notifyEngineSetupFailed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QmlEngine::notifyEngineRemoteServerRunning(const QByteArray &serverChannel, int pid)
|
||||||
|
{
|
||||||
|
bool ok = false;
|
||||||
|
quint16 qmlPort = serverChannel.toUInt(&ok);
|
||||||
|
if (ok)
|
||||||
|
startParameters().qmlServerPort = qmlPort;
|
||||||
|
else
|
||||||
|
qWarning() << tr("QML debugging port not set! Unable to convert %1 to unsigned int.").arg(QString::fromLatin1(serverChannel));
|
||||||
|
|
||||||
|
DebuggerEngine::notifyEngineRemoteServerRunning(serverChannel, pid);
|
||||||
|
notifyEngineSetupOk();
|
||||||
|
|
||||||
|
// The remote setup can take a while especially with mixed debugging.
|
||||||
|
// Just waiting for 8 seconds is not enough. Increase the timeout
|
||||||
|
// to 60 s
|
||||||
|
// In case we get an output the m_outputParser will start the connection.
|
||||||
|
m_noDebugOutputTimer.setInterval(60000);
|
||||||
|
}
|
||||||
|
|
||||||
void QmlEngine::shutdownInferior()
|
void QmlEngine::shutdownInferior()
|
||||||
{
|
{
|
||||||
if (m_adapter.activeDebuggerClient())
|
if (m_adapter.activeDebuggerClient())
|
||||||
|
@@ -61,8 +61,10 @@ public:
|
|||||||
DebuggerEngine *masterEngine = 0);
|
DebuggerEngine *masterEngine = 0);
|
||||||
~QmlEngine();
|
~QmlEngine();
|
||||||
|
|
||||||
|
void notifyInferiorSetupOk();
|
||||||
void notifyEngineRemoteSetupDone(int gdbServerPort, int qmlPort);
|
void notifyEngineRemoteSetupDone(int gdbServerPort, int qmlPort);
|
||||||
void notifyEngineRemoteSetupFailed(const QString &message);
|
void notifyEngineRemoteSetupFailed(const QString &message);
|
||||||
|
void notifyEngineRemoteServerRunning(const QByteArray &, int pid);
|
||||||
|
|
||||||
bool canDisplayTooltip() const;
|
bool canDisplayTooltip() const;
|
||||||
|
|
||||||
@@ -90,6 +92,7 @@ public:
|
|||||||
signals:
|
signals:
|
||||||
void tooltipRequested(const QPoint &mousePos,
|
void tooltipRequested(const QPoint &mousePos,
|
||||||
TextEditor::ITextEditor *editor, int cursorPos);
|
TextEditor::ITextEditor *editor, int cursorPos);
|
||||||
|
void aboutToNotifyInferiorSetupOk();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void disconnected();
|
void disconnected();
|
||||||
|
Reference in New Issue
Block a user