IosDeviceToolHandlerPrivate: Replace QProcess with Process

The Process takes care of the proper destruction automatically.
This is a preparation step before creating a task tree adapter
for IosToolHandler.

Change-Id: I6a8ae12b46a83be3a7074d0a268a598c260a66b5
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
Jarek Kobus
2023-07-13 11:19:23 +02:00
parent af5a8fe80c
commit a9663d65ad
2 changed files with 54 additions and 107 deletions

View File

@@ -261,8 +261,8 @@ void IosDeployStep::checkProvisioningProfile()
} }
m_expectFail = true; m_expectFail = true;
QString provisioningProfile = provisionPlist.value(QLatin1String("Name")).toString(); const QString provisioningProfile = provisionPlist.value(QLatin1String("Name")).toString();
QString provisioningUid = provisionPlist.value(QLatin1String("UUID")).toString(); const QString provisioningUid = provisionPlist.value(QLatin1String("UUID")).toString();
CompileTask task(Task::Warning, CompileTask task(Task::Warning,
Tr::tr("The provisioning profile \"%1\" (%2) used to sign the application " Tr::tr("The provisioning profile \"%1\" (%2) used to sign the application "
"does not cover the device %3 (%4). Deployment to it will fail.") "does not cover the device %3 (%4). Deployment to it will fail.")

View File

@@ -13,26 +13,14 @@
#include <debugger/debuggerconstants.h> #include <debugger/debuggerconstants.h>
#include <utils/async.h> #include <utils/async.h>
#include <utils/filepath.h>
#include <utils/futuresynchronizer.h> #include <utils/futuresynchronizer.h>
#include <utils/process.h> #include <utils/process.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/temporarydirectory.h> #include <utils/temporarydirectory.h>
#include <QDir> #include <QDir>
#include <QFutureWatcher>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QList>
#include <QLoggingCategory> #include <QLoggingCategory>
#include <QPointer>
#include <QProcess>
#include <QProcessEnvironment>
#include <QScopedArrayPointer>
#include <QSocketNotifier>
#include <QTemporaryFile> #include <QTemporaryFile>
#include <QTimer>
#include <QXmlStreamReader> #include <QXmlStreamReader>
#include <signal.h> #include <signal.h>
@@ -216,7 +204,6 @@ class IosDeviceToolHandlerPrivate final : public IosToolHandlerPrivate
}; };
public: public:
explicit IosDeviceToolHandlerPrivate(const IosDeviceType &devType, IosToolHandler *q); explicit IosDeviceToolHandlerPrivate(const IosDeviceType &devType, IosToolHandler *q);
~IosDeviceToolHandlerPrivate() override;
// IosToolHandlerPrivate overrides // IosToolHandlerPrivate overrides
public: public:
@@ -231,14 +218,20 @@ public:
void stop(int errorCode) override; void stop(int errorCode) override;
private: private:
void subprocessError(QProcess::ProcessError error);
void subprocessFinished(int exitCode, QProcess::ExitStatus exitStatus);
void subprocessHasData(); void subprocessHasData();
void processXml(); void processXml();
void killProcess();
QTimer killTimer; struct Deleter {
std::shared_ptr<QProcess> process; void operator()(Process *process) const
{
if (process->state() != QProcess::NotRunning) {
process->write("k\n\r");
process->closeWriteChannel();
}
delete process;
};
};
std::unique_ptr<Process, Deleter> process;
State state = NonStarted; State state = NonStarted;
Op op = OpNone; Op op = OpNone;
QXmlStreamReader outputParser; QXmlStreamReader outputParser;
@@ -305,7 +298,7 @@ private:
private: private:
qint64 m_pid = -1; qint64 m_pid = -1;
LogTailFiles outputLogger; LogTailFiles outputLogger;
Utils::FutureSynchronizer futureSynchronizer; FutureSynchronizer futureSynchronizer;
}; };
IosToolHandlerPrivate::IosToolHandlerPrivate(const IosDeviceType &devType, IosToolHandlerPrivate::IosToolHandlerPrivate(const IosDeviceType &devType,
@@ -369,25 +362,6 @@ void IosToolHandlerPrivate::toolExited(int code)
emit q->toolExited(q, code); emit q->toolExited(q, code);
} }
void IosDeviceToolHandlerPrivate::subprocessError(QProcess::ProcessError error)
{
if (state != Stopped)
errorMsg(Tr::tr("iOS tool error %1").arg(error));
stop(-1);
if (error == QProcess::FailedToStart) {
qCDebug(toolHandlerLog) << "IosToolHandler::finished(" << this << ")";
emit q->finished(q);
}
}
void IosDeviceToolHandlerPrivate::subprocessFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
stop((exitStatus == QProcess::NormalExit) ? exitCode : -1 );
qCDebug(toolHandlerLog) << "IosToolHandler::finished(" << this << ")";
killTimer.stop();
emit q->finished(q);
}
void IosDeviceToolHandlerPrivate::processXml() void IosDeviceToolHandlerPrivate::processXml()
{ {
while (!outputParser.atEnd()) { while (!outputParser.atEnd()) {
@@ -475,9 +449,9 @@ void IosDeviceToolHandlerPrivate::processXml()
} else if (elName == QLatin1String("server_ports")) { } else if (elName == QLatin1String("server_ports")) {
stack.append(ParserState(ParserState::ServerPorts)); stack.append(ParserState(ParserState::ServerPorts));
QXmlStreamAttributes attributes = outputParser.attributes(); QXmlStreamAttributes attributes = outputParser.attributes();
Utils::Port gdbServerPort( Port gdbServerPort(
attributes.value(QLatin1String("gdb_server")).toString().toInt()); attributes.value(QLatin1String("gdb_server")).toString().toInt());
Utils::Port qmlServerPort( Port qmlServerPort(
attributes.value(QLatin1String("qml_server")).toString().toInt()); attributes.value(QLatin1String("qml_server")).toString().toInt());
gotServerPorts(m_bundlePath, m_deviceId, gdbServerPort, qmlServerPort); gotServerPorts(m_bundlePath, m_deviceId, gdbServerPort, qmlServerPort);
} else { } else {
@@ -570,12 +544,6 @@ void IosDeviceToolHandlerPrivate::processXml()
} }
} }
void IosDeviceToolHandlerPrivate::killProcess()
{
if (isRunning())
process->kill();
}
void IosDeviceToolHandlerPrivate::subprocessHasData() void IosDeviceToolHandlerPrivate::subprocessHasData()
{ {
qCDebug(toolHandlerLog) << "subprocessHasData, state:" << state; qCDebug(toolHandlerLog) << "subprocessHasData, state:" << state;
@@ -588,17 +556,12 @@ void IosDeviceToolHandlerPrivate::subprocessHasData()
case StartedInferior: case StartedInferior:
// read some data // read some data
{ {
char buf[200];
while (isRunning()) { while (isRunning()) {
qint64 rRead = process->read(buf, sizeof(buf)); const QByteArray buffer = process->readAllRawStandardOutput();
if (rRead == -1) { if (buffer.isEmpty())
stop(-1);
return; return;
} qCDebug(toolHandlerLog) << "subprocessHasData read " << buffer;
if (rRead == 0) outputParser.addData(buffer);
return;
qCDebug(toolHandlerLog) << "subprocessHasData read " << QByteArray(buf, rRead);
outputParser.addData(QByteArray(buf, rRead));
processXml(); processXml();
} }
break; break;
@@ -617,27 +580,18 @@ void IosDeviceToolHandlerPrivate::subprocessHasData()
IosDeviceToolHandlerPrivate::IosDeviceToolHandlerPrivate(const IosDeviceType &devType, IosDeviceToolHandlerPrivate::IosDeviceToolHandlerPrivate(const IosDeviceType &devType,
IosToolHandler *q) IosToolHandler *q)
: IosToolHandlerPrivate(devType, q) : IosToolHandlerPrivate(devType, q)
, process(new Process, Deleter())
{ {
killTimer.setSingleShot(true);
auto deleter = [](QProcess *p) {
if (p->state() != QProcess::NotRunning) {
p->kill();
if (!p->waitForFinished(2000))
p->terminate();
}
delete p;
};
process = std::shared_ptr<QProcess>(new QProcess, deleter);
// Prepare & set process Environment. // Prepare & set process Environment.
QProcessEnvironment env(QProcessEnvironment::systemEnvironment()); const Environment systemEnv = Environment::systemEnvironment();
const QStringList keys = env.keys(); Environment env(systemEnv);
for (const QString &k : keys) systemEnv.forEachEntry([&env](const QString &key, const QString &, bool enabled) {
if (k.startsWith(QLatin1String("DYLD_"))) if (enabled && key.startsWith(QLatin1String("DYLD_")))
env.remove(k); env.unset(key);
});
QStringList frameworkPaths; QStringList frameworkPaths;
const Utils::FilePath libPath = IosConfigurations::developerPath().pathAppended("Platforms/iPhoneSimulator.platform/Developer/Library"); const FilePath libPath = IosConfigurations::developerPath().pathAppended("Platforms/iPhoneSimulator.platform/Developer/Library");
for (const auto framework : {"PrivateFrameworks", "OtherFrameworks", "SharedFrameworks"}) { for (const auto framework : {"PrivateFrameworks", "OtherFrameworks", "SharedFrameworks"}) {
const QString frameworkPath = const QString frameworkPath =
libPath.pathAppended(QLatin1String(framework)).toFileInfo().canonicalFilePath(); libPath.pathAppended(QLatin1String(framework)).toFileInfo().canonicalFilePath();
@@ -645,34 +599,27 @@ IosDeviceToolHandlerPrivate::IosDeviceToolHandlerPrivate(const IosDeviceType &de
frameworkPaths << frameworkPath; frameworkPaths << frameworkPath;
} }
frameworkPaths << "/System/Library/Frameworks" << "/System/Library/PrivateFrameworks"; frameworkPaths << "/System/Library/Frameworks" << "/System/Library/PrivateFrameworks";
env.insert(QLatin1String("DYLD_FALLBACK_FRAMEWORK_PATH"), frameworkPaths.join(QLatin1Char(':'))); env.set(QLatin1String("DYLD_FALLBACK_FRAMEWORK_PATH"), frameworkPaths.join(QLatin1Char(':')));
qCDebug(toolHandlerLog) << "IosToolHandler runEnv:" << env.toStringList(); qCDebug(toolHandlerLog) << "IosToolHandler runEnv:" << env.toStringList();
process->setProcessEnvironment(env); process->setEnvironment(env);
process->setProcessMode(ProcessMode::Writer);
process->setReaperTimeout(1500);
QObject::connect(process.get(), &QProcess::readyReadStandardOutput, QObject::connect(process.get(), &Process::readyReadStandardOutput,
std::bind(&IosDeviceToolHandlerPrivate::subprocessHasData,this)); q, [this] { subprocessHasData(); });
QObject::connect(process.get(), &Process::done, q, [this] {
QObject::connect(process.get(), &QProcess::finished, if (process->result() == ProcessResult::FinishedWithSuccess) {
std::bind(&IosDeviceToolHandlerPrivate::subprocessFinished,this, _1,_2)); stop((process->exitStatus() == QProcess::NormalExit) ? process->exitCode() : -1);
qCDebug(toolHandlerLog) << "IosToolHandler::finished(" << this << ")";
QObject::connect(process.get(), &QProcess::errorOccurred, } else {
std::bind(&IosDeviceToolHandlerPrivate::subprocessError, this, _1)); if (state != Stopped)
errorMsg(Tr::tr("iOS tool error %1").arg(process->error()));
QObject::connect(&killTimer, &QTimer::timeout, std::bind(&IosDeviceToolHandlerPrivate::killProcess, this)); stop(-1);
} if (process->result() == ProcessResult::StartFailed)
qCDebug(toolHandlerLog) << "IosToolHandler::finished(" << this << ")";
IosDeviceToolHandlerPrivate::~IosDeviceToolHandlerPrivate()
{
if (isRunning()) {
// Disconnect the signals to avoid notifications while destructing.
// QTCREATORBUG-18147
process->disconnect();
// Quit ios-tool gracefully before kill is executed.
process->write("k\n\r");
process->closeWriteChannel();
// Give some time to ios-tool to finish.
process->waitForFinished(2000);
} }
emit IosToolHandlerPrivate::q->finished(IosToolHandlerPrivate::q);
});
} }
void IosDeviceToolHandlerPrivate::requestTransferApp(const FilePath &bundlePath, void IosDeviceToolHandlerPrivate::requestTransferApp(const FilePath &bundlePath,
@@ -680,7 +627,7 @@ void IosDeviceToolHandlerPrivate::requestTransferApp(const FilePath &bundlePath,
{ {
m_bundlePath = bundlePath; m_bundlePath = bundlePath;
m_deviceId = deviceId; m_deviceId = deviceId;
QString tmpDeltaPath = Utils::TemporaryDirectory::masterDirectoryFilePath().pathAppended("ios").toString(); QString tmpDeltaPath = TemporaryDirectory::masterDirectoryFilePath().pathAppended("ios").toString();
QStringList args; QStringList args;
args << QLatin1String("--id") << deviceId << QLatin1String("--bundle") args << QLatin1String("--id") << deviceId << QLatin1String("--bundle")
<< bundlePath.path() << QLatin1String("--timeout") << QString::number(timeout) << bundlePath.path() << QLatin1String("--timeout") << QString::number(timeout)
@@ -736,11 +683,11 @@ void IosDeviceToolHandlerPrivate::start(const QString &exe, const QStringList &a
QTC_CHECK(state == NonStarted); QTC_CHECK(state == NonStarted);
state = Starting; state = Starting;
qCDebug(toolHandlerLog) << "running " << exe << args; qCDebug(toolHandlerLog) << "running " << exe << args;
process->start(exe, args); process->setCommand({FilePath::fromString(exe), args});
process->start();
state = StartedInferior; state = StartedInferior;
} }
void IosDeviceToolHandlerPrivate::stop(int errorCode) void IosDeviceToolHandlerPrivate::stop(int errorCode)
{ {
qCDebug(toolHandlerLog) << "IosToolHandlerPrivate::stop"; qCDebug(toolHandlerLog) << "IosToolHandlerPrivate::stop";
@@ -775,7 +722,7 @@ void IosDeviceToolHandlerPrivate::stop(int errorCode)
if (isRunning()) { if (isRunning()) {
process->write("k\n\r"); process->write("k\n\r");
process->closeWriteChannel(); process->closeWriteChannel();
killTimer.start(1500); process->stop();
} }
} }