diff --git a/src/plugins/android/androidrunner.cpp b/src/plugins/android/androidrunner.cpp index a60156bacfe..8b908eaf059 100644 --- a/src/plugins/android/androidrunner.cpp +++ b/src/plugins/android/androidrunner.cpp @@ -44,14 +44,12 @@ AndroidRunner::AndroidRunner(RunControl *runControl) this, &AndroidRunner::qmlServerPortReady); } -AndroidRunner::~AndroidRunner() -{ - m_thread.quit(); - m_thread.wait(); -} - void AndroidRunner::start() { + const Storage glueStorage; + + std::optional avdRecipe; + QString deviceSerialNumber; int apiLevel = -1; @@ -69,56 +67,49 @@ void AndroidRunner::start() if (!info.avdName.isEmpty()) { const Storage serialNumberStorage; - const Group recipe { + avdRecipe = Group { serialNumberStorage, AndroidAvdManager::startAvdRecipe(info.avdName, serialNumberStorage) - }; - - m_startAvdRunner.start(recipe, {}, [this, deviceSerialNumber, apiLevel](DoneWith result) { - if (result == DoneWith::Success) - startImpl(deviceSerialNumber, apiLevel); + }.withCancel([glueStorage] { + return std::make_pair(glueStorage.activeStorage(), &RunnerInterface::canceled); }); - return; } } else { deviceSerialNumber = AndroidManager::deviceSerialNumber(m_target); apiLevel = AndroidManager::deviceApiLevel(m_target); } - startImpl(deviceSerialNumber, apiLevel); + + const auto onSetup = [this, glueStorage, deviceSerialNumber, apiLevel] { + RunnerInterface *glue = glueStorage.activeStorage(); + glue->setRunControl(runControl()); + glue->setDeviceSerialNumber(deviceSerialNumber); + glue->setApiLevel(apiLevel); + + connect(this, &AndroidRunner::canceled, glue, &RunnerInterface::cancel); + + connect(glue, &RunnerInterface::started, this, &AndroidRunner::remoteStarted); + connect(glue, &RunnerInterface::finished, this, &AndroidRunner::remoteFinished); + connect(glue, &RunnerInterface::stdOut, this, &AndroidRunner::remoteStdOut); + connect(glue, &RunnerInterface::stdErr, this, &AndroidRunner::remoteStdErr); + }; + + const Group recipe { + glueStorage, + onGroupSetup(onSetup), + avdRecipe ? *avdRecipe : nullItem, + runnerRecipe(glueStorage) + }; + m_taskTreeRunner.start(recipe); } void AndroidRunner::stop() { - if (m_startAvdRunner.isRunning()) { - m_startAvdRunner.reset(); - appendMessage("\n\n" + Tr::tr("\"%1\" terminated.").arg(AndroidManager::packageName(m_target)), - Utils::NormalMessageFormat); + if (!m_taskTreeRunner.isRunning()) return; - } - emit asyncStop(); -} -void AndroidRunner::startImpl(const QString &deviceSerialNumber, int apiLevel) -{ - if (m_worker) - m_worker->deleteLater(); - - m_worker = new AndroidRunnerWorker(runControl(), deviceSerialNumber, apiLevel); - m_worker->moveToThread(&m_thread); - QObject::connect(&m_thread, &QThread::finished, m_worker, &QObject::deleteLater); - - connect(this, &AndroidRunner::asyncStop, m_worker, &AndroidRunnerWorker::asyncStop); - - connect(m_worker, &AndroidRunnerWorker::remoteProcessStarted, - this, &AndroidRunner::handleRemoteProcessStarted); - connect(m_worker, &AndroidRunnerWorker::remoteProcessFinished, - this, &AndroidRunner::handleRemoteProcessFinished); - connect(m_worker, &AndroidRunnerWorker::remoteOutput, this, &AndroidRunner::remoteOutput); - connect(m_worker, &AndroidRunnerWorker::remoteErrorOutput, - this, &AndroidRunner::remoteErrorOutput); - - m_thread.start(); - QMetaObject::invokeMethod(m_worker, &AndroidRunnerWorker::asyncStart); + emit canceled(); + appendMessage("\n\n" + Tr::tr("\"%1\" terminated.").arg(AndroidManager::packageName(m_target)), + Utils::NormalMessageFormat); } void AndroidRunner::qmlServerPortReady(Port port) @@ -134,20 +125,7 @@ void AndroidRunner::qmlServerPortReady(Port port) emit qmlServerReady(serverUrl); } -void AndroidRunner::remoteOutput(const QString &output) -{ - appendMessage(output, Utils::StdOutFormat); - m_outputParser.processOutput(output); -} - -void AndroidRunner::remoteErrorOutput(const QString &output) -{ - appendMessage(output, Utils::StdErrFormat); - m_outputParser.processOutput(output); -} - -void AndroidRunner::handleRemoteProcessStarted(Utils::Port debugServerPort, - const QUrl &qmlServer, qint64 pid) +void AndroidRunner::remoteStarted(const Port &debugServerPort, const QUrl &qmlServer, qint64 pid) { m_pid = ProcessHandle(pid); m_debugServerPort = debugServerPort; @@ -155,7 +133,7 @@ void AndroidRunner::handleRemoteProcessStarted(Utils::Port debugServerPort, reportStarted(); } -void AndroidRunner::handleRemoteProcessFinished(const QString &errString) +void AndroidRunner::remoteFinished(const QString &errString) { appendMessage(errString, Utils::NormalMessageFormat); if (runControl()->isRunning()) @@ -163,4 +141,16 @@ void AndroidRunner::handleRemoteProcessFinished(const QString &errString) reportStopped(); } +void AndroidRunner::remoteStdOut(const QString &output) +{ + appendMessage(output, Utils::StdOutFormat); + m_outputParser.processOutput(output); +} + +void AndroidRunner::remoteStdErr(const QString &output) +{ + appendMessage(output, Utils::StdErrFormat); + m_outputParser.processOutput(output); +} + } // namespace Android::Internal diff --git a/src/plugins/android/androidrunner.h b/src/plugins/android/androidrunner.h index e439becc897..b5ac68c4a9a 100644 --- a/src/plugins/android/androidrunner.h +++ b/src/plugins/android/androidrunner.h @@ -12,19 +12,14 @@ #include -#include - namespace Android::Internal { -class AndroidRunnerWorker; - class AndroidRunner : public ProjectExplorer::RunWorker { Q_OBJECT public: explicit AndroidRunner(ProjectExplorer::RunControl *runControl); - ~AndroidRunner() override; Utils::Port debugServerPort() const { return m_debugServerPort; } // GDB or LLDB QUrl qmlServer() const { return m_qmlServer; } @@ -34,27 +29,24 @@ public: void stop() override; signals: - void asyncStop(); + void canceled(); void qmlServerReady(const QUrl &serverUrl); void avdDetected(); private: - void startImpl(const QString &deviceSerialNumber, int apiLevel); void qmlServerPortReady(Utils::Port port); - void remoteOutput(const QString &output); - void remoteErrorOutput(const QString &output); - void gotRemoteOutput(const QString &output); - void handleRemoteProcessStarted(Utils::Port debugServerPort, const QUrl &qmlServer, qint64 pid); - void handleRemoteProcessFinished(const QString &errString = QString()); - QThread m_thread; - AndroidRunnerWorker *m_worker = nullptr; + void remoteStarted(const Utils::Port &debugServerPort, const QUrl &qmlServer, qint64 pid); + void remoteFinished(const QString &errString); + void remoteStdOut(const QString &output); + void remoteStdErr(const QString &output); + QPointer m_target; Utils::Port m_debugServerPort; QUrl m_qmlServer; Utils::ProcessHandle m_pid; QmlDebug::QmlOutputParser m_outputParser; - Tasking::TaskTreeRunner m_startAvdRunner; + Tasking::TaskTreeRunner m_taskTreeRunner; }; } // namespace Android::Internal diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index 4aad98a8a3c..195f906bb2d 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -131,10 +131,8 @@ static FilePath debugServer(bool useLldb, const Target *target) return {}; } -class RunnerStorage : public QObject +class RunnerStorage { - Q_OBJECT - public: QStringList selector() const { return AndroidDeviceInfo::adbSelector(m_deviceSerialNumber); } bool isPreNougat() const { return m_apiLevel > 0 && m_apiLevel <= 23; } @@ -154,6 +152,8 @@ public: return QStringList{"shell", "run-as", m_packageName} + userArgs(); } + RunnerInterface *m_glue = nullptr; + QString m_packageName; QString m_intentName; QStringList m_beforeStartAdbCommands; @@ -165,30 +165,21 @@ public: bool m_useLldb = false; QmlDebug::QmlDebugServicesPreset m_qmlDebugServices; QUrl m_qmlServer; - QString m_deviceSerialNumber; - int m_apiLevel = -1; + QString m_deviceSerialNumber; // TODO: remove + int m_apiLevel = -1; // TODO: remove QString m_extraAppParams; Utils::Environment m_extraEnvVars; Utils::FilePath m_debugServerPath; // On build device, typically as part of ndk bool m_useAppParamsForQmlDebugger = false; - -signals: - void remoteProcessStarted(Utils::Port debugServerPort, const QUrl &qmlServer, qint64 pid); - void remoteProcessFinished(const QString &errString = QString()); - - void remoteOutput(const QString &output); - void remoteErrorOutput(const QString &output); - - void cancel(); }; -static void setupStorage(RunnerStorage *storage, RunControl *runControl, - const QString &deviceSerialNumber, int apiLevel) +static void setupStorage(RunnerStorage *storage, RunnerInterface *glue) { - storage->m_useLldb = Debugger::DebuggerKitAspect::engineType(runControl->kit()) + storage->m_glue = glue; + storage->m_useLldb = Debugger::DebuggerKitAspect::engineType(glue->runControl()->kit()) == Debugger::LldbEngineType; - auto aspect = runControl->aspectData(); - const Id runMode = runControl->runMode(); + auto aspect = glue->runControl()->aspectData(); + const Id runMode = glue->runControl()->runMode(); const bool debuggingMode = runMode == ProjectExplorer::Constants::DEBUG_RUN_MODE; storage->m_useCppDebugger = debuggingMode && aspect->useCppDebugger; if (debuggingMode && aspect->useQmlDebugger) @@ -212,30 +203,30 @@ static void setupStorage(RunnerStorage *storage, RunControl *runControl, qCDebug(androidRunWorkerLog) << "QML server:" << storage->m_qmlServer.toDisplayString(); } - auto target = runControl->target(); + auto target = glue->runControl()->target(); storage->m_packageName = AndroidManager::packageName(target); storage->m_intentName = storage->m_packageName + '/' + AndroidManager::activityName(target); - storage->m_deviceSerialNumber = deviceSerialNumber; - storage->m_apiLevel = apiLevel; + storage->m_deviceSerialNumber = glue->deviceSerialNumber(); + storage->m_apiLevel = glue->apiLevel(); qCDebug(androidRunWorkerLog) << "Intent name:" << storage->m_intentName << "Package name:" << storage->m_packageName; qCDebug(androidRunWorkerLog) << "Device API:" << storage->m_apiLevel; - storage->m_extraEnvVars = runControl->aspectData()->environment; + storage->m_extraEnvVars = glue->runControl()->aspectData()->environment; qCDebug(androidRunWorkerLog).noquote() << "Environment variables for the app" << storage->m_extraEnvVars.toStringList(); if (target->buildConfigurations().first()->buildType() != BuildConfiguration::BuildType::Release) - storage->m_extraAppParams = runControl->commandLine().arguments(); + storage->m_extraAppParams = glue->runControl()->commandLine().arguments(); - if (const Store sd = runControl->settingsData(Constants::ANDROID_AM_START_ARGS); + if (const Store sd = glue->runControl()->settingsData(Constants::ANDROID_AM_START_ARGS); !sd.isEmpty()) { QTC_CHECK(sd.first().typeId() == QMetaType::QString); const QString startArgs = sd.first().toString(); storage->m_amStartExtraArgs = ProcessArgs::splitArgs(startArgs, OsTypeOtherUnix); } - if (const Store sd = runControl->settingsData(Constants::ANDROID_PRESTARTSHELLCMDLIST); + if (const Store sd = glue->runControl()->settingsData(Constants::ANDROID_PRESTARTSHELLCMDLIST); !sd.isEmpty()) { const QVariant &first = sd.first(); QTC_CHECK(first.typeId() == QMetaType::QStringList); @@ -244,7 +235,7 @@ static void setupStorage(RunnerStorage *storage, RunControl *runControl, storage->m_beforeStartAdbCommands.append(QString("shell %1").arg(shellCmd)); } - if (const Store sd = runControl->settingsData(Constants::ANDROID_POSTFINISHSHELLCMDLIST); + if (const Store sd = glue->runControl()->settingsData(Constants::ANDROID_POSTFINISHSHELLCMDLIST); !sd.isEmpty()) { const QVariant &first = sd.first(); QTC_CHECK(first.typeId() == QMetaType::QStringList); @@ -265,27 +256,7 @@ static void setupStorage(RunnerStorage *storage, RunControl *runControl, storage->m_useAppParamsForQmlDebugger = version->qtVersion() >= QVersionNumber(5, 12); } -AndroidRunnerWorker::AndroidRunnerWorker(RunControl *runControl, const QString &deviceSerialNumber, - int apiLevel) - : m_storage(new RunnerStorage) -{ - m_storage->setParent(this); // Move m_storage object together with *this into a separate thread. - setupStorage(m_storage.get(), runControl, deviceSerialNumber, apiLevel); - m_taskTreeRunner.setParent(this); // Move m_taskTreeRunner object together with *this into a separate thread. - - connect(m_storage.get(), &RunnerStorage::remoteProcessStarted, - this, &AndroidRunnerWorker::remoteProcessStarted); - connect(m_storage.get(), &RunnerStorage::remoteProcessFinished, - this, &AndroidRunnerWorker::remoteProcessFinished); - connect(m_storage.get(), &RunnerStorage::remoteOutput, - this, &AndroidRunnerWorker::remoteOutput); - connect(m_storage.get(), &RunnerStorage::remoteErrorOutput, - this, &AndroidRunnerWorker::remoteErrorOutput); - - connect(this, &AndroidRunnerWorker::cancel, m_storage.get(), &RunnerStorage::cancel); -} - -static ExecutableItem forceStopRecipe(RunnerStorage *storage) +static ExecutableItem forceStopRecipe(const Storage &storage) { const auto onForceStopSetup = [storage](Process &process) { process.setCommand(storage->adbCommand({"shell", "am", "force-stop", storage->m_packageName})); @@ -335,7 +306,7 @@ static ExecutableItem removeForwardPortRecipe(RunnerStorage *storage, const QStr process.setCommand(storage->adbCommand({"forward", "--remove", port})); }; const auto onForwardRemoveDone = [storage](const Process &process) { - emit storage->remoteErrorOutput(process.cleanedStdErr().trimmed()); + storage->m_glue->addStdErr(process.cleanedStdErr().trimmed()); return true; }; @@ -346,7 +317,7 @@ static ExecutableItem removeForwardPortRecipe(RunnerStorage *storage, const QStr if (result == DoneWith::Success) storage->m_afterFinishAdbCommands.push_back("forward --remove " + port); else - emit storage->remoteProcessFinished(Tr::tr("Failed to forward %1 debugging ports.").arg(portType)); + storage->m_glue->setFinished(Tr::tr("Failed to forward %1 debugging ports.").arg(portType)); }; return Group { @@ -359,7 +330,8 @@ static ExecutableItem removeForwardPortRecipe(RunnerStorage *storage, const QStr // The startBarrier is passed when logcat process received "Sending WAIT chunk" message. // The settledBarrier is passed when logcat process received "debugger has settled" message. -static ExecutableItem jdbRecipe(RunnerStorage *storage, const SingleBarrier &startBarrier, +static ExecutableItem jdbRecipe(const Storage &storage, + const SingleBarrier &startBarrier, const SingleBarrier &settledBarrier) { const auto onSetup = [storage] { @@ -367,9 +339,9 @@ static ExecutableItem jdbRecipe(RunnerStorage *storage, const SingleBarrier &sta }; const auto onTaskTreeSetup = [storage](TaskTree &taskTree) { - taskTree.setRecipe({ - removeForwardPortRecipe(storage, "tcp:" + s_localJdbServerPort.toString(), - "jdwp:" + QString::number(storage->m_processPID), "JDB") + taskTree.setRecipe({removeForwardPortRecipe(storage.activeStorage(), + "tcp:" + s_localJdbServerPort.toString(), + "jdwp:" + QString::number(storage->m_processPID), "JDB") }); }; @@ -403,7 +375,7 @@ static ExecutableItem jdbRecipe(RunnerStorage *storage, const SingleBarrier &sta }; } -static ExecutableItem logcatRecipe(RunnerStorage *storage) +static ExecutableItem logcatRecipe(const Storage &storage) { struct Buffer { QStringList timeArgs; @@ -424,11 +396,12 @@ static ExecutableItem logcatRecipe(RunnerStorage *storage) }; const auto onLogcatSetup = [storage, bufferStorage, startJdbBarrier, settledJdbBarrier](Process &process) { + RunnerStorage *storagePtr = storage.activeStorage(); Buffer *bufferPtr = bufferStorage.activeStorage(); - const auto parseLogcat = [storage, bufferPtr, start = startJdbBarrier->barrier(), + const auto parseLogcat = [storagePtr, bufferPtr, start = startJdbBarrier->barrier(), settled = settledJdbBarrier->barrier(), processPtr = &process]( QProcess::ProcessChannel channel) { - if (storage->m_processPID == -1) + if (storagePtr->m_processPID == -1) return; QByteArray &buffer = channel == QProcess::StandardOutput ? bufferPtr->stdOutBuffer @@ -444,13 +417,13 @@ static ExecutableItem logcatRecipe(RunnerStorage *storage) else buffer = lines.takeLast(); // incomplete line - const QString pidString = QString::number(storage->m_processPID); + const QString pidString = QString::number(storagePtr->m_processPID); for (const QByteArray &msg : std::as_const(lines)) { const QString line = QString::fromUtf8(msg).trimmed() + QLatin1Char('\n'); if (!line.contains(pidString)) continue; - if (storage->m_useCppDebugger) { + if (storagePtr->m_useCppDebugger) { if (start->current() == 0 && msg.trimmed().endsWith("Sending WAIT chunk")) start->advance(); else if (settled->current() == 0 && msg.indexOf("debugger has settled") > 0) @@ -481,16 +454,16 @@ static ExecutableItem logcatRecipe(RunnerStorage *storage) const QString msgType = match.captured(2); const QString output = line.mid(match.capturedStart(2)); if (onlyError || msgType == "F" || msgType == "E" || msgType == "W") - emit storage->remoteErrorOutput(output); + storagePtr->m_glue->addStdErr(output); else - emit storage->remoteOutput(output); + storagePtr->m_glue->addStdOut(output); } } else { if (onlyError || line.startsWith("F/") || line.startsWith("E/") || line.startsWith("W/")) { - emit storage->remoteErrorOutput(line); + storagePtr->m_glue->addStdErr(line); } else { - emit storage->remoteOutput(line); + storagePtr->m_glue->addStdOut(line); } } } @@ -517,12 +490,12 @@ static ExecutableItem logcatRecipe(RunnerStorage *storage) }; } -static ExecutableItem preStartRecipe(RunnerStorage *storage) +static ExecutableItem preStartRecipe(const Storage &storage) { - const QString port = "tcp:" + QString::number(storage->m_qmlServer.port()); - const Storage argsStorage; - const LoopList iterator(storage->m_beforeStartAdbCommands); + const LoopUntil iterator([storage](int iteration) { + return iteration < storage->m_beforeStartAdbCommands.size(); + }); const auto onArgsSetup = [storage, argsStorage] { *argsStorage = {"shell", "am", "start", "-n", storage->m_intentName}; @@ -531,15 +504,20 @@ static ExecutableItem preStartRecipe(RunnerStorage *storage) }; const auto onPreCommandSetup = [storage, iterator](Process &process) { - process.setCommand(storage->adbCommand({iterator->split(' ', Qt::SkipEmptyParts)})); + process.setCommand(storage->adbCommand( + {storage->m_beforeStartAdbCommands.at(iterator.iteration()).split(' ', Qt::SkipEmptyParts)})); }; const auto onPreCommandDone = [storage](const Process &process) { - emit storage->remoteErrorOutput(process.cleanedStdErr().trimmed()); + storage->m_glue->addStdErr(process.cleanedStdErr().trimmed()); }; const auto onQmlDebugSetup = [storage] { - return storage->m_qmlDebugServices == QmlDebug::NoQmlDebugServices ? SetupResult::StopWithSuccess - : SetupResult::Continue; + return storage->m_qmlDebugServices == QmlDebug::NoQmlDebugServices + ? SetupResult::StopWithSuccess : SetupResult::Continue; + }; + const auto onTaskTreeSetup = [storage](TaskTree &taskTree) { + const QString port = "tcp:" + QString::number(storage->m_qmlServer.port()); + taskTree.setRecipe({removeForwardPortRecipe(storage.activeStorage(), port, port, "QML")}); }; const auto onQmlDebugDone = [storage, argsStorage] { const QString qmljsdebugger = QString("port:%1,block,services:%2") @@ -575,8 +553,8 @@ static ExecutableItem preStartRecipe(RunnerStorage *storage) process.setCommand(storage->adbCommand({args})); }; const auto onActivityDone = [storage](const Process &process) { - emit storage->remoteProcessFinished(Tr::tr("Activity Manager error: %1") - .arg(process.cleanedStdErr().trimmed())); + storage->m_glue->setFinished( + Tr::tr("Activity Manager error: %1").arg(process.cleanedStdErr().trimmed())); }; return Group { @@ -587,14 +565,14 @@ static ExecutableItem preStartRecipe(RunnerStorage *storage) }, Group { onGroupSetup(onQmlDebugSetup), - removeForwardPortRecipe(storage, port, port, "QML"), + TaskTreeTask(onTaskTreeSetup), onGroupDone(onQmlDebugDone, CallDoneIf::Success) }, ProcessTask(onActivitySetup, onActivityDone, CallDoneIf::Error) }; } -static ExecutableItem postDoneRecipe(RunnerStorage *storage) +static ExecutableItem postDoneRecipe(const Storage &storage) { const LoopUntil iterator([storage](int iteration) { return iteration < storage->m_afterFinishAdbCommands.size(); @@ -608,7 +586,7 @@ static ExecutableItem postDoneRecipe(RunnerStorage *storage) const auto onDone = [storage] { storage->m_processPID = -1; storage->m_processUser = -1; - emit storage->remoteProcessFinished("\n\n" + Tr::tr("\"%1\" died.").arg(storage->m_packageName)); + storage->m_glue->setFinished("\n\n" + Tr::tr("\"%1\" died.").arg(storage->m_packageName)); }; return Group { @@ -626,7 +604,8 @@ static QString tempDebugServerPath(int count) return tempDebugServerPathTemplate.arg(count); } -static ExecutableItem uploadDebugServerRecipe(RunnerStorage *storage, const QString &debugServerFileName) +static ExecutableItem uploadDebugServerRecipe(const Storage &storage, + const QString &debugServerFileName) { const Storage tempDebugServerPathStorage; const LoopUntil iterator([tempDebugServerPathStorage](int iteration) { @@ -645,8 +624,8 @@ static ExecutableItem uploadDebugServerRecipe(RunnerStorage *storage, const QStr const auto onTempDebugServerPath = [storage, tempDebugServerPathStorage] { const bool tempDirOK = !tempDebugServerPathStorage->isEmpty(); if (tempDirOK) { - emit storage->remoteProcessStarted(s_localDebugServerPort, storage->m_qmlServer, - storage->m_processPID); + storage->m_glue->setStarted(s_localDebugServerPort, storage->m_qmlServer, + storage->m_processPID); } else { qCDebug(androidRunWorkerLog) << "Can not get temporary file name"; } @@ -693,7 +672,7 @@ static ExecutableItem uploadDebugServerRecipe(RunnerStorage *storage, const QStr }; } -static ExecutableItem startNativeDebuggingRecipe(RunnerStorage *storage) +static ExecutableItem startNativeDebuggingRecipe(const Storage &storage) { const auto onSetup = [storage] { return storage->m_useCppDebugger ? SetupResult::Continue : SetupResult::StopWithSuccess; @@ -709,7 +688,7 @@ static ExecutableItem startNativeDebuggingRecipe(RunnerStorage *storage) if (result == DoneWith::Success) *packageDirStorage = process.stdOut(); else - emit storage->remoteProcessFinished(Tr::tr("Failed to find application directory.")); + storage->m_glue->setFinished(Tr::tr("Failed to find application directory.")); }; // Add executable flag to package dir. Gdb can't connect to running server on device on @@ -723,7 +702,7 @@ static ExecutableItem startNativeDebuggingRecipe(RunnerStorage *storage) QString msg = Tr::tr("Cannot find C++ debug server in NDK installation."); if (storage->m_useLldb) msg += "\n" + Tr::tr("The lldb-server binary has not been found."); - emit storage->remoteProcessFinished(msg); + storage->m_glue->setFinished(msg); return false; }; @@ -742,7 +721,7 @@ static ExecutableItem startNativeDebuggingRecipe(RunnerStorage *storage) setDebugServer(debugServerFileName) } >> Else { Sync([storage] { - emit storage->remoteProcessFinished(Tr::tr("Cannot copy C++ debug server.")); + storage->m_glue->setFinished(Tr::tr("Cannot copy C++ debug server.")); return false; }) }; @@ -776,7 +755,8 @@ static ExecutableItem startNativeDebuggingRecipe(RunnerStorage *storage) const auto onTaskTreeSetup = [storage, packageDirStorage](TaskTree &taskTree) { const QString gdbServerSocket = *packageDirStorage + "/debug-socket"; - taskTree.setRecipe({removeForwardPortRecipe(storage, "tcp:" + s_localDebugServerPort.toString(), + taskTree.setRecipe({removeForwardPortRecipe(storage.activeStorage(), + "tcp:" + s_localDebugServerPort.toString(), "localfilesystem:" + gdbServerSocket, "C++")}); }; @@ -813,13 +793,12 @@ static ExecutableItem startNativeDebuggingRecipe(RunnerStorage *storage) }; } -static ExecutableItem pidRecipe(RunnerStorage *storage) +static ExecutableItem pidRecipe(const Storage &storage) { - const QString pidScript = storage->isPreNougat() - ? QString("for p in /proc/[0-9]*; do cat <$p/cmdline && echo :${p##*/}; done") - : QString("pidof -s '%1'").arg(storage->m_packageName); - - const auto onPidSetup = [storage, pidScript](Process &process) { + const auto onPidSetup = [storage](Process &process) { + const QString pidScript = storage->isPreNougat() + ? QString("for p in /proc/[0-9]*; do cat <$p/cmdline && echo :${p##*/}; done") + : QString("pidof -s '%1'").arg(storage->m_packageName); process.setCommand(storage->adbCommand({"shell", pidScript})); }; const auto onPidDone = [storage](const Process &process) { @@ -848,8 +827,8 @@ static ExecutableItem pidRecipe(RunnerStorage *storage) storage->m_processUser = processUser; qCDebug(androidRunWorkerLog) << "Process ID changed to:" << storage->m_processPID; if (!storage->m_useCppDebugger) { - emit storage->remoteProcessStarted(s_localDebugServerPort, storage->m_qmlServer, - storage->m_processPID); + storage->m_glue->setStarted(s_localDebugServerPort, storage->m_qmlServer, + storage->m_processPID); } return DoneResult::Success; } @@ -890,42 +869,41 @@ static ExecutableItem pidRecipe(RunnerStorage *storage) }; } -AndroidRunnerWorker::~AndroidRunnerWorker() +void RunnerInterface::setStarted(const Utils::Port &debugServerPort, const QUrl &qmlServer, + qint64 pid) { - if (m_storage->m_processPID != -1) - TaskTree::runBlocking(Group { forceStopRecipe(m_storage.get()), postDoneRecipe(m_storage.get()) }); + emit started(debugServerPort, qmlServer, pid); } -void AndroidRunnerWorker::asyncStart() +ExecutableItem runnerRecipe(const Storage &glueStorage) { - // TODO: Instead of asyncStop recipe, add a barrier storage. - const Group recipe { + const Storage storage; + + const auto onSetup = [glueStorage, storage] { + setupStorage(storage.activeStorage(), glueStorage.activeStorage()); + }; + + return Group { finishAllAndSuccess, + storage, + onGroupSetup(onSetup), Group { - forceStopRecipe(m_storage.get()), + forceStopRecipe(storage), Group { parallel, stopOnSuccessOrError, - logcatRecipe(m_storage.get()), + logcatRecipe(storage), Group { - preStartRecipe(m_storage.get()), - pidRecipe(m_storage.get()) + preStartRecipe(storage), + pidRecipe(storage) } } - }.withCancel([storage = m_storage.get()] { - return std::make_pair(storage, &RunnerStorage::cancel); + }.withCancel([glueStorage] { + return std::make_pair(glueStorage.activeStorage(), &RunnerInterface::canceled); }), - forceStopRecipe(m_storage.get()), - postDoneRecipe(m_storage.get()) + forceStopRecipe(storage), + postDoneRecipe(storage) }; - m_taskTreeRunner.start(recipe); -} - -void AndroidRunnerWorker::asyncStop() -{ - emit cancel(); } } // namespace Android::Internal - -#include "androidrunnerworker.moc" diff --git a/src/plugins/android/androidrunnerworker.h b/src/plugins/android/androidrunnerworker.h index 2f4089fdb95..4293821f50d 100644 --- a/src/plugins/android/androidrunnerworker.h +++ b/src/plugins/android/androidrunnerworker.h @@ -8,34 +8,52 @@ namespace ProjectExplorer { class RunControl; } namespace Utils { class Port; } +QT_BEGIN_NAMESPACE +class QUrl; +QT_END_NAMESPACE + namespace Android::Internal { -class RunnerStorage; - -class AndroidRunnerWorker : public QObject +class RunnerInterface : public QObject { Q_OBJECT public: - AndroidRunnerWorker(ProjectExplorer::RunControl *runControl, const QString &deviceSerialNumber, - int apiLevel); - ~AndroidRunnerWorker() override; + // Gui init setters + void setRunControl(ProjectExplorer::RunControl *runControl) { m_runControl = runControl; } + void setDeviceSerialNumber(const QString &deviceSerialNumber) { m_deviceSerialNumber = deviceSerialNumber; } + void setApiLevel(int apiLevel) { m_apiLevel = apiLevel; } - void asyncStart(); - void asyncStop(); + // business logic init getters + ProjectExplorer::RunControl *runControl() const { return m_runControl; } + QString deviceSerialNumber() const { return m_deviceSerialNumber; } + int apiLevel() const { return m_apiLevel; } + + // GUI -> business logic + void cancel() { emit canceled(); } + + // business logic -> GUI + void setStarted(const Utils::Port &debugServerPort, const QUrl &qmlServer, qint64 pid); + void setFinished(const QString &errorMessage) { emit finished(errorMessage); } + void addStdOut(const QString &data) { emit stdOut(data); } + void addStdErr(const QString &data) { emit stdErr(data); } signals: - void remoteProcessStarted(const Utils::Port &debugServerPort, const QUrl &qmlServer, qint64 pid); - void remoteProcessFinished(const QString &errString = QString()); + // GUI -> business logic + void canceled(); - void remoteOutput(const QString &output); - void remoteErrorOutput(const QString &output); - - void cancel(); + // business logic -> GUI + void started(const Utils::Port &debugServerPort, const QUrl &qmlServer, qint64 pid); + void finished(const QString &errorMessage); + void stdOut(const QString &data); + void stdErr(const QString &data); private: - std::unique_ptr m_storage; - Tasking::TaskTreeRunner m_taskTreeRunner; + ProjectExplorer::RunControl *m_runControl = nullptr; + QString m_deviceSerialNumber; + int m_apiLevel = -1; }; +Tasking::ExecutableItem runnerRecipe(const Tasking::Storage &storage); + } // namespace Android::Internal