iostool: Cleanup and improve debug output

Replaced the custom command line arg parsing code
with QCommandLineParser

Change-Id: I14e8695b5ee327b1d111558271bf98afd0c942b0
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
Marcus Tillmanns
2022-06-15 12:08:07 +02:00
parent cf147aa4b6
commit 30f9f68b15
9 changed files with 725 additions and 656 deletions

View File

@@ -733,7 +733,7 @@ void IosDeviceToolHandlerPrivate::requestRunApp(const QString &bundlePath,
args << QLatin1String("--debug");
break;
}
args << QLatin1String("--args") << extraArgs;
args << QLatin1String("--") << extraArgs;
op = OpAppRun;
start(IosToolHandler::iosDeviceToolPath(), args);
}

View File

@@ -1,7 +1,7 @@
add_qtc_executable(iostool
DESTINATION ${IDE_LIBEXEC_PATH}/ios
DEPENDS
Qt5::Gui
Qt5::Core
Qt5::Xml
Qt5::Network
${FWCoreFoundation}

View File

@@ -46,20 +46,20 @@ void GdbRunner::run()
{
{
QMutexLocker l(&m_iosTool->m_xmlMutex);
if (!m_iosTool->splitAppOutput) {
m_iosTool->out.writeStartElement(QLatin1String("app_output"));
m_iosTool->inAppOutput = true;
if (!m_iosTool->m_splitAppOutput) {
m_iosTool->m_xmlWriter.writeStartElement(QLatin1String("app_output"));
m_iosTool->m_inAppOutput = true;
}
m_iosTool->outFile.flush();
m_iosTool->m_outputFile.flush();
}
Ios::IosDeviceManager::instance()->processGdbServer(m_conn);
{
QMutexLocker l(&m_iosTool->m_xmlMutex);
if (!m_iosTool->splitAppOutput) {
m_iosTool->inAppOutput = false;
m_iosTool->out.writeEndElement();
if (!m_iosTool->m_splitAppOutput) {
m_iosTool->m_inAppOutput = false;
m_iosTool->m_xmlWriter.writeEndElement();
}
m_iosTool->outFile.flush();
m_iosTool->m_outputFile.flush();
}
MobileDeviceLib::instance().serviceConnectionInvalidate(m_conn);
m_conn = nullptr;

File diff suppressed because it is too large Load Diff

View File

@@ -28,6 +28,7 @@
#include "relayserver.h"
#include "gdbrunner.h"
#include <QCommandLineParser>
#include <QCoreApplication>
#include <QRegularExpression>
#include <QTimer>
@@ -37,19 +38,10 @@ namespace Ios {
IosTool::IosTool(QObject *parent):
QObject(parent),
maxProgress(0),
opLeft(0),
debug(false),
inAppOutput(false),
splitAppOutput(true),
appOp(IosDeviceManager::None),
outFile(),
out(&outFile),
gdbServer(0),
qmlServer(0)
m_xmlWriter(&m_outputFile)
{
outFile.open(stdout, QIODevice::WriteOnly, QFileDevice::DontCloseHandle);
out.setAutoFormatting(true);
m_outputFile.open(stdout, QIODevice::WriteOnly, QFileDevice::DontCloseHandle);
m_xmlWriter.setAutoFormatting(true);
}
IosTool::~IosTool()
@@ -66,73 +58,83 @@ void IosTool::run(const QStringList &args)
int timeout = 1000;
QStringList extraArgs;
out.writeStartDocument();
out.writeStartElement(QLatin1String("query_result"));
for (int iarg = 1; iarg < args.size(); ++iarg) {
const QString &arg = args[iarg];
if (arg == QLatin1String("-i") || arg == QLatin1String("--id")) {
if (++iarg == args.size()) {
writeMsg(QStringLiteral("missing device id value after ") + arg);
printHelp = true;
}
deviceId = args.value(iarg);
} else if (arg == QLatin1String("-b") || arg == QLatin1String("--bundle")) {
if (++iarg == args.size()) {
writeMsg(QStringLiteral("missing bundle path after ") + arg);
printHelp = true;
}
bundlePath = args.value(iarg);
} else if (arg == QLatin1String("--delta-path")) {
if (++iarg == args.size()) {
writeMsg(QStringLiteral("missing path after ") + arg);
printHelp = true;
}
m_deltasPath = args.value(iarg);
} else if (arg == QLatin1String("--install")) {
appOp = IosDeviceManager::AppOp(appOp | IosDeviceManager::Install);
} else if (arg == QLatin1String("--run")) {
appOp = IosDeviceManager::AppOp(appOp | IosDeviceManager::Run);
} else if (arg == QLatin1String("--noninteractive")) {
// ignored for compatibility
} else if (arg == QLatin1String("-v") || arg == QLatin1String("--verbose")) {
m_echoRelays = true;
} else if (arg == QLatin1String("-d") || arg == QLatin1String("--debug")) {
appOp = IosDeviceManager::AppOp(appOp | IosDeviceManager::Run);
debug = true;
} else if (arg == QLatin1String("--device-info")) {
deviceInfo = true;
} else if (arg == QLatin1String("-t") || arg == QLatin1String("--timeout")) {
if (++iarg == args.size()) {
writeMsg(QStringLiteral("missing timeout value after ") + arg);
printHelp = true;
}
bool ok = false;
int tOut = args.value(iarg).toInt(&ok);
if (ok && tOut > 0) {
timeout = tOut;
} else {
writeMsg("timeout value should be an integer");
printHelp = true;
}
} else if (arg == QLatin1String("-a") || arg == QLatin1String("--args")) {
extraArgs = args.mid(iarg + 1, args.size() - iarg - 1);
iarg = args.size();
} else if (arg == QLatin1String("-h") || arg == QLatin1String("--help")) {
m_xmlWriter.writeStartDocument();
m_xmlWriter.writeStartElement(QLatin1String("query_result"));
QCommandLineParser cmdLineParser;
cmdLineParser.setOptionsAfterPositionalArgumentsMode(QCommandLineParser::ParseAsPositionalArguments);
cmdLineParser.setApplicationDescription("iOS Deployment and run helper");
const QList<QCommandLineOption> options{
QCommandLineOption(QStringList{"h", "help"}),
QCommandLineOption(QStringList{"i", "id"}, "target device id", "id"),
QCommandLineOption(QStringList{"b", "bundle"}, "path to the target bundle.app", "bundle"),
QCommandLineOption("delta-path", "path to the deploy delta directory", "delta-path"),
QCommandLineOption("install", "Install a bundle on a device"),
QCommandLineOption(QStringList{"r", "run"}, "Run the bundle on the device"),
QCommandLineOption(QStringList{"d", "debug"}, "Debug the bundle on the device"),
QCommandLineOption("device-info", "Retrieve information about the selected device"),
QCommandLineOption(QStringList{"t", "timeout"}, "Operation timeout (s)", "timeout"),
QCommandLineOption(QStringList{"v", "verbose"}, "Verbose output"),
};
cmdLineParser.addOptions(options);
cmdLineParser.process(args);
if (cmdLineParser.isSet("verbose"))
m_echoRelays = true;
if (cmdLineParser.isSet("id"))
deviceId = cmdLineParser.value("id");
if (cmdLineParser.isSet("bundle"))
bundlePath = cmdLineParser.value("bundle");
if (cmdLineParser.isSet("delta-path"))
m_deltasPath = cmdLineParser.value("delta-path");
if (cmdLineParser.isSet("install")) {
m_requestedOperation = IosDeviceManager::AppOp(m_requestedOperation
| IosDeviceManager::Install);
}
else if (cmdLineParser.isSet("run")) {
m_requestedOperation = IosDeviceManager::AppOp(m_requestedOperation | IosDeviceManager::Run);
}
if (cmdLineParser.isSet("debug")) {
m_requestedOperation = IosDeviceManager::AppOp(m_requestedOperation | IosDeviceManager::Run);
m_debug = true;
}
if (cmdLineParser.isSet("device-info"))
deviceInfo = true;
if (cmdLineParser.isSet("timeout")) {
bool ok = false;
timeout = cmdLineParser.value("timeout").toInt(&ok);
if (!ok || timeout < 0) {
writeMsg("timeout value should be an integer");
printHelp = true;
} else {
writeMsg(QString::fromLatin1("unexpected argument \"%1\"").arg(arg));
}
}
if (printHelp) {
out.writeStartElement(QLatin1String("msg"));
out.writeCharacters(QLatin1String("iostool [--id <device_id>] [--bundle <bundle.app>] [--install] [--run] [--debug]\n"));
out.writeCharacters(QLatin1String(" [--device-info] [--timeout <timeout_in_ms>] [--verbose]\n")); // to do pass in env as stub does
out.writeCharacters(QLatin1String(" [--args <arguments for the target app>]"));
out.writeEndElement();
extraArgs = cmdLineParser.positionalArguments();
if (printHelp || cmdLineParser.isSet("help")) {
m_xmlWriter.writeStartElement(QLatin1String("msg"));
m_xmlWriter.writeCharacters(
QLatin1String("iostool [--id <device_id>] [--bundle <bundle.app>] [--delta-path] "
"[--install] [--run] [--debug]\n"));
m_xmlWriter.writeCharacters(QLatin1String(
" [--device-info] [--timeout <timeout_in_ms>] [--verbose]\n")); // to do pass in env as stub does
m_xmlWriter.writeCharacters(QLatin1String(" [-- <arguments for the target app>]"));
m_xmlWriter.writeEndElement();
doExit(-1);
return;
}
outFile.flush();
m_outputFile.flush();
connect(manager, &IosDeviceManager::isTransferringApp, this, &IosTool::isTransferringApp);
connect(manager, &IosDeviceManager::didTransferApp, this, &IosTool::didTransferApp);
connect(manager, &IosDeviceManager::didStartApp, this, &IosTool::didStartApp);
@@ -154,35 +156,35 @@ void IosTool::run(const QStringList &args)
if (deviceInfo) {
if (!bundlePath.isEmpty())
writeMsg("--device-info overrides --bundle");
++opLeft;
++m_operationsRemaining;
manager->requestDeviceInfo(deviceId, timeout);
} else if (!bundlePath.isEmpty()) {
switch (appOp) {
switch (m_requestedOperation) {
case IosDeviceManager::None:
break;
case IosDeviceManager::Install:
case IosDeviceManager::Run:
++opLeft;
++m_operationsRemaining;
break;
case IosDeviceManager::InstallAndRun:
opLeft += 2;
m_operationsRemaining += 2;
break;
}
maxProgress = 200;
manager->requestAppOp(bundlePath, extraArgs, appOp, deviceId, timeout, m_deltasPath);
m_maxProgress = 200;
manager->requestAppOp(bundlePath, extraArgs, m_requestedOperation, deviceId, timeout, m_deltasPath);
}
if (opLeft == 0)
if (m_operationsRemaining == 0)
doExit(0);
}
void IosTool::stopXml(int errorCode)
{
QMutexLocker l(&m_xmlMutex);
out.writeEmptyElement(QLatin1String("exit"));
out.writeAttribute(QLatin1String("code"), QString::number(errorCode));
out.writeEndElement(); // result element (hopefully)
out.writeEndDocument();
outFile.flush();
m_xmlWriter.writeEmptyElement(QLatin1String("exit"));
m_xmlWriter.writeAttribute(QLatin1String("code"), QString::number(errorCode));
m_xmlWriter.writeEndElement(); // result element (hopefully)
m_xmlWriter.writeEndDocument();
m_outputFile.flush();
}
void IosTool::doExit(int errorCode)
@@ -198,12 +200,12 @@ void IosTool::isTransferringApp(const QString &bundlePath, const QString &device
Q_UNUSED(bundlePath)
Q_UNUSED(deviceId)
QMutexLocker l(&m_xmlMutex);
out.writeStartElement(QLatin1String("status"));
out.writeAttribute(QLatin1String("progress"), QString::number(progress));
out.writeAttribute(QLatin1String("max_progress"), QString::number(maxProgress));
out.writeCharacters(info);
out.writeEndElement();
outFile.flush();
m_xmlWriter.writeStartElement(QLatin1String("status"));
m_xmlWriter.writeAttribute(QLatin1String("progress"), QString::number(progress));
m_xmlWriter.writeAttribute(QLatin1String("max_progress"), QString::number(m_maxProgress));
m_xmlWriter.writeCharacters(info);
m_xmlWriter.writeEndElement();
m_outputFile.flush();
}
void IosTool::didTransferApp(const QString &bundlePath, const QString &deviceId,
@@ -214,21 +216,21 @@ void IosTool::didTransferApp(const QString &bundlePath, const QString &deviceId,
{
QMutexLocker l(&m_xmlMutex);
if (status == IosDeviceManager::Success) {
out.writeStartElement(QLatin1String("status"));
out.writeAttribute(QLatin1String("progress"), QString::number(maxProgress));
out.writeAttribute(QLatin1String("max_progress"), QString::number(maxProgress));
out.writeCharacters(QLatin1String("App Transferred"));
out.writeEndElement();
m_xmlWriter.writeStartElement(QLatin1String("status"));
m_xmlWriter.writeAttribute(QLatin1String("progress"), QString::number(m_maxProgress));
m_xmlWriter.writeAttribute(QLatin1String("max_progress"), QString::number(m_maxProgress));
m_xmlWriter.writeCharacters(QLatin1String("App Transferred"));
m_xmlWriter.writeEndElement();
}
out.writeEmptyElement(QLatin1String("app_transfer"));
out.writeAttribute(QLatin1String("status"),
m_xmlWriter.writeEmptyElement(QLatin1String("app_transfer"));
m_xmlWriter.writeAttribute(QLatin1String("status"),
(status == IosDeviceManager::Success) ?
QLatin1String("SUCCESS") :
QLatin1String("FAILURE"));
//out.writeCharacters(QString()); // trigger a complete closing of the empty element
outFile.flush();
m_outputFile.flush();
}
if (status != IosDeviceManager::Success || --opLeft == 0)
if (status != IosDeviceManager::Success || --m_operationsRemaining == 0)
doExit((status == IosDeviceManager::Success) ? 0 : -1);
}
@@ -240,15 +242,15 @@ void IosTool::didStartApp(const QString &bundlePath, const QString &deviceId,
Q_UNUSED(deviceId)
{
QMutexLocker l(&m_xmlMutex);
out.writeEmptyElement(QLatin1String("app_started"));
out.writeAttribute(QLatin1String("status"),
m_xmlWriter.writeEmptyElement(QLatin1String("app_started"));
m_xmlWriter.writeAttribute(QLatin1String("status"),
(status == IosDeviceManager::Success) ?
QLatin1String("SUCCESS") :
QLatin1String("FAILURE"));
//out.writeCharacters(QString()); // trigger a complete closing of the empty element
outFile.flush();
m_outputFile.flush();
}
if (status != IosDeviceManager::Success || appOp == IosDeviceManager::Install) {
if (status != IosDeviceManager::Success || m_requestedOperation == IosDeviceManager::Install) {
doExit();
return;
}
@@ -257,43 +259,44 @@ void IosTool::didStartApp(const QString &bundlePath, const QString &deviceId,
doExit(-2);
return;
}
if (appOp != IosDeviceManager::InstallAndRun && appOp != IosDeviceManager::Run) {
writeMsg(QString::fromLatin1("unexpected appOp value %1").arg(appOp));
if (m_requestedOperation != IosDeviceManager::InstallAndRun && m_requestedOperation != IosDeviceManager::Run) {
writeMsg(QString::fromLatin1("unexpected appOp value %1").arg(m_requestedOperation));
doExit(-3);
return;
}
if (deviceSession) {
int qmlPort = deviceSession->qmljsDebugPort();
if (qmlPort) {
qmlServer = new QmlRelayServer(this, qmlPort, deviceSession);
qmlServer->startServer();
m_qmlServer = std::make_unique<QmlRelayServer>(this, qmlPort, deviceSession);
m_qmlServer->startServer();
}
}
if (debug) {
gdbServer = new GdbRelayServer(this, gdbFd, conn);
if (!gdbServer->startServer()) {
if (m_debug) {
m_gdbServer = std::make_unique<GdbRelayServer>(this, gdbFd, conn);
if (!m_gdbServer->startServer()) {
doExit(-4);
return;
}
}
{
QMutexLocker l(&m_xmlMutex);
out.writeStartElement(QLatin1String("server_ports"));
out.writeAttribute(QLatin1String("gdb_server"),
QString::number(gdbServer ? gdbServer->serverPort() : -1));
out.writeAttribute(QLatin1String("qml_server"),
QString::number(qmlServer ? qmlServer->serverPort() : -1));
out.writeEndElement();
outFile.flush();
m_xmlWriter.writeStartElement(QLatin1String("server_ports"));
m_xmlWriter.writeAttribute(QLatin1String("gdb_server"),
QString::number(m_gdbServer ? m_gdbServer->serverPort() : -1));
m_xmlWriter.writeAttribute(QLatin1String("qml_server"),
QString::number(m_qmlServer ? m_qmlServer->serverPort() : -1));
m_xmlWriter.writeEndElement();
m_outputFile.flush();
}
if (!debug) {
gdbRunner = new GdbRunner(this, conn);
if (!m_debug) {
m_gdbRunner = std::make_unique<GdbRunner>(this, conn);
// we should not stop the event handling of the main thread
// all output moves to the new thread (other option would be to signal it back)
QThread *gdbProcessThread = new QThread();
gdbRunner->moveToThread(gdbProcessThread);
QObject::connect(gdbProcessThread, &QThread::started, gdbRunner, &GdbRunner::run);
QObject::connect(gdbRunner, &GdbRunner::finished, gdbProcessThread, &QThread::quit);
m_gdbRunner->moveToThread(gdbProcessThread);
QObject::connect(gdbProcessThread, &QThread::started, m_gdbRunner.get(), &GdbRunner::run);
QObject::connect(m_gdbRunner.get(), &GdbRunner::finished, gdbProcessThread, &QThread::quit);
QObject::connect(gdbProcessThread, &QThread::finished,
gdbProcessThread, &QObject::deleteLater);
gdbProcessThread->start();
@@ -310,11 +313,11 @@ void IosTool::writeMsg(const char *msg)
void IosTool::writeMsg(const QString &msg)
{
QMutexLocker l(&m_xmlMutex);
out.writeStartElement(QLatin1String("msg"));
m_xmlWriter.writeStartElement(QLatin1String("msg"));
writeTextInElement(msg);
out.writeCharacters(QLatin1String("\n"));
out.writeEndElement();
outFile.flush();
m_xmlWriter.writeCharacters(QLatin1String("\n"));
m_xmlWriter.writeEndElement();
m_outputFile.flush();
}
void IosTool::writeMaybeBin(const QString &extraMsg, const char *msg, quintptr len)
@@ -331,9 +334,9 @@ void IosTool::writeMaybeBin(const QString &extraMsg, const char *msg, quintptr l
buf2[2 * len + 3] = 0;
QMutexLocker l(&m_xmlMutex);
out.writeStartElement(QLatin1String("msg"));
out.writeCharacters(extraMsg);
out.writeCharacters(QLatin1String(buf2));
m_xmlWriter.writeStartElement(QLatin1String("msg"));
m_xmlWriter.writeCharacters(extraMsg);
m_xmlWriter.writeCharacters(QLatin1String(buf2));
for (quintptr i = 0; i < len; ++i) {
if (msg[i] < 0x20 || msg[i] > 0x7f)
buf2[i] = '_';
@@ -341,10 +344,10 @@ void IosTool::writeMaybeBin(const QString &extraMsg, const char *msg, quintptr l
buf2[i] = msg[i];
}
buf2[len] = 0;
out.writeCharacters(QLatin1String(buf2));
m_xmlWriter.writeCharacters(QLatin1String(buf2));
delete[] buf2;
out.writeEndElement();
outFile.flush();
m_xmlWriter.writeEndElement();
m_outputFile.flush();
}
void IosTool::deviceInfo(const QString &deviceId, const IosDeviceManager::Dict &devInfo)
@@ -352,16 +355,16 @@ void IosTool::deviceInfo(const QString &deviceId, const IosDeviceManager::Dict &
Q_UNUSED(deviceId)
{
QMutexLocker l(&m_xmlMutex);
out.writeTextElement(QLatin1String("device_id"), deviceId);
out.writeStartElement(QLatin1String("device_info"));
m_xmlWriter.writeTextElement(QLatin1String("device_id"), deviceId);
m_xmlWriter.writeStartElement(QLatin1String("device_info"));
for (auto i = devInfo.cbegin(); i != devInfo.cend(); ++i) {
out.writeStartElement(QLatin1String("item"));
out.writeTextElement(QLatin1String("key"), i.key());
out.writeTextElement(QLatin1String("value"), i.value());
out.writeEndElement();
m_xmlWriter.writeStartElement(QLatin1String("item"));
m_xmlWriter.writeTextElement(QLatin1String("key"), i.key());
m_xmlWriter.writeTextElement(QLatin1String("value"), i.value());
m_xmlWriter.writeEndElement();
}
out.writeEndElement();
outFile.flush();
m_xmlWriter.writeEndElement();
m_outputFile.flush();
}
doExit();
}
@@ -374,24 +377,24 @@ void IosTool::writeTextInElement(const QString &output)
while ((pos = output.indexOf(controlCharRe, pos)) != -1) {
QMutexLocker l(&m_xmlMutex);
out.writeCharacters(output.mid(oldPos, pos - oldPos));
out.writeEmptyElement(QLatin1String("control_char"));
out.writeAttribute(QLatin1String("code"), QString::number(output.at(pos).toLatin1()));
m_xmlWriter.writeCharacters(output.mid(oldPos, pos - oldPos));
m_xmlWriter.writeEmptyElement(QLatin1String("control_char"));
m_xmlWriter.writeAttribute(QLatin1String("code"), QString::number(output.at(pos).toLatin1()));
pos += 1;
oldPos = pos;
}
out.writeCharacters(output.mid(oldPos, output.length() - oldPos));
m_xmlWriter.writeCharacters(output.mid(oldPos, output.length() - oldPos));
}
void IosTool::appOutput(const QString &output)
{
QMutexLocker l(&m_xmlMutex);
if (!inAppOutput)
out.writeStartElement(QLatin1String("app_output"));
if (!m_inAppOutput)
m_xmlWriter.writeStartElement(QLatin1String("app_output"));
writeTextInElement(output);
if (!inAppOutput)
out.writeEndElement();
outFile.flush();
if (!m_inAppOutput)
m_xmlWriter.writeEndElement();
m_outputFile.flush();
}
void IosTool::readStdin()
@@ -412,26 +415,26 @@ void IosTool::errorMsg(const QString &msg)
void IosTool::stopGdbRunner()
{
if (gdbRunner) {
gdbRunner->stop(0);
if (m_gdbRunner) {
m_gdbRunner->stop(0);
QTimer::singleShot(100, this, &IosTool::stopGdbRunner2);
}
}
void IosTool::stopGdbRunner2()
{
if (gdbRunner)
gdbRunner->stop(1);
if (m_gdbRunner)
m_gdbRunner->stop(1);
}
void IosTool::stopRelayServers(int errorCode)
{
if (echoRelays())
writeMsg("gdbServerStops");
if (qmlServer)
qmlServer->stopServer();
if (gdbServer)
gdbServer->stopServer();
if (m_qmlServer)
m_qmlServer->stopServer();
if (m_gdbServer)
m_gdbServer->stopServer();
doExit(errorCode);
}

View File

@@ -40,6 +40,8 @@ class QmlRelayServer;
class IosTool: public QObject
{
friend class GdbRunner;
Q_OBJECT
public:
@@ -71,20 +73,19 @@ private:
void readStdin();
QRecursiveMutex m_xmlMutex;
int maxProgress;
int opLeft;
bool debug;
bool inAppOutput;
bool splitAppOutput; // as QXmlStreamReader reports the text attributes atomically it is better to split
Ios::IosDeviceManager::AppOp appOp;
QFile outFile;
int m_maxProgress = 0;
int m_operationsRemaining = 0;
bool m_debug = false;
bool m_inAppOutput = false;
bool m_splitAppOutput = true; // as QXmlStreamReader reports the text attributes atomically it is better to split
IosDeviceManager::AppOp m_requestedOperation{IosDeviceManager::AppOp::None};
QFile m_outputFile;
QString m_qmlPort;
QString m_deltasPath;
QXmlStreamWriter out;
GdbRelayServer *gdbServer;
QmlRelayServer *qmlServer;
GdbRunner *gdbRunner;
QXmlStreamWriter m_xmlWriter;
std::unique_ptr<GdbRelayServer> m_gdbServer;
std::unique_ptr<QmlRelayServer> m_qmlServer;
std::unique_ptr<GdbRunner> m_gdbRunner;
bool m_echoRelays = false;
friend class GdbRunner;
};
}

View File

@@ -25,13 +25,15 @@
#include "iostool.h"
#include <QGuiApplication>
#include <QCoreApplication>
#include <QStringList>
int main(int argc, char *argv[])
{
//This keeps iostool from stealing focus
qputenv("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM", "true");
// Make sure that our runloop uses the CFRunLoop dispatcher.
// Otherwise the MobileDevice.Framework notifications won't work.
qputenv("QT_EVENT_DISPATCHER_CORE_FOUNDATION", "1");
// We do not pass the real arguments to QCoreApplication because this wrapper needs to be able
// to forward arguments like -qmljsdebugger=... that are filtered by QCoreApplication
QStringList args;
@@ -44,7 +46,10 @@ int main(int argc, char *argv[])
qtArgc = 1;
}
QGuiApplication a(qtArgc, &qtArg);
QCoreApplication a(qtArgc, &qtArg);
QCoreApplication::setApplicationName("iostool");
QCoreApplication::setApplicationVersion("1.0");
Ios::IosTool tool;
tool.run(args);
int res = a.exec();

View File

@@ -24,9 +24,15 @@
****************************************************************************/
#include "mobiledevicelib.h"
#include "cfutils.h"
#include <QDebug>
#include <QLoggingCategory>
#include <QUrl>
namespace {
Q_LOGGING_CATEGORY(loggingCategory, "qtc.iostool.mobiledevicelib")
}
#ifdef MOBILE_DEV_DIRECT_LINK
#include "MobileDevice.h"
@@ -51,6 +57,14 @@ MobileDeviceLib::MobileDeviceLib()
setLogLevel(5);
}
template<typename T>
void MobileDeviceLib::resolveFunction(const char *functionName, T &functionPtr) {
functionPtr = reinterpret_cast<T>(m_mobileDeviceLib.resolve(functionName));
if (!functionPtr) {
addError(QLatin1String("MobileDeviceLib does not define ") + functionName);
}
}
bool MobileDeviceLib::load()
{
#ifdef MOBILE_DEV_DIRECT_LINK
@@ -75,116 +89,46 @@ bool MobileDeviceLib::load()
//m_AMDeviceLookupApplications = &AMDeviceLookupApplications;
m_USBMuxConnectByPort = &USBMuxConnectByPort;
#else
QLibrary *libAppleFSCompression = new QLibrary(QLatin1String("/System/Library/PrivateFrameworks/AppleFSCompression.framework/AppleFSCompression"));
if (!libAppleFSCompression->load())
addError("MobileDevice dependency AppleFSCompression failed to load");
deps << libAppleFSCompression;
QLibrary *libBom = new QLibrary(QLatin1String("/System/Library/PrivateFrameworks/Bom.framework/Bom"));
if (!libBom->load())
addError("MobileDevice dependency Bom failed to load");
deps << libBom;
lib.setFileName(QLatin1String("/System/Library/PrivateFrameworks/MobileDevice.framework/MobileDevice"));
if (!lib.load())
m_mobileDeviceLib.setFileName("/System/Library/PrivateFrameworks/MobileDevice.framework/MobileDevice");
if (!m_mobileDeviceLib.load())
return false;
m_AMDSetLogLevel = reinterpret_cast<AMDSetLogLevelPtr>(lib.resolve("AMDSetLogLevel"));
if (m_AMDSetLogLevel == 0)
addError("MobileDeviceLib does not define AMDSetLogLevel");
m_AMDeviceSecureInstallApplicationBundle
= reinterpret_cast<AMDeviceSecureInstallApplicationBundlePtr>(
lib.resolve("AMDeviceSecureInstallApplicationBundle"));
if (m_AMDeviceSecureInstallApplicationBundle == 0)
addError("MobileDeviceLib does not define m_AMDeviceSecureInstallApplicationBundle");
m_AMDeviceNotificationSubscribe = reinterpret_cast<AMDeviceNotificationSubscribePtr>(
lib.resolve("AMDeviceNotificationSubscribe"));
if (m_AMDeviceNotificationSubscribe == 0)
addError("MobileDeviceLib does not define AMDeviceNotificationSubscribe");
m_AMDeviceNotificationUnsubscribe = reinterpret_cast<AMDeviceNotificationUnsubscribePtr>(lib.resolve("AMDeviceNotificationUnsubscribe"));
if (m_AMDeviceNotificationUnsubscribe == 0)
addError("MobileDeviceLib does not define AMDeviceNotificationUnsubscribe");
m_AMDeviceGetInterfaceType = reinterpret_cast<AMDeviceGetInterfaceTypePtr>(lib.resolve("AMDeviceGetInterfaceType"));
if (m_AMDeviceGetInterfaceType == 0)
addError("MobileDeviceLib does not define AMDeviceGetInterfaceType");
m_AMDeviceCopyValue = reinterpret_cast<AMDeviceCopyValuePtr>(lib.resolve("AMDeviceCopyValue"));
if (m_AMDSetLogLevel == 0)
addError("MobileDeviceLib does not define AMDSetLogLevel");
m_AMDeviceGetConnectionID = reinterpret_cast<AMDeviceGetConnectionIDPtr>(lib.resolve("AMDeviceGetConnectionID"));
if (m_AMDeviceGetConnectionID == 0)
addError("MobileDeviceLib does not define AMDeviceGetConnectionID");
m_AMDeviceCopyDeviceIdentifier = reinterpret_cast<AMDeviceCopyDeviceIdentifierPtr>(lib.resolve("AMDeviceCopyDeviceIdentifier"));
if (m_AMDeviceCopyDeviceIdentifier == 0)
addError("MobileDeviceLib does not define AMDeviceCopyDeviceIdentifier");
m_AMDeviceConnect = reinterpret_cast<AMDeviceConnectPtr>(lib.resolve("AMDeviceConnect"));
if (m_AMDeviceConnect == 0)
addError("MobileDeviceLib does not define AMDeviceConnect");
m_AMDevicePair = reinterpret_cast<AMDevicePairPtr>(lib.resolve("AMDevicePair"));
if (m_AMDevicePair == 0)
addError("MobileDeviceLib does not define AMDevicePair");
m_AMDeviceIsPaired = reinterpret_cast<AMDeviceIsPairedPtr>(lib.resolve("AMDeviceIsPaired"));
if (m_AMDeviceIsPaired == 0)
addError("MobileDeviceLib does not define AMDeviceIsPaired");
m_AMDeviceValidatePairing = reinterpret_cast<AMDeviceValidatePairingPtr>(lib.resolve("AMDeviceValidatePairing"));
if (m_AMDeviceValidatePairing == 0)
addError("MobileDeviceLib does not define AMDeviceValidatePairing");
m_AMDeviceStartSession = reinterpret_cast<AMDeviceStartSessionPtr>(lib.resolve("AMDeviceStartSession"));
if (m_AMDeviceStartSession == 0)
addError("MobileDeviceLib does not define AMDeviceStartSession");
m_AMDeviceStopSession = reinterpret_cast<AMDeviceStopSessionPtr>(lib.resolve("AMDeviceStopSession"));
if (m_AMDeviceStopSession == 0)
addError("MobileDeviceLib does not define AMDeviceStopSession");
m_AMDeviceDisconnect = reinterpret_cast<AMDeviceDisconnectPtr>(lib.resolve("AMDeviceDisconnect"));
if (m_AMDeviceDisconnect == 0)
addError("MobileDeviceLib does not define AMDeviceDisconnect");
m_AMDeviceMountImage = reinterpret_cast<AMDeviceMountImagePtr>(lib.resolve("AMDeviceMountImage"));
if (m_AMDeviceMountImage == 0)
addError("MobileDeviceLib does not define AMDeviceMountImage");
m_AMDeviceSecureStartService = reinterpret_cast<AMDeviceSecureStartServicePtr>(lib.resolve("AMDeviceSecureStartService"));
if (m_AMDeviceSecureStartService == 0)
addError("MobileDeviceLib does not define AMDeviceSecureStartService");
m_AMDeviceSecureTransferPath = reinterpret_cast<AMDeviceSecureTransferPathPtr>(lib.resolve("AMDeviceSecureTransferPath"));
if (m_AMDeviceSecureTransferPath == 0)
addError("MobileDeviceLib does not define AMDeviceSecureTransferPath");
m_AMDeviceSecureInstallApplication = reinterpret_cast<AMDeviceSecureInstallApplicationPtr>(lib.resolve("AMDeviceSecureInstallApplication"));
if (m_AMDeviceSecureInstallApplication == 0)
addError("MobileDeviceLib does not define AMDeviceSecureInstallApplication");
m_AMDServiceConnectionGetSocket = reinterpret_cast<AMDServiceConnectionGetSocketPtr>(lib.resolve("AMDServiceConnectionGetSocket"));
if (m_AMDServiceConnectionGetSocket == nullptr)
addError("MobileDeviceLib does not define AMDServiceConnectionGetSocket");
m_AMDeviceUninstallApplication = reinterpret_cast<AMDeviceUninstallApplicationPtr>(lib.resolve("AMDeviceUninstallApplication"));
m_AMDServiceConnectionSend = reinterpret_cast<AMDServiceConnectionSendPtr>(lib.resolve("AMDServiceConnectionSend"));
if (m_AMDServiceConnectionSend == nullptr)
addError("MobileDeviceLib does not define AMDServiceConnectionSend");
m_AMDServiceConnectionReceive = reinterpret_cast<AMDServiceConnectionReceivePtr>(lib.resolve("AMDServiceConnectionReceive"));
if (m_AMDServiceConnectionReceive == nullptr)
addError("MobileDeviceLib does not define AMDServiceConnectionReceive");
m_AMDServiceConnectionInvalidate = reinterpret_cast<AMDServiceConnectionInvalidatePtr>(lib.resolve("AMDServiceConnectionInvalidate"));
if (m_AMDServiceConnectionInvalidate == nullptr)
addError("MobileDeviceLib does not define AMDServiceConnectionInvalidate");
m_AMDeviceIsAtLeastVersionOnPlatform = reinterpret_cast<AMDeviceIsAtLeastVersionOnPlatformPtr>(lib.resolve("AMDeviceIsAtLeastVersionOnPlatform"));
if (m_AMDeviceIsAtLeastVersionOnPlatform == nullptr)
addError("MobileDeviceLib does not define AMDeviceIsAtLeastVersionOnPlatform");
if (m_AMDeviceUninstallApplication == 0)
addError("MobileDeviceLib does not define AMDeviceUninstallApplication");
m_AMDeviceLookupApplications = reinterpret_cast<AMDeviceLookupApplicationsPtr>(lib.resolve("AMDeviceLookupApplications"));
if (m_AMDeviceLookupApplications == 0)
addError("MobileDeviceLib does not define AMDeviceLookupApplications");
m_AMDErrorString = reinterpret_cast<AMDErrorStringPtr>(lib.resolve("AMDErrorString"));
if (m_AMDErrorString == 0)
addError("MobileDeviceLib does not define AMDErrorString");
m_MISCopyErrorStringForErrorCode = reinterpret_cast<MISCopyErrorStringForErrorCodePtr>(lib.resolve("MISCopyErrorStringForErrorCode"));
if (m_MISCopyErrorStringForErrorCode == 0)
addError("MobileDeviceLib does not define MISCopyErrorStringForErrorCode");
m_USBMuxConnectByPort = reinterpret_cast<USBMuxConnectByPortPtr>(lib.resolve("USBMuxConnectByPort"));
if (m_USBMuxConnectByPort == 0)
addError("MobileDeviceLib does not define USBMuxConnectByPort");
resolveFunction("AMDSetLogLevel", m_AMDSetLogLevel);
resolveFunction("AMDeviceSecureInstallApplicationBundle", m_AMDeviceSecureInstallApplicationBundle);
resolveFunction("AMDeviceNotificationSubscribe", m_AMDeviceNotificationSubscribe);
resolveFunction("AMDeviceNotificationUnsubscribe", m_AMDeviceNotificationUnsubscribe);
resolveFunction("AMDeviceGetInterfaceType", m_AMDeviceGetInterfaceType);
resolveFunction("AMDeviceCopyValue", m_AMDeviceCopyValue);
resolveFunction("AMDeviceGetConnectionID", m_AMDeviceGetConnectionID);
resolveFunction("AMDeviceCopyDeviceIdentifier", m_AMDeviceCopyDeviceIdentifier);
resolveFunction("AMDeviceConnect", m_AMDeviceConnect);
resolveFunction("AMDevicePair", m_AMDevicePair);
resolveFunction("AMDeviceIsPaired", m_AMDeviceIsPaired);
resolveFunction("AMDeviceValidatePairing", m_AMDeviceValidatePairing);
resolveFunction("AMDeviceStartSession", m_AMDeviceStartSession);
resolveFunction("AMDeviceStopSession", m_AMDeviceStopSession);
resolveFunction("AMDeviceDisconnect", m_AMDeviceDisconnect);
resolveFunction("AMDeviceMountImage", m_AMDeviceMountImage);
resolveFunction("AMDeviceSecureStartService", m_AMDeviceSecureStartService);
resolveFunction("AMDeviceSecureTransferPath", m_AMDeviceSecureTransferPath);
resolveFunction("AMDeviceSecureInstallApplication", m_AMDeviceSecureInstallApplication);
resolveFunction("AMDServiceConnectionGetSocket", m_AMDServiceConnectionGetSocket);
resolveFunction("AMDeviceUninstallApplication", m_AMDeviceUninstallApplication);
resolveFunction("AMDServiceConnectionSend", m_AMDServiceConnectionSend);
resolveFunction("AMDServiceConnectionReceive", m_AMDServiceConnectionReceive);
resolveFunction("AMDServiceConnectionInvalidate", m_AMDServiceConnectionInvalidate);
resolveFunction("AMDeviceIsAtLeastVersionOnPlatform", m_AMDeviceIsAtLeastVersionOnPlatform);
resolveFunction("AMDeviceLookupApplications", m_AMDeviceLookupApplications);
resolveFunction("AMDErrorString", m_AMDErrorString);
resolveFunction("MISCopyErrorStringForErrorCode", m_MISCopyErrorStringForErrorCode);
resolveFunction("USBMuxConnectByPort", m_USBMuxConnectByPort);
#endif
return true;
}
bool MobileDeviceLib::isLoaded()
{
return lib.isLoaded();
return m_mobileDeviceLib.isLoaded();
}
QStringList MobileDeviceLib::errors()
@@ -199,11 +143,13 @@ void MobileDeviceLib::setLogLevel(int i)
}
am_res_t MobileDeviceLib::deviceNotificationSubscribe(AMDeviceNotificationCallback callback,
unsigned int v1, unsigned int v2, void *callbackArgs,
const AMDeviceNotification **handle)
unsigned int v1,
unsigned int v2,
void *callbackArgs,
const AMDeviceNotification **handle)
{
if (m_AMDeviceNotificationSubscribe)
return m_AMDeviceNotificationSubscribe(callback,v1,v2,callbackArgs,handle);
return m_AMDeviceNotificationSubscribe(callback, v1, v2, callbackArgs, handle);
return -1;
}
@@ -221,7 +167,9 @@ int MobileDeviceLib::deviceGetInterfaceType(AMDeviceRef device)
return DeviceInterfaceType::UNKNOWN;
}
CFPropertyListRef MobileDeviceLib::deviceCopyValue(AMDeviceRef device,CFStringRef group,CFStringRef key)
CFPropertyListRef MobileDeviceLib::deviceCopyValue(AMDeviceRef device,
CFStringRef group,
CFStringRef key)
{
if (m_AMDeviceCopyValue)
return m_AMDeviceCopyValue(device, group, key);
@@ -291,28 +239,35 @@ am_res_t MobileDeviceLib::deviceDisconnect(AMDeviceRef device)
return -1;
}
am_res_t MobileDeviceLib::deviceMountImage(AMDeviceRef device, CFStringRef imagePath,
CFDictionaryRef options,
AMDeviceMountImageCallback callback,
void *callbackExtraArgs)
am_res_t MobileDeviceLib::deviceMountImage(AMDeviceRef device,
CFStringRef imagePath,
CFDictionaryRef options,
AMDeviceMountImageCallback callback,
void *callbackExtraArgs)
{
if (m_AMDeviceMountImage)
return m_AMDeviceMountImage(device, imagePath, options, callback, callbackExtraArgs);
return -1;
}
am_res_t MobileDeviceLib::deviceUninstallApplication(int serviceFd, CFStringRef bundleId,
CFDictionaryRef options,
AMDeviceInstallApplicationCallback callback,
void *callbackExtraArgs)
am_res_t MobileDeviceLib::deviceUninstallApplication(int serviceFd,
CFStringRef bundleId,
CFDictionaryRef options,
AMDeviceInstallApplicationCallback callback,
void *callbackExtraArgs)
{
if (m_AMDeviceUninstallApplication)
return m_AMDeviceUninstallApplication(serviceFd, bundleId, options, callback, callbackExtraArgs);
return m_AMDeviceUninstallApplication(serviceFd,
bundleId,
options,
callback,
callbackExtraArgs);
return -1;
}
am_res_t MobileDeviceLib::deviceLookupApplications(AMDeviceRef device, CFDictionaryRef options,
CFDictionaryRef *res)
am_res_t MobileDeviceLib::deviceLookupApplications(AMDeviceRef device,
CFDictionaryRef options,
CFDictionaryRef *res)
{
if (m_AMDeviceLookupApplications)
return m_AMDeviceLookupApplications(device, options, res);
@@ -342,7 +297,7 @@ am_res_t MobileDeviceLib::connectByPort(unsigned int connectionId, int port, Ser
void MobileDeviceLib::addError(const QString &msg)
{
qDebug() << "MobileDeviceLib ERROR:" << msg;
qCWarning(loggingCategory) << "MobileDeviceLib ERROR:" << msg;
m_errors << QLatin1String("MobileDeviceLib ERROR:") << msg;
}
@@ -351,16 +306,25 @@ void MobileDeviceLib::addError(const char *msg)
addError(QLatin1String(msg));
}
am_res_t MobileDeviceLib::deviceSecureStartService(AMDeviceRef device, CFStringRef serviceName, ServiceConnRef *fdRef)
am_res_t MobileDeviceLib::deviceSecureStartService(AMDeviceRef device,
CFStringRef serviceName,
ServiceConnRef *fdRef)
{
if (m_AMDeviceSecureStartService)
return m_AMDeviceSecureStartService(device, serviceName, nullptr, fdRef);
return 0;
}
int MobileDeviceLib::deviceSecureTransferApplicationPath(int zero, AMDeviceRef device, CFURLRef url, CFDictionaryRef dict, AMDeviceSecureInstallApplicationCallback callback, int args)
int MobileDeviceLib::deviceSecureTransferApplicationPath(
int zero,
AMDeviceRef device,
CFURLRef url,
CFDictionaryRef dict,
AMDeviceSecureInstallApplicationCallback callback,
int args)
{
int returnCode = -1;
if (m_AMDeviceSecureTransferPath)
returnCode = m_AMDeviceSecureTransferPath(zero, device, url, dict, callback, args);
return returnCode;
@@ -381,7 +345,12 @@ int MobileDeviceLib::deviceSecureInstallApplicationBundle(
return returnCode;
}
int MobileDeviceLib::deviceSecureInstallApplication(int zero, AMDeviceRef device, CFURLRef url, CFDictionaryRef options, AMDeviceSecureInstallApplicationCallback callback, int arg)
int MobileDeviceLib::deviceSecureInstallApplication(int zero,
AMDeviceRef device,
CFURLRef url,
CFDictionaryRef options,
AMDeviceSecureInstallApplicationCallback callback,
int arg)
{
int returnCode = -1;
if (m_AMDeviceSecureInstallApplication) {
@@ -390,7 +359,8 @@ int MobileDeviceLib::deviceSecureInstallApplication(int zero, AMDeviceRef device
return returnCode;
}
int MobileDeviceLib::deviceConnectionGetSocket(ServiceConnRef ref) {
int MobileDeviceLib::deviceConnectionGetSocket(ServiceConnRef ref)
{
int fd = 0;
if (m_AMDServiceConnectionGetSocket)
fd = m_AMDServiceConnectionGetSocket(ref);
@@ -428,4 +398,4 @@ bool MobileDeviceLib::deviceIsAtLeastVersionOnPlatform(AMDeviceRef device, CFDic
return false;
}
} // IOS
} // namespace Ios

View File

@@ -180,8 +180,10 @@ public:
QStringList m_errors;
private:
QLibrary lib;
QList<QLibrary *> deps;
template<typename T> void resolveFunction(const char *functionName, T &functionPtr);
private:
QLibrary m_mobileDeviceLib;
AMDSetLogLevelPtr m_AMDSetLogLevel;
AMDeviceNotificationSubscribePtr m_AMDeviceNotificationSubscribe;
AMDeviceNotificationUnsubscribePtr m_AMDeviceNotificationUnsubscribe;