forked from qt-creator/qt-creator
Android: Move the AndroidRunnerWorker to the main thread
Replace AndroidRunnerWorker with runnerRecipe(). Add RunnerInterface for communication between AndroidRunner and runnerRecipe(). Get rid of a separate thread. Change-Id: I32a651592859b762b0e52a2d44c28652d42566bb Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
This commit is contained in:
@@ -44,14 +44,12 @@ AndroidRunner::AndroidRunner(RunControl *runControl)
|
||||
this, &AndroidRunner::qmlServerPortReady);
|
||||
}
|
||||
|
||||
AndroidRunner::~AndroidRunner()
|
||||
{
|
||||
m_thread.quit();
|
||||
m_thread.wait();
|
||||
}
|
||||
|
||||
void AndroidRunner::start()
|
||||
{
|
||||
const Storage<RunnerInterface> glueStorage;
|
||||
|
||||
std::optional<ExecutableItem> avdRecipe;
|
||||
|
||||
QString deviceSerialNumber;
|
||||
int apiLevel = -1;
|
||||
|
||||
@@ -69,56 +67,49 @@ void AndroidRunner::start()
|
||||
if (!info.avdName.isEmpty()) {
|
||||
const Storage<QString> 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();
|
||||
if (!m_taskTreeRunner.isRunning())
|
||||
return;
|
||||
|
||||
emit canceled();
|
||||
appendMessage("\n\n" + Tr::tr("\"%1\" terminated.").arg(AndroidManager::packageName(m_target)),
|
||||
Utils::NormalMessageFormat);
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
|
@@ -12,19 +12,14 @@
|
||||
|
||||
#include <solutions/tasking/tasktreerunner.h>
|
||||
|
||||
#include <QThread>
|
||||
|
||||
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<ProjectExplorer::Target> 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
|
||||
|
@@ -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<Debugger::DebuggerRunConfigurationAspect>();
|
||||
const Id runMode = runControl->runMode();
|
||||
auto aspect = glue->runControl()->aspectData<Debugger::DebuggerRunConfigurationAspect>();
|
||||
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<EnvironmentAspect>()->environment;
|
||||
storage->m_extraEnvVars = glue->runControl()->aspectData<EnvironmentAspect>()->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<RunnerStorage> &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<RunnerStorage> &storage,
|
||||
const SingleBarrier &startBarrier,
|
||||
const SingleBarrier &settledBarrier)
|
||||
{
|
||||
const auto onSetup = [storage] {
|
||||
@@ -367,8 +339,8 @@ static ExecutableItem jdbRecipe(RunnerStorage *storage, const SingleBarrier &sta
|
||||
};
|
||||
|
||||
const auto onTaskTreeSetup = [storage](TaskTree &taskTree) {
|
||||
taskTree.setRecipe({
|
||||
removeForwardPortRecipe(storage, "tcp:" + s_localJdbServerPort.toString(),
|
||||
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<RunnerStorage> &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<RunnerStorage> &storage)
|
||||
{
|
||||
const QString port = "tcp:" + QString::number(storage->m_qmlServer.port());
|
||||
|
||||
const Storage<QStringList> 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<RunnerStorage> &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<RunnerStorage> &storage,
|
||||
const QString &debugServerFileName)
|
||||
{
|
||||
const Storage<QString> tempDebugServerPathStorage;
|
||||
const LoopUntil iterator([tempDebugServerPathStorage](int iteration) {
|
||||
@@ -645,7 +624,7 @@ 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_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<RunnerStorage> &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<RunnerStorage> &storage)
|
||||
{
|
||||
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);
|
||||
|
||||
const auto onPidSetup = [storage, pidScript](Process &process) {
|
||||
process.setCommand(storage->adbCommand({"shell", pidScript}));
|
||||
};
|
||||
const auto onPidDone = [storage](const Process &process) {
|
||||
@@ -848,7 +827,7 @@ 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_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<RunnerInterface> &glueStorage)
|
||||
{
|
||||
// TODO: Instead of asyncStop recipe, add a barrier storage.
|
||||
const Group recipe {
|
||||
const Storage<RunnerStorage> 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"
|
||||
|
@@ -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<RunnerStorage> m_storage;
|
||||
Tasking::TaskTreeRunner m_taskTreeRunner;
|
||||
ProjectExplorer::RunControl *m_runControl = nullptr;
|
||||
QString m_deviceSerialNumber;
|
||||
int m_apiLevel = -1;
|
||||
};
|
||||
|
||||
Tasking::ExecutableItem runnerRecipe(const Tasking::Storage<RunnerInterface> &storage);
|
||||
|
||||
} // namespace Android::Internal
|
||||
|
Reference in New Issue
Block a user