diff --git a/src/plugins/android/androiddebugsupport.cpp b/src/plugins/android/androiddebugsupport.cpp index 721529f0b23..25967ba2e2a 100644 --- a/src/plugins/android/androiddebugsupport.cpp +++ b/src/plugins/android/androiddebugsupport.cpp @@ -186,16 +186,6 @@ AndroidDebugSupport::AndroidDebugSupport(AndroidRunConfiguration *runConfig, QTC_ASSERT(m_runControl, return); m_runControl->showMessage(output, AppOutput); }); - - QTC_ASSERT(runControl, return); - auto formatter = qobject_cast(runControl->outputFormatter()); - QTC_ASSERT(formatter, return); - connect(m_runner, &AndroidRunner::pidFound, formatter, &AndroidOutputFormatter::appendPid); - connect(m_runner, &AndroidRunner::pidLost, formatter, &AndroidOutputFormatter::removePid); - connect(m_runner, &AndroidRunner::remoteProcessFinished, formatter, - [formatter] { - formatter->removePid(-1); - }); } void AndroidDebugSupport::handleRemoteProcessStarted(Utils::Port gdbServerPort, Utils::Port qmlPort) diff --git a/src/plugins/android/androidrunconfiguration.cpp b/src/plugins/android/androidrunconfiguration.cpp index 54f64497539..d2d7844e5c6 100644 --- a/src/plugins/android/androidrunconfiguration.cpp +++ b/src/plugins/android/androidrunconfiguration.cpp @@ -29,205 +29,16 @@ #include "androidmanager.h" #include -#include -#include #include #include #include -#include -#include -#include #include -#include using namespace ProjectExplorer; namespace Android { -static QRegularExpression logCatRegExp("([0-9\\-]*\\s+[0-9\\-:.]*)" // 1. time - "\\s*" - "([DEIVWF])" // 2. log level - "\\/" - "(.*)" // 3. TAG - "\\(\\s*" - "(\\d+)" // 4. PID - "\\)\\:\\s" - "(.*)"); // 5. Message - -AndroidOutputFormatter::AndroidOutputFormatter(Project *project) - : QtSupport::QtOutputFormatter(project) - , m_filtersButton(new QToolButton) -{ - auto filtersMenu = new QMenu(m_filtersButton.data()); - - m_filtersButton->setToolTip(tr("Filters")); - m_filtersButton->setIcon(Utils::Icons::FILTER.icon()); - m_filtersButton->setProperty("noArrow", true); - m_filtersButton->setAutoRaise(true); - m_filtersButton->setPopupMode(QToolButton::InstantPopup); - m_filtersButton->setMenu(filtersMenu); - - auto logsMenu = filtersMenu->addMenu(tr("Log Level")); - addLogAction(All, logsMenu, tr("All")); - addLogAction(Verbose, logsMenu, tr("Verbose")); - addLogAction(Info, logsMenu, tr("Info")); - addLogAction(Debug, logsMenu, tr("Debug")); - addLogAction(Warning, logsMenu, tr("Warning")); - addLogAction(Error, logsMenu, tr("Error")); - addLogAction(Fatal, logsMenu, tr("Fatal")); - updateLogMenu(); - m_appsMenu = filtersMenu->addMenu(tr("Applications")); - appendPid(-1, tr("All")); -} - -AndroidOutputFormatter::~AndroidOutputFormatter() -{} - -QList AndroidOutputFormatter::toolbarWidgets() const -{ - return QList{m_filtersButton.data()}; -} - -void AndroidOutputFormatter::appendMessage(const QString &text, Utils::OutputFormat format) -{ - if (text.isEmpty()) - return; - - CachedLine line; - line.content = text; - - if (format < Utils::StdOutFormat) { - line.level = SkipFiltering; - line.pid = -1; - } else { - QRegularExpressionMatch match = logCatRegExp.match(text); - if (!match.hasMatch()) - return; - line.level = None; - - switch (match.captured(2).toLatin1()[0]) { - case 'D': line.level = Debug; break; - case 'I': line.level = Info; break; - case 'V': line.level = Verbose; break; - case 'W': line.level = Warning; break; - case 'E': line.level = Error; break; - case 'F': line.level = Fatal; break; - default: return; - } - line.pid = match.captured(4).toLongLong(); - } - - m_cachedLines.append(line); - if (m_cachedLines.size() > ProjectExplorerPlugin::projectExplorerSettings().maxAppOutputLines) - m_cachedLines.pop_front(); - - filterMessage(line); -} - -void AndroidOutputFormatter::clear() -{ - m_cachedLines.clear(); -} - -void AndroidOutputFormatter::appendPid(qint64 pid, const QString &name) -{ - if (m_pids.contains(pid)) - return; - - auto action = m_appsMenu->addAction(name); - m_pids[pid] = action; - action->setCheckable(true); - action->setChecked(pid != -1); - connect(action, &QAction::triggered, this, &AndroidOutputFormatter::applyFilter); - applyFilter(); -} - -void AndroidOutputFormatter::removePid(qint64 pid) -{ - if (pid == -1) { - for (auto action : m_pids) - m_appsMenu->removeAction(action); - m_pids.clear(); - } else { - m_appsMenu->removeAction(m_pids[pid]); - m_pids.remove(pid); - } -} - -void AndroidOutputFormatter::updateLogMenu(LogLevel set, LogLevel reset) -{ - m_logLevelFlags |= set; - m_logLevelFlags &= ~reset; - for (const auto & pair : m_logLevels) - pair.second->setChecked((m_logLevelFlags & pair.first) == pair.first); - - applyFilter(); -} - -void AndroidOutputFormatter::filterMessage(const CachedLine &line) -{ - if (line.level == SkipFiltering || m_pids[-1]->isChecked()) { - QtOutputFormatter::appendMessage(line.content, Utils::NormalMessageFormat); - } else { - // Filter Log Level - if (!(m_logLevelFlags & line.level)) - return; - - // Filter PIDs - if (!m_pids[-1]->isChecked()) { - auto it = m_pids.find(line.pid); - if (it == m_pids.end() || !(*it)->isChecked()) - return; - } - - Utils::OutputFormat format = Utils::NormalMessageFormat; - switch (line.level) { - case Debug: - format = Utils::DebugFormat; - break; - case Info: - case Verbose: - format = Utils::StdOutFormat; - break; - - case Warning: - case Error: - case Fatal: - format = Utils::StdErrFormat; - break; - default: - return; - } - - Utils::OutputFormatter::appendMessage(line.content, format); - } -} - -void AndroidOutputFormatter::applyFilter() -{ - if (!plainTextEdit()) - return; - - plainTextEdit()->clear(); - if (!m_pids[-1]->isChecked()) { - bool allOn = true; - for (auto action : m_pids) { - if (!action->isChecked()) { - allOn = false; - break; - } - } - m_pids[-1]->setChecked(allOn); - } else { - for (auto action : m_pids) - action->setChecked(true); - } - - for (const auto &line : m_cachedLines) - filterMessage(line); -} - AndroidRunConfiguration::AndroidRunConfiguration(Target *parent, Core::Id id) : RunConfiguration(parent, id) { @@ -245,7 +56,7 @@ QWidget *AndroidRunConfiguration::createConfigurationWidget() Utils::OutputFormatter *AndroidRunConfiguration::createOutputFormatter() const { - return new AndroidOutputFormatter(target()->project()); + return new QtSupport::QtOutputFormatter(target()->project()); } const QString AndroidRunConfiguration::remoteChannel() const diff --git a/src/plugins/android/androidrunconfiguration.h b/src/plugins/android/androidrunconfiguration.h index 9ec42e3d78f..b9b4d6ab9de 100644 --- a/src/plugins/android/androidrunconfiguration.h +++ b/src/plugins/android/androidrunconfiguration.h @@ -28,9 +28,6 @@ #include "android_global.h" #include -#include - -#include QT_BEGIN_NAMESPACE class QToolButton; @@ -38,65 +35,6 @@ QT_END_NAMESPACE namespace Android { -class AndroidOutputFormatter : public QtSupport::QtOutputFormatter -{ - Q_OBJECT -public: - enum LogLevel { - None = 0, - Verbose = 1, - Info = 1 << 1, - Debug = 1 << 2, - Warning = 1 << 3, - Error = 1 << 4, - Fatal = 1 << 5, - All = Verbose | Info | Debug | Warning | Error | Fatal, - SkipFiltering = ~All - }; - -public: - explicit AndroidOutputFormatter(ProjectExplorer::Project *project); - ~AndroidOutputFormatter(); - - // OutputFormatter interface - QList toolbarWidgets() const override; - void appendMessage(const QString &text, Utils::OutputFormat format) override; - void clear() override; - -public slots: - void appendPid(qint64 pid, const QString &name); - void removePid(qint64 pid); - -private: - struct CachedLine { - qint64 pid; - LogLevel level; - QString content; - }; - -private: - void updateLogMenu(LogLevel set = None, LogLevel reset = None); - void filterMessage(const CachedLine &line); - - void applyFilter(); - void addLogAction(LogLevel level, QMenu *logsMenu, const QString &name) { - auto action = logsMenu->addAction(name); - m_logLevels.push_back(qMakePair(level, action)); - action->setCheckable(true); - connect(action, &QAction::triggered, this, [level, this](bool checked) { - updateLogMenu(checked ? level : None , checked ? None : level); - }); - } - -private: - int m_logLevelFlags = All; - QVector> m_logLevels; - QHash m_pids; - QScopedPointer m_filtersButton; - QMenu *m_appsMenu; - QList m_cachedLines; -}; - class ANDROID_EXPORT AndroidRunConfiguration : public ProjectExplorer::RunConfiguration { Q_OBJECT diff --git a/src/plugins/android/androidruncontrol.cpp b/src/plugins/android/androidruncontrol.cpp index b220bdda99e..7c5d815a168 100644 --- a/src/plugins/android/androidruncontrol.cpp +++ b/src/plugins/android/androidruncontrol.cpp @@ -62,13 +62,6 @@ void AndroidRunControl::start() this, &AndroidRunControl::handleRemoteOutput); connect(m_runner, &AndroidRunner::remoteProcessFinished, this, &AndroidRunControl::handleRemoteProcessFinished); - - auto formatter = static_cast(outputFormatter()); - connect(m_runner, &AndroidRunner::pidFound, - formatter, &AndroidOutputFormatter::appendPid); - connect(m_runner, &AndroidRunner::pidLost, - formatter, &AndroidOutputFormatter::removePid); - appendMessage(tr("Starting remote process."), Utils::NormalMessageFormat); m_runner->setRunnable(runnable().as()); m_runner->start(); diff --git a/src/plugins/android/androidrunner.cpp b/src/plugins/android/androidrunner.cpp index b10dd2ee5d7..ad1b511938c 100644 --- a/src/plugins/android/androidrunner.cpp +++ b/src/plugins/android/androidrunner.cpp @@ -52,7 +52,6 @@ #include #include #include -#include using namespace std; using namespace std::placeholders; @@ -127,10 +126,10 @@ namespace Internal { const int MIN_SOCKET_HANDSHAKE_PORT = 20001; const int MAX_SOCKET_HANDSHAKE_PORT = 20999; -static const QString pidScript = QStringLiteral("input keyevent KEYCODE_WAKEUP; " - "while true; do sleep 1; echo \"=\"; " - "for p in /proc/[0-9]*; " - "do cat <$p/cmdline && echo :${p##*/}; done; done"); +static const QString pidScript = QStringLiteral("for p in /proc/[0-9]*; " + "do cat <$p/cmdline && echo :${p##*/}; done"); +static const QString pidPollingScript = QStringLiteral("while true; do sleep 1; " + "cat /proc/%1/cmdline > /dev/null; done"); static const QString regExpLogcat = QStringLiteral("[0-9\\-]*" // date "\\s+" @@ -148,26 +147,55 @@ static const QString regExpLogcat = QStringLiteral("[0-9\\-]*" // date ); static int APP_START_TIMEOUT = 45000; -enum class PidStatus { - Found, - Lost -}; - -struct PidInfo +static bool isTimedOut(const chrono::high_resolution_clock::time_point &start, + int msecs = APP_START_TIMEOUT) { - PidInfo(qint64 pid = -1, PidStatus status = PidStatus::Lost, QString name = {}) - : pid(pid) - , status(status) - , name(name) - {} - qint64 pid; - PidStatus status; - QString name; -}; + bool timedOut = false; + auto end = chrono::high_resolution_clock::now(); + if (chrono::duration_cast(end-start).count() > msecs) + timedOut = true; + return timedOut; +} + +static qint64 extractPID(const QByteArray &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()); + if (parts.length() == 2 && commandName == packageName) { + pid = parts.last().toLongLong(); + break; + } + } + } + return pid; +} + +void findProcessPID(QFutureInterface &fi, const QString &adbPath, + QStringList selector, const QString &packageName) +{ + if (packageName.isEmpty()) + return; + + qint64 processPID = -1; + chrono::high_resolution_clock::time_point start = chrono::high_resolution_clock::now(); + do { + QThread::msleep(200); + const QByteArray out = Utils::SynchronousProcess() + .runBlocking(adbPath, selector << QStringLiteral("shell") << pidScript) + .allRawOutput(); + processPID = extractPID(out, packageName); + } while (processPID == -1 && !isTimedOut(start) && !fi.isCanceled()); + + if (!fi.isCanceled()) + fi.reportResult(processPID); +} static void deleter(QProcess *p) { - p->disconnect(); p->kill(); p->waitForFinished(); // Might get deleted from its own signal handler. @@ -201,31 +229,29 @@ signals: void remoteOutput(const QString &output); void remoteErrorOutput(const QString &output); - void pidFound(qint64, const QString &name); - void pidLost(qint64); private: - void findProcessPids(); - void onProcessIdChanged(PidInfo pidInfo); + void onProcessIdChanged(qint64 pid); void logcatReadStandardError(); void logcatReadStandardOutput(); void adbKill(qint64 pid); QStringList selector() const { return m_selector; } void forceStop(); + void findPs(); void logcatProcess(const QByteArray &text, QByteArray &buffer, bool onlyError); bool adbShellAmNeedsQuotes(); bool runAdb(const QStringList &args, QString *exitMessage = nullptr, int timeoutS = 10); - int deviceSdkVersion(); // Create the processes and timer in the worker thread, for correct thread affinity std::unique_ptr m_adbLogcatProcess; - std::unique_ptr m_pidsFinderProcess; + std::unique_ptr m_psIsAlive; QScopedPointer m_socket; QByteArray m_stdoutBuffer; QByteArray m_stderrBuffer; - QSet m_processPids; + QFuture m_pidFinder; + qint64 m_processPID = -1; bool m_useCppDebugger = false; QmlDebug::QmlDebugServicesPreset m_qmlDebugServices; Utils::Port m_localGdbServerPort; // Local end of forwarded debug socket. @@ -236,20 +262,20 @@ private: QString m_gdbserverSocket; QString m_adb; QStringList m_selector; + QRegExp m_logCatRegExp; DebugHandShakeType m_handShakeMethod = SocketHandShake; bool m_customPort = false; QString m_packageName; int m_socketHandShakePort = MIN_SOCKET_HANDSHAKE_PORT; - QByteArray m_pidsBuffer; - QScopedPointer m_timeoutTimer; }; AndroidRunnerWorker::AndroidRunnerWorker(AndroidRunConfiguration *runConfig, Core::Id runMode, const QString &packageName, const QStringList &selector) : m_adbLogcatProcess(nullptr, deleter) - , m_pidsFinderProcess(nullptr, deleter) + , m_psIsAlive(nullptr, deleter) , m_selector(selector) + , m_logCatRegExp(regExpLogcat) , m_packageName(packageName) { Debugger::DebuggerRunConfigurationAspect *aspect @@ -313,18 +339,23 @@ AndroidRunnerWorker::AndroidRunnerWorker(AndroidRunConfiguration *runConfig, Cor AndroidRunnerWorker::~AndroidRunnerWorker() { + if (!m_pidFinder.isFinished()) + m_pidFinder.cancel(); } void AndroidRunnerWorker::forceStop() { runAdb(selector() << "shell" << "am" << "force-stop" << m_packageName, nullptr, 30); - for (auto it = m_processPids.constBegin(); it != m_processPids.constEnd(); ++it) { - emit pidLost(*it); - adbKill(*it); + // try killing it via kill -9 + const QByteArray out = Utils::SynchronousProcess() + .runBlocking(m_adb, selector() << QStringLiteral("shell") << pidScript) + .allRawOutput(); + + qint64 pid = extractPID(out.simplified(), m_packageName); + if (pid != -1) { + adbKill(pid); } - m_processPids.clear(); - m_pidsBuffer.clear(); } void AndroidRunnerWorker::asyncStart(const QString &intentName, @@ -338,12 +369,8 @@ void AndroidRunnerWorker::asyncStart(const QString &intentName, this, &AndroidRunnerWorker::logcatReadStandardOutput); connect(logcatProcess.get(), &QProcess::readyReadStandardError, this, &AndroidRunnerWorker::logcatReadStandardError); - // Its assumed that the device or avd returned by selector() is online. - QStringList logcatArgs = selector() << "logcat" << "-v" << "time"; - if (deviceSdkVersion() > 20) - logcatArgs << "-T" << "0"; - logcatProcess->start(m_adb, logcatArgs); + logcatProcess->start(m_adb, selector() << "logcat"); QString errorMessage; @@ -481,20 +508,9 @@ void AndroidRunnerWorker::asyncStart(const QString &intentName, QTC_ASSERT(!m_adbLogcatProcess, /**/); m_adbLogcatProcess = std::move(logcatProcess); - - m_timeoutTimer.reset(new QTimer); - m_timeoutTimer->setSingleShot(true); - connect(m_timeoutTimer.data(), &QTimer::timeout, - this,[this] { onProcessIdChanged(PidInfo{}); }); - m_timeoutTimer->start(APP_START_TIMEOUT); - - m_pidsFinderProcess.reset(new QProcess); - m_pidsFinderProcess->setProcessChannelMode(QProcess::MergedChannels); - connect(m_pidsFinderProcess.get(), &QProcess::readyRead, this, &AndroidRunnerWorker::findProcessPids); - connect(m_pidsFinderProcess.get(), - static_cast(&QProcess::finished), - this, [this] { onProcessIdChanged(PidInfo{}); }); - m_pidsFinderProcess->start(m_adb, selector() << "shell" << pidScript); + m_pidFinder = Utils::onResultReady(Utils::runAsync(&findProcessPID, m_adb, selector(), + m_packageName), + bind(&AndroidRunnerWorker::onProcessIdChanged, this, _1)); } bool AndroidRunnerWorker::adbShellAmNeedsQuotes() @@ -530,19 +546,6 @@ bool AndroidRunnerWorker::runAdb(const QStringList &args, QString *exitMessage, return response.result == Utils::SynchronousProcessResponse::Finished; } -int AndroidRunnerWorker::deviceSdkVersion() -{ - Utils::SynchronousProcess adb; - adb.setTimeoutS(10); - Utils::SynchronousProcessResponse response - = adb.run(m_adb, selector() << "shell" << "getprop" << "ro.build.version.sdk"); - if (response.result == Utils::SynchronousProcessResponse::StartFailed - || response.result != Utils::SynchronousProcessResponse::Finished) - return -1; - - return response.allOutput().trimmed().toInt(); -} - void AndroidRunnerWorker::handleRemoteDebuggerRunning() { if (m_useCppDebugger) { @@ -556,79 +559,21 @@ void AndroidRunnerWorker::handleRemoteDebuggerRunning() runAdb(selector() << "push" << tmp.fileName() << m_pongFile); } - QTC_CHECK(!m_processPids.isEmpty()); + QTC_CHECK(m_processPID != -1); } emit remoteProcessStarted(m_localGdbServerPort, m_qmlPort); } -void AndroidRunnerWorker::findProcessPids() -{ - static QMap extractedPids; - static auto oldPids = m_processPids; - - m_pidsBuffer += m_pidsFinderProcess->readAll(); - while (!m_pidsBuffer.isEmpty()) { - const int to = m_pidsBuffer.indexOf('\n'); - if (to < 0) - break; - - if (to == 0) { - m_pidsBuffer = m_pidsBuffer.mid(1); - continue; - } - - // = is used to delimit ps outputs - // is needed to know when an existins PID is killed - if (m_pidsBuffer[0] != '=') { - QByteArray tuple = m_pidsBuffer.left(to + 1).simplified(); - QList parts = tuple.split(':'); - QByteArray commandName = parts.takeFirst(); - if (QString::fromLocal8Bit(commandName) == m_packageName) { - auto pid = parts.last().toLongLong(); - if (!m_processPids.contains(pid)) { - extractedPids[pid] = commandName + (parts.length() == 2 - ? ":" + parts.first() : QByteArray{}); - } else { - oldPids.remove(pid); - } - } - } else { - // Add new PIDs - for (auto it = extractedPids.constBegin(); it != extractedPids.constEnd(); ++it) { - onProcessIdChanged(PidInfo(it.key(), PidStatus::Found, - QString::fromLocal8Bit(it.value()))); - } - extractedPids.clear(); - - // Remove the dead ones - for (auto it = oldPids.constBegin(); it != oldPids.constEnd(); ++it) - onProcessIdChanged(PidInfo(*it, PidStatus::Lost)); - - // Save the current non dead PIDs - oldPids = m_processPids; - if (m_processPids.isEmpty()) { - extractedPids.clear(); - m_pidsBuffer.clear(); - break; - } - } - m_pidsBuffer = m_pidsBuffer.mid(to + 1); - } -} - void AndroidRunnerWorker::asyncStop(const QVector &adbCommands) { - m_timeoutTimer.reset(); - m_pidsFinderProcess.reset(); - if (!m_processPids.isEmpty()) - forceStop(); + if (!m_pidFinder.isFinished()) + m_pidFinder.cancel(); + if (m_processPID != -1) { + forceStop(); + } foreach (const QStringList &entry, adbCommands) runAdb(selector() << entry); - - m_adbLogcatProcess.reset(); - emit remoteProcessFinished(QLatin1String("\n\n") + - tr("\"%1\" terminated.").arg(m_packageName)); } void AndroidRunnerWorker::setAdbParameters(const QString &packageName, const QStringList &selector) @@ -650,48 +595,58 @@ void AndroidRunnerWorker::logcatProcess(const QByteArray &text, QByteArray &buff buffer.clear(); } + QString pidString = QString::number(m_processPID); foreach (const QByteArray &msg, lines) { - const QString line = QString::fromUtf8(msg.trimmed()); - if (onlyError) - emit remoteErrorOutput(line); - else - emit remoteOutput(line); + const QString line = QString::fromUtf8(msg).trimmed() + QLatin1Char('\n'); + if (!line.contains(pidString)) + continue; + if (m_logCatRegExp.exactMatch(line)) { + // Android M + if (m_logCatRegExp.cap(1) == pidString) { + const QString &messagetype = m_logCatRegExp.cap(2); + QString output = line.mid(m_logCatRegExp.pos(2)); + + if (onlyError + || messagetype == QLatin1String("F") + || messagetype == QLatin1String("E") + || messagetype == QLatin1String("W")) + emit remoteErrorOutput(output); + else + emit remoteOutput(output); + } + } else { + if (onlyError || line.startsWith("F/") + || line.startsWith("E/") + || line.startsWith("W/")) + emit remoteErrorOutput(line); + else + emit remoteOutput(line); + } } } -void AndroidRunnerWorker::onProcessIdChanged(PidInfo pidInfo) +void AndroidRunnerWorker::onProcessIdChanged(qint64 pid) { // Don't write to m_psProc from a different thread QTC_ASSERT(QThread::currentThread() == thread(), return); - - auto isFirst = m_processPids.isEmpty(); - if (pidInfo.status == PidStatus::Lost) { - m_processPids.remove(pidInfo.pid); - emit pidLost(pidInfo.pid); - } else { - m_processPids.insert(pidInfo.pid); - emit pidFound(pidInfo.pid, pidInfo.name); - } - - if (m_processPids.isEmpty() || pidInfo.pid == -1) { + m_processPID = pid; + if (m_processPID == -1) { emit remoteProcessFinished(QLatin1String("\n\n") + tr("\"%1\" died.") .arg(m_packageName)); // App died/killed. Reset log and monitor processes. - forceStop(); m_adbLogcatProcess.reset(); - m_timeoutTimer.reset(); - } else if (isFirst) { - m_timeoutTimer.reset(); + m_psIsAlive.reset(); + } else { if (m_useCppDebugger) { // 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_localGdbServerPort.number()); - emit remoteServerRunning(serverChannel, pidInfo.pid); + emit remoteServerRunning(serverChannel, m_processPID); } else if (m_qmlDebugServices == QmlDebug::QmlDebuggerServices) { // 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.number()); - emit remoteServerRunning(serverChannel, pidInfo.pid); + emit remoteServerRunning(serverChannel, m_processPID); } else if (m_qmlDebugServices == QmlDebug::QmlProfilerServices) { emit remoteProcessStarted(Utils::Port(), m_qmlPort); } else { @@ -699,18 +654,27 @@ void AndroidRunnerWorker::onProcessIdChanged(PidInfo pidInfo) emit remoteProcessStarted(Utils::Port(), Utils::Port()); } logcatReadStandardOutput(); + QTC_ASSERT(!m_psIsAlive, /**/); + m_psIsAlive.reset(new QProcess); + m_psIsAlive->setProcessChannelMode(QProcess::MergedChannels); + connect(m_psIsAlive.get(), &QProcess::readyRead, [this](){ + if (!m_psIsAlive->readAll().simplified().isEmpty()) + onProcessIdChanged(-1); + }); + m_psIsAlive->start(m_adb, selector() << QStringLiteral("shell") + << pidPollingScript.arg(m_processPID)); } } void AndroidRunnerWorker::logcatReadStandardError() { - if (!m_processPids.isEmpty() && m_adbLogcatProcess) + if (m_processPID != -1) logcatProcess(m_adbLogcatProcess->readAllStandardError(), m_stderrBuffer, true); } void AndroidRunnerWorker::logcatReadStandardOutput() { - if (!m_processPids.isEmpty() && m_adbLogcatProcess) + if (m_processPID != -1) logcatProcess(m_adbLogcatProcess->readAllStandardOutput(), m_stdoutBuffer, false); } @@ -761,10 +725,6 @@ AndroidRunner::AndroidRunner(QObject *parent, AndroidRunConfiguration *runConfig this, &AndroidRunner::remoteOutput); connect(m_worker.data(), &AndroidRunnerWorker::remoteErrorOutput, this, &AndroidRunner::remoteErrorOutput); - connect(m_worker.data(), &AndroidRunnerWorker::pidFound, - this, &AndroidRunner::pidFound); - connect(m_worker.data(), &AndroidRunnerWorker::pidLost, - this, &AndroidRunner::pidLost); m_thread.start(); } diff --git a/src/plugins/android/androidrunner.h b/src/plugins/android/androidrunner.h index 5332726ac35..c77180f874a 100644 --- a/src/plugins/android/androidrunner.h +++ b/src/plugins/android/androidrunner.h @@ -76,9 +76,6 @@ signals: void adbParametersChanged(const QString &packageName, const QStringList &selector); void avdDetected(); - void pidFound(qint64, const QString &name); - void pidLost(qint64); - private: void checkAVD(); void launchAVD();