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;
|
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.")
|
||||||
|
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user