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.
|
// 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
|
|
||||||
|
@@ -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
|
|
||||||
|
Reference in New Issue
Block a user