forked from qt-creator/qt-creator
Android: Reuse task tree for AndroidSignalOperation
Change-Id: I771be32bdc2456e04791be1d9f10bd979209b703 Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
This commit is contained in:
@@ -1,99 +1,73 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "androidconfigurations.h"
|
||||
#include "androidsignaloperation.h"
|
||||
|
||||
#include "androidconfigurations.h"
|
||||
|
||||
#include <utils/qtcprocess.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
using namespace Tasking;
|
||||
using namespace Utils;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
namespace Android {
|
||||
namespace Internal {
|
||||
namespace Android::Internal {
|
||||
|
||||
AndroidSignalOperation::AndroidSignalOperation()
|
||||
: 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);
|
||||
}
|
||||
AndroidSignalOperation::AndroidSignalOperation() = default;
|
||||
|
||||
void AndroidSignalOperation::signalOperationViaADB(qint64 pid, int signal)
|
||||
{
|
||||
QTC_ASSERT(m_state == Idle, return);
|
||||
m_pid = pid;
|
||||
m_signal = signal;
|
||||
startAdbProcess(RunAs, {m_adbPath, {"shell", "cat", QString("/proc/%1/cmdline").arg(m_pid)}},
|
||||
[this] { adbFindRunAsFinished(); });
|
||||
}
|
||||
struct InternalStorage {
|
||||
FilePath adbPath;
|
||||
QString runAs = {};
|
||||
QString errorMessage = {};
|
||||
};
|
||||
|
||||
void AndroidSignalOperation::startAdbProcess(State state, const Utils::CommandLine &commandLine,
|
||||
FinishHandler handler)
|
||||
{
|
||||
m_state = state;
|
||||
m_timeout->start();
|
||||
m_adbProcess.reset(new Process);
|
||||
connect(m_adbProcess.get(), &Process::done, this, handler);
|
||||
m_adbProcess->setCommand(commandLine);
|
||||
m_adbProcess->start();
|
||||
const Storage<InternalStorage> storage({AndroidConfig::adbToolPath()});
|
||||
|
||||
const auto onCatSetup = [storage, pid](Process &process) {
|
||||
process.setCommand({storage->adbPath, {"shell", "cat", QString("/proc/%1/cmdline").arg(pid)}});
|
||||
};
|
||||
const auto onCatDone = [storage, pid](const Process &process, DoneWith result) {
|
||||
if (result == DoneWith::Success) {
|
||||
storage->runAs = process.stdOut();
|
||||
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)
|
||||
@@ -114,5 +88,4 @@ void AndroidSignalOperation::interruptProcess(qint64 pid)
|
||||
signalOperationViaADB(pid, 2);
|
||||
}
|
||||
|
||||
} // Internal
|
||||
} // Android
|
||||
} // namespace Android::Internal
|
||||
|
@@ -5,16 +5,13 @@
|
||||
|
||||
#include <projectexplorer/devicesupport/idevice.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
#include <solutions/tasking/tasktreerunner.h>
|
||||
|
||||
namespace Android {
|
||||
namespace Internal {
|
||||
namespace Android::Internal {
|
||||
|
||||
class AndroidSignalOperation : public ProjectExplorer::DeviceProcessSignalOperation
|
||||
{
|
||||
public:
|
||||
~AndroidSignalOperation() override;
|
||||
void killProcess(qint64 pid) override;
|
||||
void killProcess(const QString &filePath) override;
|
||||
void interruptProcess(qint64 pid) override;
|
||||
@@ -23,32 +20,11 @@ protected:
|
||||
explicit AndroidSignalOperation();
|
||||
|
||||
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 startAdbProcess(State state, const Utils::CommandLine &commandLine, FinishHandler handler);
|
||||
|
||||
Utils::FilePath m_adbPath;
|
||||
std::unique_ptr<Utils::Process> m_adbProcess;
|
||||
QTimer *m_timeout;
|
||||
|
||||
State m_state = Idle;
|
||||
qint64 m_pid = 0;
|
||||
int m_signal = 0;
|
||||
Tasking::TaskTreeRunner m_taskTreeRunner;
|
||||
|
||||
friend class AndroidDevice;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Android
|
||||
} // namespace Android::Internal
|
||||
|
Reference in New Issue
Block a user