forked from qt-creator/qt-creator
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:
@@ -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.")
|
||||
|
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user