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;
QString provisioningProfile = provisionPlist.value(QLatin1String("Name")).toString();
QString provisioningUid = provisionPlist.value(QLatin1String("UUID")).toString();
const QString provisioningProfile = provisionPlist.value(QLatin1String("Name")).toString();
const QString provisioningUid = provisionPlist.value(QLatin1String("UUID")).toString();
CompileTask task(Task::Warning,
Tr::tr("The provisioning profile \"%1\" (%2) used to sign the application "
"does not cover the device %3 (%4). Deployment to it will fail.")

View File

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