Android: Add QML debugging support

Change-Id: I2fb2c75001569385e417ea44ae90d34e92a22449
Reviewed-by: BogDan Vatra <bog_dan_ro@yahoo.com>
Reviewed-by: Tobias Hunger <tobias.hunger@nokia.com>
This commit is contained in:
Tyler Mandry
2012-06-24 19:32:45 -07:00
committed by Tobias Hunger
parent 70ce95b44f
commit fcd01af143
5 changed files with 89 additions and 43 deletions

View File

@@ -70,30 +70,40 @@ static Qt4Project *project(AndroidRunConfiguration *rc)
RunControl *AndroidDebugSupport::createDebugRunControl(AndroidRunConfiguration *runConfig) RunControl *AndroidDebugSupport::createDebugRunControl(AndroidRunConfiguration *runConfig)
{ {
DebuggerStartParameters params; DebuggerStartParameters params;
Profile *profile = runConfig->target()->profile();
params.sysRoot = SysRootProfileInformation::sysRoot(profile).toString();
params.debuggerCommand = DebuggerProfileInformation::debuggerCommand(profile).toString();
if (ToolChain *tc = ToolChainProfileInformation::toolChain(profile))
params.toolChainAbi = tc->targetAbi();
params.dumperLibrary = runConfig->dumperLib();
params.startMode = AttachToRemoteServer; params.startMode = AttachToRemoteServer;
params.executable = project(runConfig)->rootQt4ProjectNode()->buildDir() + QLatin1String("/app_process");
params.remoteChannel = runConfig->remoteChannel();
params.displayName = AndroidManager::packageName(runConfig->target()); params.displayName = AndroidManager::packageName(runConfig->target());
params.solibSearchPath.clear();
QList<Qt4ProFileNode *> nodes = project(runConfig)->allProFiles();
foreach (Qt4ProFileNode *node, nodes)
if (node->projectType() == ApplicationTemplate)
params.solibSearchPath.append(node->targetInformation().buildDir);
QtSupport::BaseQtVersion *version = QtSupport::QtProfileInformation::qtVersion(runConfig->target()->profile());
params.solibSearchPath.append(qtSoPaths(version));
params.useServerStartScript = true;
params.remoteSetupNeeded = true; params.remoteSetupNeeded = true;
params.remoteArchitecture = QLatin1String("arm");
if (runConfig->debuggerAspect()->useCppDebugger()) {
params.languages |= CppLanguage;
Profile *profile = runConfig->target()->profile();
params.sysRoot = SysRootProfileInformation::sysRoot(profile).toString();
params.debuggerCommand = DebuggerProfileInformation::debuggerCommand(profile).toString();
if (ToolChain *tc = ToolChainProfileInformation::toolChain(profile))
params.toolChainAbi = tc->targetAbi();
params.dumperLibrary = runConfig->dumperLib();
params.executable = project(runConfig)->rootQt4ProjectNode()->buildDir() + QLatin1String("/app_process");
params.remoteChannel = runConfig->remoteChannel();
params.remoteArchitecture = QLatin1String("arm");
params.useServerStartScript = true;
params.solibSearchPath.clear();
QList<Qt4ProFileNode *> nodes = project(runConfig)->allProFiles();
foreach (Qt4ProFileNode *node, nodes)
if (node->projectType() == ApplicationTemplate)
params.solibSearchPath.append(node->targetInformation().buildDir);
QtSupport::BaseQtVersion *version = QtSupport::QtProfileInformation::qtVersion(runConfig->target()->profile());
params.solibSearchPath.append(qtSoPaths(version));
}
if (runConfig->debuggerAspect()->useQmlDebugger()) {
params.languages |= QmlLanguage;
params.qmlServerAddress = QLatin1String("localhost");
params.qmlServerPort = runConfig->debuggerAspect()->qmlDebugServerPort();
//TODO: Not sure if these are the right paths.
params.projectSourceDirectory = project(runConfig)->projectDirectory();
params.projectSourceFiles = project(runConfig)->files(Qt4Project::ExcludeGeneratedFiles);
params.projectBuildDirectory = project(runConfig)->rootQt4ProjectNode()->buildDir();
}
DebuggerRunControl * const debuggerRunControl DebuggerRunControl * const debuggerRunControl
= DebuggerPlugin::createDebugger(params, runConfig); = DebuggerPlugin::createDebugger(params, runConfig);
@@ -106,8 +116,10 @@ AndroidDebugSupport::AndroidDebugSupport(AndroidRunConfiguration *runConfig,
: QObject(runControl), m_runControl(runControl), : QObject(runControl), m_runControl(runControl),
m_runner(new AndroidRunner(this, runConfig, true)), m_runner(new AndroidRunner(this, runConfig, true)),
m_debuggingType(runConfig->debuggingType()), m_debuggingType(runConfig->debuggingType()),
m_gdbServerPort(5039), m_qmlPort(-1) m_gdbServerPort(5039), m_qmlPort(runConfig->debuggerAspect()->qmlDebugServerPort())
{ {
Q_ASSERT(runConfig->debuggerAspect()->useCppDebugger() || runConfig->debuggerAspect()->useQmlDebugger());
connect(m_runControl->engine(), SIGNAL(requestRemoteSetup()), connect(m_runControl->engine(), SIGNAL(requestRemoteSetup()),
m_runner, SLOT(start())); m_runner, SLOT(start()));
connect(m_runControl, SIGNAL(finished()), connect(m_runControl, SIGNAL(finished()),
@@ -144,14 +156,22 @@ void AndroidDebugSupport::handleRemoteProcessFinished(const QString &errorMsg)
void AndroidDebugSupport::handleRemoteOutput(const QByteArray &output) void AndroidDebugSupport::handleRemoteOutput(const QByteArray &output)
{ {
if (m_runControl) if (m_runControl) {
m_runControl->showMessage(QString::fromUtf8(output), AppOutput); if (m_runControl->engine())
m_runControl->engine()->showMessage(QString::fromUtf8(output), AppOutput);
else
m_runControl->showMessage(QString::fromUtf8(output), AppOutput);
}
} }
void AndroidDebugSupport::handleRemoteErrorOutput(const QByteArray &output) void AndroidDebugSupport::handleRemoteErrorOutput(const QByteArray &output)
{ {
if (m_runControl) if (m_runControl) {
m_runControl->showMessage(QString::fromUtf8(output), AppError); if (m_runControl->engine())
m_runControl->engine()->showMessage(QString::fromUtf8(output), AppError);
else
m_runControl->showMessage(QString::fromUtf8(output), AppError);
}
} }
QStringList AndroidDebugSupport::qtSoPaths(QtSupport::BaseQtVersion *qtVersion) QStringList AndroidDebugSupport::qtSoPaths(QtSupport::BaseQtVersion *qtVersion)

View File

@@ -142,7 +142,12 @@ QString AndroidRunConfiguration::proFilePath() const
AndroidRunConfiguration::DebuggingType AndroidRunConfiguration::debuggingType() const AndroidRunConfiguration::DebuggingType AndroidRunConfiguration::debuggingType() const
{ {
return DebugCppAndQml; if (debuggerAspect()->useCppDebugger()) {
if (debuggerAspect()->useQmlDebugger())
return DebugCppAndQml;
return DebugCppOnly;
}
return DebugQmlOnly;
} }
} // namespace Internal } // namespace Internal

View File

@@ -38,7 +38,6 @@
#include "androidrunner.h" #include "androidrunner.h"
#include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectexplorerconstants.h>
#include <utils/qtcassert.h>
#include <QIcon> #include <QIcon>

View File

@@ -46,11 +46,13 @@
namespace Android { namespace Android {
namespace Internal { namespace Internal {
AndroidRunner::AndroidRunner(QObject *parent, AndroidRunner::AndroidRunner(QObject *parent, AndroidRunConfiguration *runConfig, bool debuggingMode)
AndroidRunConfiguration *runConfig, bool debugging)
: QThread(parent) : QThread(parent)
{ {
m_remoteChannel = runConfig->remoteChannel(); m_useCppDebugger = debuggingMode && runConfig->debuggerAspect()->useCppDebugger();
m_useQmlDebugger = debuggingMode && runConfig->debuggerAspect()->useQmlDebugger();
m_remoteGdbChannel = runConfig->remoteChannel();
m_qmlPort = runConfig->debuggerAspect()->qmlDebugServerPort();
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())) {
@@ -58,7 +60,6 @@ AndroidRunner::AndroidRunner(QObject *parent,
m_localJars = AndroidManager::loadLocalJars(target, ds->deviceAPILevel()); m_localJars = AndroidManager::loadLocalJars(target, ds->deviceAPILevel());
} }
m_intentName = AndroidManager::intentName(target); m_intentName = AndroidManager::intentName(target);
m_debugingMode = debugging;
m_packageName = m_intentName.left(m_intentName.indexOf(QLatin1Char('/'))); m_packageName = m_intentName.left(m_intentName.indexOf(QLatin1Char('/')));
m_deviceSerialNumber = ds->deviceSerialNumber(); m_deviceSerialNumber = ds->deviceSerialNumber();
m_processPID = -1; m_processPID = -1;
@@ -101,9 +102,9 @@ void AndroidRunner::checkPID()
return; return;
} }
m_processPID = pid; m_processPID = pid;
if (!m_debugingMode)
return;
if (!m_useCppDebugger)
return;
m_gdbserverPID = -1; m_gdbserverPID = -1;
foreach (const QByteArray &proc, procs) { foreach (const QByteArray &proc, procs) {
if (proc.trimmed().endsWith("gdbserver")) { if (proc.trimmed().endsWith("gdbserver")) {
@@ -145,22 +146,39 @@ void AndroidRunner::asyncStart()
killPID(); // kill any process with this name killPID(); // kill any process with this name
QString extraParams; QString extraParams;
QProcess adbStarProc; QProcess adbStarProc;
if (m_debugingMode) { if (m_useCppDebugger) {
QStringList arguments; QStringList arguments;
arguments << QLatin1String("-s") << m_deviceSerialNumber arguments << QLatin1String("-s") << m_deviceSerialNumber
<< QLatin1String("forward") << QString::fromLatin1("tcp%1").arg(m_remoteChannel) << QLatin1String("forward") << QString::fromLatin1("tcp%1").arg(m_remoteGdbChannel)
<< QString::fromLatin1("localfilesystem:/data/data/%1/debug-socket").arg(m_packageName); << QString::fromLatin1("localfilesystem:/data/data/%1/debug-socket").arg(m_packageName);
adbStarProc.start(AndroidConfigurations::instance().adbToolPath().toString(), arguments); adbStarProc.start(AndroidConfigurations::instance().adbToolPath().toString(), arguments);
if (!adbStarProc.waitForStarted()) { if (!adbStarProc.waitForStarted()) {
emit remoteProcessFinished(tr("Failed to forward debugging ports. Reason: $1").arg(adbStarProc.errorString())); emit remoteProcessFinished(tr("Failed to forward C++ debugging ports. Reason: %1").arg(adbStarProc.errorString()));
return; return;
} }
if (!adbStarProc.waitForFinished(-1)) { if (!adbStarProc.waitForFinished(-1)) {
emit remoteProcessFinished(tr("Failed to forward debugging ports")); emit remoteProcessFinished(tr("Failed to forward C++ debugging ports"));
return; return;
} }
extraParams = QLatin1String("-e native_debug true -e gdbserver_socket +debug-socket"); extraParams = QLatin1String("-e native_debug true -e gdbserver_socket +debug-socket");
} }
if (m_useQmlDebugger) {
QStringList arguments;
QString port = QString::fromLatin1("tcp:%1").arg(m_qmlPort);
arguments << QLatin1String("-s") << m_deviceSerialNumber
<< QLatin1String("forward") << port << port; // currently forward to same port on device and host
adbStarProc.start(AndroidConfigurations::instance().adbToolPath().toString(), arguments);
if (!adbStarProc.waitForStarted()) {
emit remoteProcessFinished(tr("Failed to forward QML debugging ports. Reason: %1").arg(adbStarProc.errorString()));
return;
}
if (!adbStarProc.waitForFinished(-1)) {
emit remoteProcessFinished(tr("Failed to forward QML debugging ports"));
return;
}
extraParams+=QString::fromLatin1(" -e qml_debug true -e qmljsdebugger port:%1")
.arg(m_qmlPort);
}
if (m_useLocalQtLibs) { if (m_useLocalQtLibs) {
extraParams += QLatin1String(" -e use_local_qt_libs true"); extraParams += QLatin1String(" -e use_local_qt_libs true");
@@ -197,7 +215,7 @@ void AndroidRunner::asyncStart()
return; return;
} }
if (m_debugingMode) { if (m_useCppDebugger) {
startTime = QTime::currentTime(); startTime = QTime::currentTime();
while (m_gdbserverPID == -1 && startTime.secsTo(QTime::currentTime()) < 25) { // wait up to 25 seconds to connect while (m_gdbserverPID == -1 && startTime.secsTo(QTime::currentTime()) < 25) { // wait up to 25 seconds to connect
checkPID(); checkPID();
@@ -247,6 +265,9 @@ void AndroidRunner::logcatReadStandardOutput()
foreach (line, m_logcat.split('\n')) { foreach (line, m_logcat.split('\n')) {
if (!line.contains(pid)) if (!line.contains(pid))
continue; continue;
if (line.endsWith('\r'))
line.chop(1);
line.append('\n');
if (line.startsWith("E/")) if (line.startsWith("E/"))
emit remoteErrorOutput(line); emit remoteErrorOutput(line);
else else

View File

@@ -52,8 +52,7 @@ class AndroidRunner : public QThread
Q_OBJECT Q_OBJECT
public: public:
AndroidRunner(QObject *parent, AndroidRunConfiguration *runConfig, AndroidRunner(QObject *parent, AndroidRunConfiguration *runConfig, bool debuggingMode);
bool debugging);
~AndroidRunner(); ~AndroidRunner();
QString displayName() const; QString displayName() const;
@@ -82,7 +81,6 @@ private:
void adbKill(qint64 pid, const QString &device, int timeout = 2000, const QString &runAsPackageName = QString()); void adbKill(qint64 pid, const QString &device, int timeout = 2000, const QString &runAsPackageName = QString());
private: private:
bool m_debugingMode;
QProcess m_adbLogcatProcess; QProcess m_adbLogcatProcess;
QByteArray m_logcat; QByteArray m_logcat;
QString m_intentName; QString m_intentName;
@@ -91,7 +89,10 @@ private:
qint64 m_processPID; qint64 m_processPID;
qint64 m_gdbserverPID; qint64 m_gdbserverPID;
QTimer m_checkPIDTimer; QTimer m_checkPIDTimer;
QString m_remoteChannel; bool m_useCppDebugger;
bool m_useQmlDebugger;
QString m_remoteGdbChannel;
uint m_qmlPort;
bool m_useLocalQtLibs; bool m_useLocalQtLibs;
QString m_localLibs; QString m_localLibs;
QString m_localJars; QString m_localJars;