diff --git a/src/plugins/android/androiddebugsupport.cpp b/src/plugins/android/androiddebugsupport.cpp index d716e7b6106..96c9c4c80d8 100644 --- a/src/plugins/android/androiddebugsupport.cpp +++ b/src/plugins/android/androiddebugsupport.cpp @@ -49,6 +49,7 @@ #include #include +#include using namespace Debugger; using namespace ProjectExplorer; @@ -113,8 +114,11 @@ RunControl *AndroidDebugSupport::createDebugRunControl(AndroidRunConfiguration * } if (aspect->useQmlDebugger()) { params.languages |= QmlLanguage; - params.qmlServerAddress = QLatin1String("localhost"); - params.qmlServerPort = aspect->qmlDebugServerPort(); + QTcpServer server; + 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. params.projectSourceDirectory = project->projectDirectory(); params.projectSourceFiles = project->files(Qt4Project::ExcludeGeneratedFiles); @@ -141,7 +145,7 @@ AndroidDebugSupport::AndroidDebugSupport(AndroidRunConfiguration *runConfig, connect(m_runControl, SIGNAL(finished()), m_runner, SLOT(stop())); connect(m_runControl->engine(), SIGNAL(aboutToNotifyInferiorSetupOk()), - m_runner, SLOT(handleGdbRunning())); + m_runner, SLOT(handleRemoteDebuggerRunning())); connect(m_runner, SIGNAL(remoteServerRunning(QByteArray,int)), SLOT(handleRemoteServerRunning(QByteArray,int))); diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index 982d90eca1b..64cc451eee8 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -84,6 +84,11 @@ void AndroidDevice::executeAction(Core::Id actionId, QWidget *parent) const Q_UNUSED(parent) } +bool AndroidDevice::canAutoDetectPorts() const +{ + return true; +} + IDevice::Ptr AndroidDevice::clone() const { return IDevice::Ptr(new AndroidDevice(*this)); diff --git a/src/plugins/android/androiddevice.h b/src/plugins/android/androiddevice.h index 224564bbc0f..a89d6357d38 100644 --- a/src/plugins/android/androiddevice.h +++ b/src/plugins/android/androiddevice.h @@ -46,6 +46,7 @@ public: QList actionIds() const; QString displayNameForActionId(Core::Id actionId) const; void executeAction(Core::Id actionId, QWidget *parent = 0) const; + bool canAutoDetectPorts() const; ProjectExplorer::IDevice::Ptr clone() const; diff --git a/src/plugins/android/androidrunner.cpp b/src/plugins/android/androidrunner.cpp index 2a68dc17c42..a6f42fe0ac1 100644 --- a/src/plugins/android/androidrunner.cpp +++ b/src/plugins/android/androidrunner.cpp @@ -42,6 +42,7 @@ #include #include #include +#include namespace Android { namespace Internal { @@ -60,7 +61,13 @@ AndroidRunner::AndroidRunner(QObject *parent, AndroidRunConfiguration *runConfig QTC_CHECK(channel.startsWith(QLatin1Char(':'))); m_localGdbServerPort = channel.mid(1).toUShort(); 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(); AndroidDeployStep *ds = runConfig->deployStep(); if ((m_useLocalQtLibs = ds->useLocalQtLibs())) { @@ -81,7 +88,6 @@ AndroidRunner::AndroidRunner(QObject *parent, AndroidRunConfiguration *runConfig m_gdbserverSocket = packageDir + _("/debug-socket"); m_gdbserverPath = packageDir + _("/lib/gdbserver"); m_gdbserverCommand = m_gdbserverPath + _(" --multi +") + m_gdbserverSocket; - // Detect busybox, as we need to pass -w to ps to get wide output. QProcess psProc; psProc.start(m_adb, selector() << _("shell") << _("readlink") << _("$(which ps)")); @@ -216,7 +222,7 @@ void AndroidRunner::asyncStart() } if (m_useQmlDebugger) { // 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; adb.start(m_adb, selector() << _("forward") << port << port); if (!adb.waitForStarted()) { @@ -228,9 +234,8 @@ void AndroidRunner::asyncStart() return; } 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) { args << _("-e") << _("use_local_qt_libs") << _("true"); args << _("-e") << _("libs_prefix") << _("/data/local/tmp/qt/"); @@ -252,7 +257,7 @@ void AndroidRunner::asyncStart() return; } - if (m_useCppDebugger || m_useQmlDebugger) { + if (m_useCppDebugger) { // Handling ping. for (int i = 0; ; ++i) { @@ -289,28 +294,35 @@ void AndroidRunner::asyncStart() } m_wasStarted = true; - if (m_useCppDebugger || m_useQmlDebugger) { + if (m_useCppDebugger) { // 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); 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 { // Start without debugging. emit remoteProcessStarted(-1, -1); } } -void AndroidRunner::handleGdbRunning() +void AndroidRunner::handleRemoteDebuggerRunning() { - QTemporaryFile tmp(_("pingpong")); - tmp.open(); + if (m_useCppDebugger) { + QTemporaryFile tmp(_("pingpong")); + tmp.open(); - QProcess process; - process.start(m_adb, selector() << _("push") << tmp.fileName() << m_pongFile); - process.waitForFinished(); + QProcess process; + process.start(m_adb, selector() << _("push") << tmp.fileName() << m_pongFile); + process.waitForFinished(); - QTC_CHECK(m_processPID != -1); - emit remoteProcessStarted(m_localGdbServerPort, -1); + QTC_CHECK(m_processPID != -1); + } + emit remoteProcessStarted(m_localGdbServerPort, m_qmlPort); } void AndroidRunner::stop() diff --git a/src/plugins/android/androidrunner.h b/src/plugins/android/androidrunner.h index 24e4f8ded74..f44fcb98e82 100644 --- a/src/plugins/android/androidrunner.h +++ b/src/plugins/android/androidrunner.h @@ -56,7 +56,7 @@ public: public slots: void start(); void stop(); - void handleGdbRunning(); + void handleRemoteDebuggerRunning(); signals: void remoteServerRunning(const QByteArray &serverChannel, int pid); @@ -93,7 +93,7 @@ private: bool m_useCppDebugger; bool m_useQmlDebugger; ushort m_localGdbServerPort; // Local end of forwarded debug socket. - uint m_qmlPort; + quint16 m_qmlPort; bool m_useLocalQtLibs; QString m_pingFile; QString m_pongFile; diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index 6d053e4cbc6..b7db2927ab6 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -345,6 +345,12 @@ QmlEngine::~QmlEngine() Core::EditorManager::instance()->closeEditors(editorsToClose); } +void QmlEngine::notifyInferiorSetupOk() +{ + emit aboutToNotifyInferiorSetupOk(); + DebuggerEngine::notifyInferiorSetupOk(); +} + void QmlEngine::setupInferior() { QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state()); @@ -620,6 +626,25 @@ void QmlEngine::notifyEngineRemoteSetupFailed(const QString &message) 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() { if (m_adapter.activeDebuggerClient()) diff --git a/src/plugins/debugger/qml/qmlengine.h b/src/plugins/debugger/qml/qmlengine.h index efc1108ebea..0c8ef50b470 100644 --- a/src/plugins/debugger/qml/qmlengine.h +++ b/src/plugins/debugger/qml/qmlengine.h @@ -61,8 +61,10 @@ public: DebuggerEngine *masterEngine = 0); ~QmlEngine(); + void notifyInferiorSetupOk(); void notifyEngineRemoteSetupDone(int gdbServerPort, int qmlPort); void notifyEngineRemoteSetupFailed(const QString &message); + void notifyEngineRemoteServerRunning(const QByteArray &, int pid); bool canDisplayTooltip() const; @@ -90,6 +92,7 @@ public: signals: void tooltipRequested(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos); + void aboutToNotifyInferiorSetupOk(); private slots: void disconnected();