diff --git a/src/plugins/android/androidmanager.cpp b/src/plugins/android/androidmanager.cpp index df678d1f741..77ad59b8a76 100644 --- a/src/plugins/android/androidmanager.cpp +++ b/src/plugins/android/androidmanager.cpp @@ -79,18 +79,6 @@ namespace { Q_LOGGING_CATEGORY(androidManagerLog, "qtc.android.androidManager") - bool runCommand(const QString &executable, const QStringList &args, - QString *output = nullptr, int timeoutS = 30) - { - Utils::SynchronousProcess cmdProc; - cmdProc.setTimeoutS(timeoutS); - qCDebug(androidManagerLog) << executable << args.join(' '); - Utils::SynchronousProcessResponse response = cmdProc.runBlocking(executable, args); - if (output) - *output = response.allOutput(); - return response.result == Utils::SynchronousProcessResponse::Finished; - } - QString parseAaptOutput(const QString &output, const QString ®Ex) { const QRegularExpression regRx(regEx, QRegularExpression::CaseInsensitiveOption | @@ -162,10 +150,8 @@ bool AndroidManager::packageInstalled(const QString &deviceSerial, return false; QStringList args = AndroidDeviceInfo::adbSelector(deviceSerial); args << "shell" << "pm" << "list" << "packages"; - QString output; - runAdbCommand(args, &output); - QStringList lines = output.split(QRegularExpression("[\\n\\r]"), - QString::SkipEmptyParts); + QStringList lines = runAdbCommand(args).stdOut().split(QRegularExpression("[\\n\\r]"), + QString::SkipEmptyParts); for (const QString &line : lines) { // Don't want to confuse com.abc.xyz with com.abc.xyz.def so check with // endsWith @@ -180,24 +166,24 @@ void AndroidManager::apkInfo(const Utils::FileName &apkPath, QVersionNumber *version, QString *activityPath) { - QString output; - runAaptCommand({"dump", "badging", apkPath.toString()}, &output); + SdkToolResult result; + result = runAaptCommand({"dump", "badging", apkPath.toString()}); QString packageStr; if (activityPath) { - packageStr = parseAaptOutput(output, packageNameRegEx); - QString path = parseAaptOutput(output, activityRegEx); + packageStr = parseAaptOutput(result.stdOut(), packageNameRegEx); + QString path = parseAaptOutput(result.stdOut(), activityRegEx); if (!packageStr.isEmpty() && !path.isEmpty()) *activityPath = packageStr + '/' + path; } if (packageName) { *packageName = activityPath ? packageStr : - parseAaptOutput(output, packageNameRegEx); + parseAaptOutput(result.stdOut(), packageNameRegEx); } if (version) { - QString versionStr = parseAaptOutput(output, apkVersionRegEx); + QString versionStr = parseAaptOutput(result.stdOut(), apkVersionRegEx); *version = QVersionNumber::fromString(versionStr); } } @@ -477,8 +463,11 @@ void AndroidManager::cleanLibsOnDevice(ProjectExplorer::Target *target) } QStringList arguments = AndroidDeviceInfo::adbSelector(deviceSerialNumber); - arguments << QLatin1String("shell") << QLatin1String("rm") << QLatin1String("-r") << QLatin1String("/data/local/tmp/qt"); - runAdbCommandDetached(arguments); + arguments << "shell" << "rm" << "-r" << "/data/local/tmp/qt"; + + QString error; + if (!runAdbCommandDetached(arguments, &error)) + Core::MessageManager::write(tr("Cleaning Qt libraries on device failed.\n%1").arg(error)); } void AndroidManager::installQASIPackage(ProjectExplorer::Target *target, const QString &packagePath) @@ -499,8 +488,10 @@ void AndroidManager::installQASIPackage(ProjectExplorer::Target *target, const Q } QStringList arguments = AndroidDeviceInfo::adbSelector(deviceSerialNumber); - arguments << QLatin1String("install") << QLatin1String("-r ") << packagePath; - runAdbCommandDetached(arguments); + arguments << "install" << "-r " << packagePath; + QString error; + if (!runAdbCommandDetached(arguments, &error, true)) + Core::MessageManager::write(tr("Android package installation failed.\n%1").arg(error)); } bool AndroidManager::checkKeystorePassword(const QString &keystorePath, const QString &keystorePasswd) @@ -683,27 +674,57 @@ int AndroidManager::findApiLevel(const Utils::FileName &platformPath) return apiLevel; } -void AndroidManager::runAdbCommandDetached(const QStringList &args) +QProcess *AndroidManager::runAdbCommandDetached(const QStringList &args, QString *err, + bool deleteOnFinish) { - auto process = new QProcess(); - connect(process, static_cast(&QProcess::finished), - process, &QObject::deleteLater); + std::unique_ptr p(new QProcess); const QString adb = AndroidConfigurations::currentConfig().adbToolPath().toString(); - qCDebug(androidManagerLog) << adb << args.join(' '); - process->start(adb, args); - if (!process->waitForStarted(500) && process->state() != QProcess::Running) - delete process; + qCDebug(androidManagerLog) << "Running command:" << adb << args.join(' '); + p->start(adb, args); + if (p->waitForStarted(500) && p->state() == QProcess::Running) { + if (deleteOnFinish) { + connect(p.get(), static_cast(&QProcess::finished), + p.get(), &QObject::deleteLater); + } + return p.release(); + } + + QString errorStr = QString::fromUtf8(p->readAllStandardError()); + qCDebug(androidManagerLog) << "Running command failed" << adb << args.join(' ') << errorStr; + if (err) + *err = errorStr; + return nullptr; } -bool AndroidManager::runAdbCommand(const QStringList &args, QString *output) +SdkToolResult AndroidManager::runCommand(const QString &executable, const QStringList &args, + const QByteArray &writeData, int timeoutS) { - return runCommand(AndroidConfigurations::currentConfig().adbToolPath().toString(), - args, output); + Android::SdkToolResult cmdResult; + Utils::SynchronousProcess cmdProc; + cmdProc.setTimeoutS(timeoutS); + qCDebug(androidManagerLog) << "Running command: " << executable << args.join(' '); + Utils::SynchronousProcessResponse response = cmdProc.run(executable, args, writeData); + cmdResult.m_stdOut = response.stdOut().trimmed(); + cmdResult.m_stdErr = response.stdErr().trimmed(); + cmdResult.m_success = response.result == Utils::SynchronousProcessResponse::Finished; + qCDebug(androidManagerLog) << "Running command finshed:" << executable << args.join(' ') + << "Success:" << cmdResult.m_success + << "Output:" << response.allRawOutput(); + if (!cmdResult.success()) + cmdResult.m_exitMessage = response.exitMessage(executable, timeoutS); + return cmdResult; } -bool AndroidManager::runAaptCommand(const QStringList &args, QString *output) +SdkToolResult AndroidManager::runAdbCommand(const QStringList &args, + const QByteArray &writeData, int timeoutS) { - return runCommand(AndroidConfigurations::currentConfig().aaptToolPath().toString(), - args, output); + return runCommand(AndroidConfigurations::currentConfig().adbToolPath().toString(), args, + writeData, timeoutS); +} + +SdkToolResult AndroidManager::runAaptCommand(const QStringList &args, int timeoutS) +{ + return runCommand(AndroidConfigurations::currentConfig().aaptToolPath().toString(), args, {}, + timeoutS); } } // namespace Android diff --git a/src/plugins/android/androidmanager.h b/src/plugins/android/androidmanager.h index 444710ac918..2bf3bb8458c 100644 --- a/src/plugins/android/androidmanager.h +++ b/src/plugins/android/androidmanager.h @@ -31,6 +31,10 @@ #include #include +QT_BEGIN_NAMESPACE +class QProcess; +QT_END_NAMESPACE + namespace ProjectExplorer { class Kit; class Target; @@ -42,6 +46,22 @@ namespace Android { class AndroidQtSupport; +class SdkToolResult { +public: + SdkToolResult() = default; + bool success() const { return m_success; } + const QString &stdOut() { return m_stdOut; } + const QString &stdErr() { return m_stdErr; } + const QString &exitMessage() { return m_exitMessage; } + +private: + bool m_success = false; + QString m_stdOut; + QString m_stdErr; + QString m_exitMessage; + friend class AndroidManager; +}; + class ANDROID_EXPORT AndroidManager : public QObject { Q_OBJECT @@ -94,9 +114,15 @@ public: static bool updateGradleProperties(ProjectExplorer::Target *target); static int findApiLevel(const Utils::FileName &platformPath); - static void runAdbCommandDetached(const QStringList &args); - static bool runAdbCommand(const QStringList &args, QString *output = nullptr); - static bool runAaptCommand(const QStringList &args, QString *output = nullptr); + static QProcess *runAdbCommandDetached(const QStringList &args, QString *err = nullptr, + bool deleteOnFinish = false); + static SdkToolResult runAdbCommand(const QStringList &args, const QByteArray &writeData = {}, + int timeoutS = 30); + static SdkToolResult runAaptCommand(const QStringList &args, int timeoutS = 30); + +private: + static SdkToolResult runCommand(const QString &executable, const QStringList &args, + const QByteArray &writeData = {}, int timeoutS = 30); }; } // namespace Android diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index 648a0d363d4..4de4c4227f8 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -94,14 +94,14 @@ static bool isTimedOut(const chrono::high_resolution_clock::time_point &start, return timedOut; } -static qint64 extractPID(const QByteArray &output, const QString &packageName) +static qint64 extractPID(const QString &output, const QString &packageName) { qint64 pid = -1; foreach (auto tuple, output.split('\n')) { tuple = tuple.simplified(); if (!tuple.isEmpty()) { auto parts = tuple.split(':'); - QString commandName = QString::fromLocal8Bit(parts.first()); + QString commandName = parts.first(); if (parts.length() == 2 && commandName == packageName) { pid = parts.last().toLongLong(); break; @@ -111,9 +111,8 @@ static qint64 extractPID(const QByteArray &output, const QString &packageName) return pid; } -static void findProcessPID(QFutureInterface &fi, const QString &adbPath, - QStringList selector, const QString &packageName, - bool preNougat) +static void findProcessPID(QFutureInterface &fi, QStringList selector, + const QString &packageName, bool preNougat) { qCDebug(androidRunWorkerLog) << "Finding PID. PreNougat:" << preNougat; if (packageName.isEmpty()) @@ -127,12 +126,12 @@ static void findProcessPID(QFutureInterface &fi, const QString &adbPath, do { QThread::msleep(200); - const QByteArray out = Utils::SynchronousProcess().runBlocking(adbPath, selector).allRawOutput(); + SdkToolResult result = AndroidManager::runAdbCommand(selector); if (preNougat) { - processPID = extractPID(out, packageName); + processPID = extractPID(result.stdOut(), packageName); } else { - if (!out.isEmpty()) - processPID = out.trimmed().toLongLong(); + if (!result.stdOut().isEmpty()) + processPID = result.stdOut().trimmed().toLongLong(); } } while (processPID == -1 && !isTimedOut(start) && !fi.isCanceled()); @@ -188,7 +187,6 @@ AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const QString &packa m_qmlServer.setPort(server.serverPort()); qCDebug(androidRunWorkerLog) << "QML server:" << m_qmlServer.toDisplayString(); } - m_adb = AndroidConfigurations::currentConfig().adbToolPath().toString(); m_localJdbServerPort = Utils::Port(5038); QTC_CHECK(m_localJdbServerPort.isValid()); @@ -236,40 +234,16 @@ AndroidRunnerWorker::~AndroidRunnerWorker() m_pidFinder.cancel(); } -bool AndroidRunnerWorker::adbShellAmNeedsQuotes() -{ - // Between Android SDK Tools version 24.3.1 and 24.3.4 the quoting - // needs for the 'adb shell am start ...' parameters changed. - // Run a test to find out on what side of the fence we live. - // The command will fail with a complaint about the "--dummy" - // option on newer SDKs, and with "No intent supplied" on older ones. - // In case the test itself fails assume a new SDK. - Utils::SynchronousProcess adb; - adb.setTimeoutS(10); - Utils::SynchronousProcessResponse response - = adb.run(m_adb, selector() << "shell" << "am" << "start" - << "-e" << "dummy" << "dummy --dummy"); - if (response.result == Utils::SynchronousProcessResponse::StartFailed - || response.result != Utils::SynchronousProcessResponse::Finished) - return true; - - const QString output = response.allOutput(); - const bool oldSdk = output.contains("Error: No intent supplied"); - return !oldSdk; -} - -bool AndroidRunnerWorker::runAdb(const QStringList &args, int timeoutS, const QByteArray &writeData) +bool AndroidRunnerWorker::runAdb(const QStringList &args, QString *stdOut, + const QByteArray &writeData) { QStringList adbArgs = selector() + args; - qCDebug(androidRunWorkerLog) << "ADB command: " << m_adb << adbArgs.join(' '); - Utils::SynchronousProcess adb; - adb.setTimeoutS(timeoutS); - Utils::SynchronousProcessResponse response = adb.run(m_adb, adbArgs, writeData); - m_lastRunAdbError = response.exitMessage(m_adb, timeoutS); - m_lastRunAdbRawOutput = response.allRawOutput(); - bool success = response.result == Utils::SynchronousProcessResponse::Finished; - qCDebug(androidRunWorkerLog) << "ADB command result:" << success << response.allRawOutput(); - return success; + SdkToolResult result = AndroidManager::runAdbCommand(adbArgs, writeData); + if (!result.success()) + emit remoteErrorOutput(result.exitMessage() + "\n" + result.stdErr()); + if (stdOut) + *stdOut = result.stdOut(); + return result.success(); } bool AndroidRunnerWorker::uploadFile(const QString &from, const QString &to, const QString &flags) @@ -278,7 +252,8 @@ bool AndroidRunnerWorker::uploadFile(const QString &from, const QString &to, con if (!f.open(QIODevice::ReadOnly)) return false; runAdb({"shell", "run-as", m_packageName, "rm", to}); - auto res = runAdb({"shell", "run-as", m_packageName, "sh", "-c", QString("'cat > %1'").arg(to)}, 60, f.readAll()); + auto res = runAdb({"shell", "run-as", m_packageName, "sh", "-c", QString("'cat > %1'").arg(to)}, + nullptr, f.readAll()); if (!res) return false; return runAdb({"shell", "run-as", m_packageName, "chmod", flags, to}); @@ -297,17 +272,14 @@ QStringList AndroidRunnerWorker::selector() const void AndroidRunnerWorker::forceStop() { - runAdb({"shell", "am", "force-stop", m_packageName}, 30); + runAdb({"shell", "am", "force-stop", m_packageName}); // try killing it via kill -9 - const QByteArray out = Utils::SynchronousProcess() - .runBlocking(m_adb, selector() << QStringLiteral("shell") << pidScriptPreNougat) - .allRawOutput(); - + QString out; + runAdb({"shell", pidScriptPreNougat}, &out); qint64 pid = extractPID(out.simplified(), m_packageName); - if (pid != -1) { + if (pid != -1) adbKill(pid); - } } void AndroidRunnerWorker::logcatReadStandardError() @@ -395,17 +367,18 @@ void AndroidRunnerWorker::asyncStartHelper() { forceStop(); - // Start the logcat process before app starts. - std::unique_ptr logcatProcess(new QProcess, deleter); - connect(logcatProcess.get(), &QProcess::readyReadStandardOutput, - this, &AndroidRunnerWorker::logcatReadStandardOutput); - connect(logcatProcess.get(), &QProcess::readyReadStandardError, - this, &AndroidRunnerWorker::logcatReadStandardError); // Its assumed that the device or avd returned by selector() is online. - logcatProcess->start(m_adb, selector() << "logcat"); + // Start the logcat process before app starts. QTC_ASSERT(!m_adbLogcatProcess, /**/); - m_adbLogcatProcess = std::move(logcatProcess); - m_adbLogcatProcess->setObjectName("AdbLogcatProcess"); + m_adbLogcatProcess.reset(AndroidManager::runAdbCommandDetached(selector() << "logcat")); + if (m_adbLogcatProcess) { + m_adbLogcatProcess->setObjectName("AdbLogcatProcess"); + connect(m_adbLogcatProcess.get(), &QProcess::readyReadStandardOutput, + this, &AndroidRunnerWorker::logcatReadStandardOutput); + connect(m_adbLogcatProcess.get(), &QProcess::readyReadStandardError, + this, &AndroidRunnerWorker::logcatReadStandardError); + } + for (const QString &entry : m_beforeStartAdbCommands) runAdb(entry.split(' ', QString::SkipEmptyParts)); @@ -415,42 +388,27 @@ void AndroidRunnerWorker::asyncStartHelper() if (m_useCppDebugger) { args << "-D"; // run-as pwd fails on API 22 so route the pwd through shell. - if (!runAdb({"shell", "run-as", m_packageName, "/system/bin/sh", "-c", "pwd"})) { - emit remoteProcessFinished(tr("Failed to get process path. Reason: %1.").arg(m_lastRunAdbError)); + QString packageDir; + if (!runAdb({"shell", "run-as", m_packageName, "/system/bin/sh", "-c", "pwd"}, + &packageDir)) { + emit remoteProcessFinished(tr("Failed to find application directory.")); return; } - QString packageDir = QString::fromUtf8(m_lastRunAdbRawOutput.trimmed()); // Add executable flag to package dir. Gdb can't connect to running server on device on // e.g. on Android 8 with NDK 10e - runAdb({"shell", "run-as", m_packageName, "chmod", "a+x", packageDir}); + runAdb({"shell", "run-as", m_packageName, "chmod", "a+x", packageDir.trimmed()}); if (m_gdbserverPath.isEmpty() || !uploadFile(m_gdbserverPath, "gdbserver")) { emit remoteProcessFinished(tr("Can not find/copy C++ debug server.")); return; } - QString gdbServerSocket = packageDir + "/debug-socket"; - runAdb({"shell", "run-as", m_packageName, "killall", "gdbserver"}); - runAdb({"shell", "run-as", m_packageName, "rm", gdbServerSocket}); - std::unique_ptr gdbServerProcess(new QProcess, deleter); - gdbServerProcess->start(m_adb, selector() << "shell" << "run-as" - << m_packageName << "./gdbserver" - << "--multi" << "+" + gdbServerSocket); - if (!gdbServerProcess->waitForStarted()) { - emit remoteProcessFinished(tr("Failed to start C++ debugger.")); + QString debuggerServerErr; + if (!startDebuggerServer(packageDir, &debuggerServerErr)) { + emit remoteProcessFinished(debuggerServerErr); return; } - m_gdbServerProcess = std::move(gdbServerProcess); - m_gdbServerProcess->setObjectName("GdbServerProcess"); - QStringList removeForward{"forward", "--remove", "tcp:" + m_localGdbServerPort.toString()}; - runAdb(removeForward); - if (!runAdb({"forward", "tcp:" + m_localGdbServerPort.toString(), - "localfilesystem:" + gdbServerSocket})) { - emit remoteProcessFinished(tr("Failed to forward C++ debugging ports. Reason: %1.").arg(m_lastRunAdbError)); - return; - } - m_afterFinishAdbCommands.push_back(removeForward.join(' ')); } if (m_qmlDebugServices != QmlDebug::NoQmlDebugServices) { @@ -459,8 +417,7 @@ void AndroidRunnerWorker::asyncStartHelper() QStringList removeForward{{"forward", "--remove", port}}; runAdb(removeForward); if (!runAdb({"forward", port, port})) { - emit remoteProcessFinished(tr("Failed to forward QML debugging ports. Reason: %1.") - .arg(m_lastRunAdbError) + "\n" + m_lastRunAdbRawOutput); + emit remoteProcessFinished(tr("Failed to forward QML debugging ports.")); return; } m_afterFinishAdbCommands.push_back(removeForward.join(' ')); @@ -487,17 +444,49 @@ void AndroidRunnerWorker::asyncStartHelper() } if (!runAdb(args)) { - emit remoteProcessFinished(tr("Failed to start the activity. Reason: %1.") - .arg(m_lastRunAdbError)); + emit remoteProcessFinished(tr("Failed to start the activity")); return; } } +bool AndroidRunnerWorker::startDebuggerServer(QString packageDir, QString *errorStr) +{ + QString gdbServerSocket = packageDir + "/debug-socket"; + runAdb({"shell", "run-as", m_packageName, "killall", "gdbserver"}); + runAdb({"shell", "run-as", m_packageName, "rm", gdbServerSocket}); + + QString gdbProcessErr; + QStringList gdbServerArgs = selector(); + gdbServerArgs << "shell" << "run-as" << m_packageName << "./gdbserver" << "--multi" + << "+" + gdbServerSocket; + m_gdbServerProcess.reset(AndroidManager::runAdbCommandDetached(gdbServerArgs, &gdbProcessErr)); + + if (!m_gdbServerProcess) { + qCDebug(androidRunWorkerLog) << "Debugger process failed to start" << gdbProcessErr; + if (errorStr) + *errorStr = tr("Failed to start debugger server."); + return false; + } + qCDebug(androidRunWorkerLog) << "Debugger process started"; + m_gdbServerProcess->setObjectName("AndroidDebugServerProcess"); + + QStringList removeForward{"forward", "--remove", "tcp:" + m_localGdbServerPort.toString()}; + runAdb(removeForward); + if (!runAdb({"forward", "tcp:" + m_localGdbServerPort.toString(), + "localfilesystem:" + gdbServerSocket})) { + if (errorStr) + *errorStr = tr("Failed to forward C++ debugging ports."); + return false; + } + m_afterFinishAdbCommands.push_back(removeForward.join(' ')); + return true; +} + void AndroidRunnerWorker::asyncStart() { asyncStartHelper(); - m_pidFinder = Utils::onResultReady(Utils::runAsync(findProcessPID, m_adb, selector(), + m_pidFinder = Utils::onResultReady(Utils::runAsync(findProcessPID, selector(), m_packageName, m_isPreNougat), bind(&AndroidRunnerWorker::onProcessIdChanged, this, _1)); } @@ -520,7 +509,7 @@ void AndroidRunnerWorker::handleJdbWaiting() runAdb(removeForward); if (!runAdb({"forward", "tcp:" + m_localJdbServerPort.toString(), "jdwp:" + QString::number(m_processPID)})) { - emit remoteProcessFinished(tr("Failed to forward jdb debugging ports. Reason: %1.").arg(m_lastRunAdbError)); + emit remoteProcessFinished(tr("Failed to forward jdb debugging ports.")); return; } m_afterFinishAdbCommands.push_back(removeForward.join(' ')); @@ -579,8 +568,7 @@ void AndroidRunnerWorker::handleJdbSettled() } } } - emit remoteProcessFinished(tr("Cannot attach jdb to the running application. Reason: %1.") - .arg(m_lastRunAdbError)); + emit remoteProcessFinished(tr("Cannot attach jdb to the running application")); } void AndroidRunnerWorker::onProcessIdChanged(qint64 pid) @@ -608,13 +596,13 @@ void AndroidRunnerWorker::onProcessIdChanged(qint64 pid) emit remoteProcessStarted(m_localGdbServerPort, m_qmlServer, m_processPID); logcatReadStandardOutput(); QTC_ASSERT(!m_psIsAlive, /**/); - m_psIsAlive.reset(new QProcess); + QStringList isAliveArgs = selector() << "shell" << pidPollingScript.arg(m_processPID); + m_psIsAlive.reset(AndroidManager::runAdbCommandDetached(isAliveArgs)); + QTC_ASSERT(m_psIsAlive, return); m_psIsAlive->setObjectName("IsAliveProcess"); m_psIsAlive->setProcessChannelMode(QProcess::MergedChannels); connect(m_psIsAlive.get(), static_cast(&QProcess::finished), this, bind(&AndroidRunnerWorker::onProcessIdChanged, this, -1)); - m_psIsAlive->start(m_adb, selector() << QStringLiteral("shell") - << pidPollingScript.arg(m_processPID)); } } diff --git a/src/plugins/android/androidrunnerworker.h b/src/plugins/android/androidrunnerworker.h index ee5ec87287a..6f166ea7c27 100644 --- a/src/plugins/android/androidrunnerworker.h +++ b/src/plugins/android/androidrunnerworker.h @@ -46,9 +46,9 @@ class AndroidRunnerWorker : public QObject public: AndroidRunnerWorker(ProjectExplorer::RunWorker *runner, const QString &packageName); ~AndroidRunnerWorker() override; - bool adbShellAmNeedsQuotes(); - bool runAdb(const QStringList &args, int timeoutS = 10, const QByteArray &writeData = {}); + bool uploadFile(const QString &from, const QString &to, const QString &flags = QString("+x")); + bool runAdb(const QStringList &args, QString *stdOut = nullptr, const QByteArray &writeData = {}); void adbKill(qint64 pid); QStringList selector() const; void forceStop(); @@ -73,6 +73,7 @@ signals: protected: void asyncStartHelper(); + bool startDebuggerServer(QString packageDir, QString *errorStr = nullptr); enum class JDBState { Idle, @@ -88,7 +89,6 @@ protected: QString m_intentName; QStringList m_beforeStartAdbCommands; QStringList m_afterFinishAdbCommands; - QString m_adb; QStringList m_amStartExtraArgs; qint64 m_processPID = -1; std::unique_ptr m_adbLogcatProcess; @@ -101,8 +101,6 @@ protected: QmlDebug::QmlDebugServicesPreset m_qmlDebugServices; Utils::Port m_localGdbServerPort; // Local end of forwarded debug socket. QUrl m_qmlServer; - QByteArray m_lastRunAdbRawOutput; - QString m_lastRunAdbError; JDBState m_jdbState = JDBState::Idle; Utils::Port m_localJdbServerPort; std::unique_ptr m_gdbServerProcess;