Android: Reuse task tree for AndroidSignalOperation

Change-Id: I771be32bdc2456e04791be1d9f10bd979209b703
Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
This commit is contained in:
Jarek Kobus
2024-09-20 12:37:04 +02:00
parent bb44a7b3d5
commit 1338c8ef6b
2 changed files with 61 additions and 112 deletions

View File

@@ -1,99 +1,73 @@
// Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "androidconfigurations.h"
#include "androidsignaloperation.h" #include "androidsignaloperation.h"
#include "androidconfigurations.h"
#include <utils/qtcprocess.h> #include <utils/qtcprocess.h>
#include <utils/qtcassert.h>
using namespace Tasking;
using namespace Utils; using namespace Utils;
using namespace std::chrono_literals;
namespace Android { namespace Android::Internal {
namespace Internal {
AndroidSignalOperation::AndroidSignalOperation() AndroidSignalOperation::AndroidSignalOperation() = default;
: m_adbPath(AndroidConfig::adbToolPath())
, m_timeout(new QTimer(this))
{
m_timeout->setInterval(5000);
connect(m_timeout, &QTimer::timeout, this, &AndroidSignalOperation::handleTimeout);
}
AndroidSignalOperation::~AndroidSignalOperation() = default;
bool AndroidSignalOperation::handleCrashMessage()
{
if (m_adbProcess->exitStatus() == QProcess::NormalExit)
return false;
m_errorMessage = QLatin1String(" adb process exit code: ") + QString::number(m_adbProcess->exitCode());
const QString adbError = m_adbProcess->errorString();
if (!adbError.isEmpty())
m_errorMessage += QLatin1String(" adb process error: ") + adbError;
return true;
}
void AndroidSignalOperation::adbFindRunAsFinished()
{
QTC_ASSERT(m_state == RunAs, return);
m_timeout->stop();
handleCrashMessage();
const QString runAs = QString::fromLatin1(m_adbProcess->readAllRawStandardOutput());
m_adbProcess.release()->deleteLater();
if (runAs.isEmpty() || !m_errorMessage.isEmpty()) {
m_errorMessage.prepend(QLatin1String("Cannot find User for process: ")
+ QString::number(m_pid));
m_state = Idle;
emit finished(m_errorMessage);
} else {
startAdbProcess(Kill, {m_adbPath, {"shell", "run-as", runAs, "kill",
QString("-%1").arg(m_signal), QString::number(m_pid)}},
[this] { adbKillFinished(); });
}
}
void AndroidSignalOperation::adbKillFinished()
{
QTC_ASSERT(m_state == Kill, return);
m_timeout->stop();
if (!handleCrashMessage())
m_errorMessage = QString::fromLatin1(m_adbProcess->readAllRawStandardError());
m_adbProcess.release()->deleteLater();
if (!m_errorMessage.isEmpty())
m_errorMessage.prepend(QLatin1String("Cannot kill process: ") + QString::number(m_pid));
m_state = Idle;
emit finished(m_errorMessage);
}
void AndroidSignalOperation::handleTimeout()
{
m_adbProcess.reset();
m_timeout->stop();
m_state = Idle;
m_errorMessage = QLatin1String("adb process timed out");
emit finished(m_errorMessage);
}
void AndroidSignalOperation::signalOperationViaADB(qint64 pid, int signal) void AndroidSignalOperation::signalOperationViaADB(qint64 pid, int signal)
{ {
QTC_ASSERT(m_state == Idle, return); struct InternalStorage {
m_pid = pid; FilePath adbPath;
m_signal = signal; QString runAs = {};
startAdbProcess(RunAs, {m_adbPath, {"shell", "cat", QString("/proc/%1/cmdline").arg(m_pid)}}, QString errorMessage = {};
[this] { adbFindRunAsFinished(); }); };
}
void AndroidSignalOperation::startAdbProcess(State state, const Utils::CommandLine &commandLine, const Storage<InternalStorage> storage({AndroidConfig::adbToolPath()});
FinishHandler handler)
{ const auto onCatSetup = [storage, pid](Process &process) {
m_state = state; process.setCommand({storage->adbPath, {"shell", "cat", QString("/proc/%1/cmdline").arg(pid)}});
m_timeout->start(); };
m_adbProcess.reset(new Process); const auto onCatDone = [storage, pid](const Process &process, DoneWith result) {
connect(m_adbProcess.get(), &Process::done, this, handler); if (result == DoneWith::Success) {
m_adbProcess->setCommand(commandLine); storage->runAs = process.stdOut();
m_adbProcess->start(); if (!storage->runAs.isEmpty())
return true;
storage->errorMessage = QLatin1String("Cannot find User for process: ")
+ QString::number(pid);
} else if (result == DoneWith::Error) {
storage->errorMessage = QLatin1String(" adb process exit code: ")
+ QString::number(process.exitCode());
const QString adbError = process.errorString();
if (!adbError.isEmpty())
storage->errorMessage += QLatin1String(" adb process error: ") + adbError;
} else {
storage->errorMessage = QLatin1String("adb process timed out");
}
return false;
};
const auto onKillSetup = [storage, pid, signal](Process &process) {
process.setCommand({storage->adbPath, {"shell", "run-as", storage->runAs, "kill",
QString("-%1").arg(signal), QString::number(pid)}});
};
const auto onKillDone = [storage, pid](const Process &process, DoneWith result) {
if (result == DoneWith::Error) {
storage->errorMessage = QLatin1String("Cannot kill process: ") + QString::number(pid)
+ process.stdErr();
} else if (result == DoneWith::Cancel) {
storage->errorMessage = QLatin1String("adb process timed out");
}
};
const auto onDone = [this, storage] { emit finished(storage->errorMessage); };
const Group recipe {
ProcessTask(onCatSetup, onCatDone).withTimeout(5s),
ProcessTask(onKillSetup, onKillDone).withTimeout(5s),
onGroupDone(onDone)
};
m_taskTreeRunner.start(recipe);
} }
void AndroidSignalOperation::killProcess(qint64 pid) void AndroidSignalOperation::killProcess(qint64 pid)
@@ -114,5 +88,4 @@ void AndroidSignalOperation::interruptProcess(qint64 pid)
signalOperationViaADB(pid, 2); signalOperationViaADB(pid, 2);
} }
} // Internal } // namespace Android::Internal
} // Android

View File

@@ -5,16 +5,13 @@
#include <projectexplorer/devicesupport/idevice.h> #include <projectexplorer/devicesupport/idevice.h>
#include <QObject> #include <solutions/tasking/tasktreerunner.h>
#include <QTimer>
namespace Android { namespace Android::Internal {
namespace Internal {
class AndroidSignalOperation : public ProjectExplorer::DeviceProcessSignalOperation class AndroidSignalOperation : public ProjectExplorer::DeviceProcessSignalOperation
{ {
public: public:
~AndroidSignalOperation() override;
void killProcess(qint64 pid) override; void killProcess(qint64 pid) override;
void killProcess(const QString &filePath) override; void killProcess(const QString &filePath) override;
void interruptProcess(qint64 pid) override; void interruptProcess(qint64 pid) override;
@@ -23,32 +20,11 @@ protected:
explicit AndroidSignalOperation(); explicit AndroidSignalOperation();
private: private:
enum State {
Idle,
RunAs,
Kill
};
using FinishHandler = std::function<void()>;
bool handleCrashMessage();
void adbFindRunAsFinished();
void adbKillFinished();
void handleTimeout();
void signalOperationViaADB(qint64 pid, int signal); void signalOperationViaADB(qint64 pid, int signal);
void startAdbProcess(State state, const Utils::CommandLine &commandLine, FinishHandler handler);
Utils::FilePath m_adbPath; Tasking::TaskTreeRunner m_taskTreeRunner;
std::unique_ptr<Utils::Process> m_adbProcess;
QTimer *m_timeout;
State m_state = Idle;
qint64 m_pid = 0;
int m_signal = 0;
friend class AndroidDevice; friend class AndroidDevice;
}; };
} // namespace Internal } // namespace Android::Internal
} // namespace Android