From 4d1e3276fc91fbd62d2a18e80fadc01b47d873b8 Mon Sep 17 00:00:00 2001 From: Vikas Pachdha Date: Sun, 7 Mar 2021 01:07:01 +0100 Subject: [PATCH] iOS: Fix iOS 14 application launch Use service connection to receive and send gdb commands. Communication via socket can no longer be done. Apple introduced this change to plug the security issue when debug session was done over wifi Task-number: QTCREATORBUG-24672 Change-Id: I7ad08242c3b13a2707b6320ee5bc1e18b5f1173d Reviewed-by: Eike Ziller --- src/tools/iostool/gdbrunner.cpp | 11 +- src/tools/iostool/gdbrunner.h | 6 +- src/tools/iostool/iosdevicemanager.cpp | 147 +++++++++++++++---------- src/tools/iostool/iosdevicemanager.h | 6 +- src/tools/iostool/iostool.cpp | 4 +- src/tools/iostool/iostool.h | 2 +- src/tools/iostool/iostooltypes.h | 8 +- src/tools/iostool/mobiledevicelib.cpp | 44 ++++++++ src/tools/iostool/mobiledevicelib.h | 22 +++- 9 files changed, 177 insertions(+), 73 deletions(-) diff --git a/src/tools/iostool/gdbrunner.cpp b/src/tools/iostool/gdbrunner.cpp index 1234a472c3f..e39d82cac2b 100644 --- a/src/tools/iostool/gdbrunner.cpp +++ b/src/tools/iostool/gdbrunner.cpp @@ -26,6 +26,7 @@ #include "gdbrunner.h" #include "iostool.h" +#include "mobiledevicelib.h" #ifdef Q_OS_UNIX #include @@ -34,10 +35,10 @@ namespace Ios { -GdbRunner::GdbRunner(IosTool *iosTool, int gdbFd) : +GdbRunner::GdbRunner(IosTool *iosTool, ServiceConnRef conn) : QObject(nullptr), m_iosTool(iosTool), - m_gdbFd(gdbFd) + m_conn(conn) { } @@ -51,7 +52,7 @@ void GdbRunner::run() } m_iosTool->outFile.flush(); } - Ios::IosDeviceManager::instance()->processGdbServer(m_gdbFd); + Ios::IosDeviceManager::instance()->processGdbServer(m_conn); { QMutexLocker l(&m_iosTool->m_xmlMutex); if (!m_iosTool->splitAppOutput) { @@ -60,14 +61,14 @@ void GdbRunner::run() } m_iosTool->outFile.flush(); } - close(m_gdbFd); + close(m_conn->sockfd); m_iosTool->doExit(); emit finished(); } void GdbRunner::stop(int phase) { - Ios::IosDeviceManager::instance()->stopGdbServer(m_gdbFd, phase); + Ios::IosDeviceManager::instance()->stopGdbServer(m_conn, phase); } } diff --git a/src/tools/iostool/gdbrunner.h b/src/tools/iostool/gdbrunner.h index 27eea4beaf4..77b7ceae97f 100644 --- a/src/tools/iostool/gdbrunner.h +++ b/src/tools/iostool/gdbrunner.h @@ -27,6 +27,8 @@ #include +#include "iostooltypes.h" + namespace Ios { class IosTool; class GdbRunner: public QObject @@ -34,7 +36,7 @@ class GdbRunner: public QObject Q_OBJECT public: - GdbRunner(IosTool *iosTool, int gdbFd); + GdbRunner(IosTool *iosTool, ServiceConnRef conn); void stop(int phase); void run(); @@ -43,6 +45,6 @@ signals: private: IosTool *m_iosTool; - int m_gdbFd; + ServiceConnRef m_conn = nullptr; }; } diff --git a/src/tools/iostool/iosdevicemanager.cpp b/src/tools/iostool/iosdevicemanager.cpp index 1d9b1874ce1..53914f1d590 100644 --- a/src/tools/iostool/iosdevicemanager.cpp +++ b/src/tools/iostool/iosdevicemanager.cpp @@ -45,6 +45,7 @@ #include #include +#include static const bool debugGdbServer = false; static const bool debugAll = false; @@ -200,6 +201,19 @@ static bool findDeveloperDiskImage(const QString &versionStr, const QString &bui return true; } +bool disable_ssl(ServiceConnRef ref) +{ + typedef void (*SSL_free_t)(void*); + static SSL_free_t SSL_free = nullptr; + if (!SSL_free) + SSL_free = (SSL_free_t)dlsym(RTLD_DEFAULT, "SSL_free"); + if (!SSL_free) + return false; + SSL_free(ref->sslContext); + ref->sslContext = nullptr; + return true; +} + extern "C" { typedef void (*DeviceAvailableCallback)(QString deviceId, AMDeviceRef, void *userData); } @@ -234,11 +248,11 @@ public: void addError(const QString &msg); bool writeAll(ServiceSocket fd, const char *cmd, qptrdiff len = -1); bool mountDeveloperDiskImage(); - bool sendGdbCommand(ServiceSocket fd, const char *cmd, qptrdiff len = -1); - QByteArray readGdbReply(ServiceSocket fd); - bool expectGdbReply(ServiceSocket gdbFd, QByteArray expected); - bool expectGdbOkReply(ServiceSocket gdbFd); - bool startServiceSecure(const QString &serviceName, ServiceSocket &fd); + bool sendGdbCommand(ServiceConnRef conn, const char *cmd, qptrdiff len = -1); + QByteArray readGdbReply(ServiceConnRef conn); + bool expectGdbReply(ServiceConnRef conn, QByteArray expected); + bool expectGdbOkReply(ServiceConnRef conn); + bool startServiceSecure(const QString &serviceName, ServiceConnRef &conn); MobileDeviceLib *lib(); @@ -252,7 +266,7 @@ private: private: bool checkRead(qptrdiff nRead, int &maxRetry); - int handleChar(int sock, QByteArray &res, char c, int status); + int handleChar(ServiceConnRef conn, QByteArray &res, char c, int status); }; // ------- IosManagerPrivate interface -------- @@ -275,12 +289,12 @@ public: void didTransferApp(const QString &bundlePath, const QString &deviceId, Ios::IosDeviceManager::OpStatus status); void didStartApp(const QString &bundlePath, const QString &deviceId, - Ios::IosDeviceManager::OpStatus status, int gdbFd, DeviceSession *deviceSession); + Ios::IosDeviceManager::OpStatus status, ServiceConnRef conn, int gdbFd, DeviceSession *deviceSession); void isTransferringApp(const QString &bundlePath, const QString &deviceId, int progress, const QString &info); void deviceWithId(QString deviceId, int timeout, DeviceAvailableCallback callback, void *userData); - int processGdbServer(int fd); - void stopGdbServer(int fd, int phase); + int processGdbServer(ServiceConnRef conn); + void stopGdbServer(ServiceConnRef conn, int phase); private: IosDeviceManager *q; QMutex m_sendMutex; @@ -601,11 +615,11 @@ void IosDeviceManagerPrivate::didTransferApp(const QString &bundlePath, const QS } void IosDeviceManagerPrivate::didStartApp(const QString &bundlePath, const QString &deviceId, - IosDeviceManager::OpStatus status, int gdbFd, - DeviceSession *deviceSession) + IosDeviceManager::OpStatus status, ServiceConnRef conn, + int gdbFd, DeviceSession *deviceSession) { - emit IosDeviceManagerPrivate::instance()->q->didStartApp(bundlePath, deviceId, status, gdbFd, - deviceSession); + emit IosDeviceManagerPrivate::instance()->q->didStartApp(bundlePath, deviceId, status, conn, + gdbFd, deviceSession); } void IosDeviceManagerPrivate::isTransferringApp(const QString &bundlePath, const QString &deviceId, @@ -655,18 +669,18 @@ enum GdbServerStatus { PROTOCOL_UNHANDLED }; -int IosDeviceManagerPrivate::processGdbServer(int fd) +int IosDeviceManagerPrivate::processGdbServer(ServiceConnRef conn) { CommandSession session((QString())); { QMutexLocker l(&m_sendMutex); - session.sendGdbCommand(fd, "vCont;c"); // resume all threads + session.sendGdbCommand(conn, "vCont;c"); // resume all threads } GdbServerStatus state = NORMAL_PROCESS; int maxRetry = 10; int maxSignal = 5; while (state == NORMAL_PROCESS) { - QByteArray repl = session.readGdbReply(fd); + QByteArray repl = session.readGdbReply(conn); int signal = 0; if (repl.size() > 0) { state = PROTOCOL_ERROR; @@ -746,7 +760,7 @@ int IosDeviceManagerPrivate::processGdbServer(int fd) state = NORMAL_PROCESS; // Ctrl-C to kill the process } else { QMutexLocker l(&m_sendMutex); - if (session.sendGdbCommand(fd, "vCont;c")) + if (session.sendGdbCommand(conn, "vCont;c")) state = NORMAL_PROCESS; else break; @@ -764,14 +778,14 @@ int IosDeviceManagerPrivate::processGdbServer(int fd) return state != INFERIOR_EXITED; } -void IosDeviceManagerPrivate::stopGdbServer(int fd, int phase) +void IosDeviceManagerPrivate::stopGdbServer(ServiceConnRef conn, int phase) { CommandSession session((QString())); QMutexLocker l(&m_sendMutex); if (phase == 0) - session.writeAll(fd,"\x03",1); + lib()->serviceConnectionSend(conn, "\x03", 1); else - session.sendGdbCommand(fd, "k", 1); + session.sendGdbCommand(conn, "k", 1); } // ------- ConnectSession implementation -------- @@ -827,21 +841,22 @@ bool CommandSession::disconnectDevice() return true; } -bool CommandSession::startServiceSecure(const QString &serviceName, ServiceSocket &fd) +bool CommandSession::startServiceSecure(const QString &serviceName, ServiceConnRef &conn) { bool success = true; // Connect device. AMDeviceConnect + AMDeviceIsPaired + AMDeviceValidatePairing + AMDeviceStartSession if (connectDevice()) { CFStringRef cfsService = serviceName.toCFString(); - ServiceConnRef ref; - if (am_res_t error = lib()->deviceSecureStartService(device, cfsService, &ref)) { + if (am_res_t error = lib()->deviceSecureStartService(device, cfsService, &conn)) { addError(QString::fromLatin1("Starting(Secure) service \"%1\" on device %2 failed, AMDeviceStartSecureService returned %3 (0x%4)") .arg(serviceName).arg(deviceId).arg(mobileDeviceErrorString(lib(), error)).arg(QString::number(error, 16))); success = false; - fd = 0; } else { - fd = lib()->deviceConnectionGetSocket(ref); + if (!conn) { + addError(QString("Starting(Secure) service \"%1\" on device %2 failed." + "Invalid service connection").arg(serviceName).arg(deviceId)); + } } disconnectDevice(); CFRelease(cfsService); @@ -985,23 +1000,23 @@ bool CommandSession::mountDeveloperDiskImage() { return success; } -bool CommandSession::sendGdbCommand(ServiceSocket fd, const char *cmd, qptrdiff len) +bool CommandSession::sendGdbCommand(ServiceConnRef conn, const char *cmd, qptrdiff len) { if (len == -1) len = strlen(cmd); unsigned char checkSum = 0; for (int i = 0; i < len; ++i) checkSum += static_cast(cmd[i]); - bool failure = !writeAll(fd, "$", 1); + bool failure = lib()->serviceConnectionSend(conn, "$", 1) == 0; if (!failure) - failure = !writeAll(fd, cmd, len); + failure = lib()->serviceConnectionSend(conn, cmd, len) == 0; char buf[3]; buf[0] = '#'; const char *hex = "0123456789abcdef"; buf[1] = hex[(checkSum >> 4) & 0xF]; buf[2] = hex[checkSum & 0xF]; if (!failure) - failure = !writeAll(fd, buf, 3); + failure = lib()->serviceConnectionSend(conn, buf, 3) == 0; return !failure; } @@ -1029,7 +1044,7 @@ bool CommandSession::checkRead(qptrdiff nRead, int &maxRetry) return true; } -int CommandSession::handleChar(int fd, QByteArray &res, char c, int status) +int CommandSession::handleChar(ServiceConnRef conn, QByteArray &res, char c, int status) { switch (status) { case 0: @@ -1065,7 +1080,7 @@ int CommandSession::handleChar(int fd, QByteArray &res, char c, int status) } } if (status == 3 && aknowledge) - writeAll(fd, "+", 1); + lib()->serviceConnectionSend(conn, "+", 1); return status + 1; case 4: addError(QString::fromLatin1("gone past end in readGdbReply")); @@ -1078,7 +1093,7 @@ int CommandSession::handleChar(int fd, QByteArray &res, char c, int status) } } -QByteArray CommandSession::readGdbReply(ServiceSocket fd) +QByteArray CommandSession::readGdbReply(ServiceConnRef conn) { // read with minimal buffering because we might want to give the socket away... QByteArray res; @@ -1087,7 +1102,7 @@ QByteArray CommandSession::readGdbReply(ServiceSocket fd) int status = 0; int toRead = 4; while (status < 4 && toRead > 0) { - qptrdiff nRead = read(fd, buf, toRead); + qptrdiff nRead = lib()->serviceConnectionReceive(conn, buf, toRead); if (!checkRead(nRead, maxRetry)) return QByteArray(); if (debugGdbServer) { @@ -1095,7 +1110,7 @@ QByteArray CommandSession::readGdbReply(ServiceSocket fd) qDebug() << "gdbReply read " << buf; } for (qptrdiff i = 0; i< nRead; ++i) - status = handleChar(fd, res, buf[i], status); + status = handleChar(conn, res, buf[i], status); toRead = 4 - status; } if (status != 4) { @@ -1133,9 +1148,9 @@ QString CommandSession::commandName() return QString::fromLatin1("CommandSession(%1)").arg(deviceId); } -bool CommandSession::expectGdbReply(ServiceSocket gdbFd, QByteArray expected) +bool CommandSession::expectGdbReply(ServiceConnRef conn, QByteArray expected) { - QByteArray repl = readGdbReply(gdbFd); + QByteArray repl = readGdbReply(conn); if (repl != expected) { addError(QString::fromLatin1("Unexpected reply: %1 (%2) vs %3 (%4)") .arg(QString::fromLocal8Bit(repl.constData(), repl.size())) @@ -1147,9 +1162,9 @@ bool CommandSession::expectGdbReply(ServiceSocket gdbFd, QByteArray expected) return true; } -bool CommandSession::expectGdbOkReply(ServiceSocket gdbFd) +bool CommandSession::expectGdbOkReply(ServiceConnRef conn) { - return expectGdbReply(gdbFd, QByteArray("OK")); + return expectGdbReply(conn, QByteArray("OK")); } MobileDeviceLib *CommandSession::lib() @@ -1304,23 +1319,40 @@ bool AppOpSession::runApp() { bool failure = (device == 0); QString exe = appPathOnDevice(); - ServiceSocket gdbFd = -1; if (!mountDeveloperDiskImage()) { addError(QString::fromLatin1("Running app \"%1\" failed. Mount developer disk failed.").arg(bundlePath)); failure = true; } - if (!failure && !startServiceSecure(QLatin1String("com.apple.debugserver"), gdbFd)) - gdbFd = 0; - if (gdbFd > 0) { + CFStringRef keys[] = { CFSTR("MinIPhoneVersion"), CFSTR("MinAppleTVVersion") }; + CFStringRef values[] = { CFSTR("14.0"), CFSTR("14.0")}; + CFDictionaryRef version = CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&values, + 2, &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + bool useSecureProxy = lib()->deviceIsAtLeastVersionOnPlatform(device, version); + // The debugserver service cannot be launched directly on iOS 14+ + // A secure proxy service sits between the actual debugserver service. + const QString &serviceName = useSecureProxy ? DebugSecureServiceName : DebugServiceName; + ServiceConnRef conn = nullptr; + if (!failure) + startServiceSecure(serviceName, conn); + + if (conn) { + // For older devices remove the ssl encryption as we can directly connecting with the + // debugserver service, i.e. not the secure proxy service. + if (!useSecureProxy) + disable_ssl(conn); // gdbServer protocol, see http://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html#Remote-Protocol // and the lldb handling of that (with apple specific stuff) // http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/RNBRemote.cpp //failure = !sendGdbCommand(gdbFd, "QStartNoAckMode"); // avoid and send required aknowledgements? //if (!failure) failure = !expectGdbOkReply(gdbFd); - if (!failure) failure = !sendGdbCommand(gdbFd, "QEnvironmentHexEncoded:"); // send the environment with a series of these commands... - if (!failure) failure = !sendGdbCommand(gdbFd, "QSetDisableASLR:1"); // avoid address randomization to debug - if (!failure) failure = !expectGdbOkReply(gdbFd); + + // send the environment with a series of these commands... + if (!failure) failure = !sendGdbCommand(conn, "QEnvironmentHexEncoded:"); + // avoid address randomization to debug + if (!failure) failure = !sendGdbCommand(conn, "QSetDisableASLR:1"); + if (!failure) failure = !expectGdbOkReply(conn); QStringList args = extraArgs; QByteArray runCommand("A"); args.insert(0, exe); @@ -1336,14 +1368,17 @@ bool AppOpSession::runApp() runCommand.append(','); runCommand.append(arg); } - if (!failure) failure = !sendGdbCommand(gdbFd, runCommand.constData(), runCommand.size()); - if (!failure) failure = !expectGdbOkReply(gdbFd); - if (!failure) failure = !sendGdbCommand(gdbFd, "qLaunchSuccess"); - if (!failure) failure = !expectGdbOkReply(gdbFd); + if (!failure) failure = !sendGdbCommand(conn, runCommand.constData(), runCommand.size()); + if (!failure) failure = !expectGdbOkReply(conn); + if (!failure) failure = !sendGdbCommand(conn, "qLaunchSuccess"); + if (!failure) failure = !expectGdbOkReply(conn); + } else { + failure = true; } - IosDeviceManagerPrivate::instance()->didStartApp( - bundlePath, deviceId, - (failure ? IosDeviceManager::Failure : IosDeviceManager::Success), gdbFd, this); + + CFSocketNativeHandle fd = failure ? 0 : lib()->deviceConnectionGetSocket(conn); + auto status = failure ? IosDeviceManager::Failure : IosDeviceManager::Success; + IosDeviceManagerPrivate::instance()->didStartApp(bundlePath, deviceId, status, conn, fd, this); return !failure; } @@ -1544,14 +1579,14 @@ void IosDeviceManager::requestDeviceInfo(const QString &deviceId, int timeout) d->requestDeviceInfo(deviceId, timeout); } -int IosDeviceManager::processGdbServer(int fd) +int IosDeviceManager::processGdbServer(ServiceConnRef conn) { - return d->processGdbServer(fd); + return d->processGdbServer(conn); } -void IosDeviceManager::stopGdbServer(int fd, int phase) +void IosDeviceManager::stopGdbServer(ServiceConnRef conn, int phase) { - return d->stopGdbServer(fd, phase); + return d->stopGdbServer(conn, phase); } QStringList IosDeviceManager::errors() { diff --git a/src/tools/iostool/iosdevicemanager.h b/src/tools/iostool/iosdevicemanager.h index a16403010a9..7c521c789fd 100644 --- a/src/tools/iostool/iosdevicemanager.h +++ b/src/tools/iostool/iosdevicemanager.h @@ -64,8 +64,8 @@ public: void requestAppOp(const QString &bundlePath, const QStringList &extraArgs, AppOp appOp, const QString &deviceId, int timeout = 1000); void requestDeviceInfo(const QString &deviceId, int timeout = 1000); - int processGdbServer(int fd); - void stopGdbServer(int fd, int phase); + int processGdbServer(ServiceConnRef conn); + void stopGdbServer(ServiceConnRef conn, int phase); QStringList errors(); signals: @@ -76,7 +76,7 @@ signals: void didTransferApp(const QString &bundlePath, const QString &deviceId, Ios::IosDeviceManager::OpStatus status); void didStartApp(const QString &bundlePath, const QString &deviceId, - Ios::IosDeviceManager::OpStatus status, int gdbFd, + Ios::IosDeviceManager::OpStatus status, ServiceConnRef conn, int gdbFd, Ios::DeviceSession *deviceSession); void deviceInfo(const QString &deviceId, const Ios::IosDeviceManager::Dict &info); void appOutput(const QString &output); diff --git a/src/tools/iostool/iostool.cpp b/src/tools/iostool/iostool.cpp index 9123dcec73a..d0be8ede5e9 100644 --- a/src/tools/iostool/iostool.cpp +++ b/src/tools/iostool/iostool.cpp @@ -227,7 +227,7 @@ void IosTool::didTransferApp(const QString &bundlePath, const QString &deviceId, } void IosTool::didStartApp(const QString &bundlePath, const QString &deviceId, - IosDeviceManager::OpStatus status, int gdbFd, + IosDeviceManager::OpStatus status, ServiceConnRef conn, int gdbFd, DeviceSession *deviceSession) { Q_UNUSED(bundlePath) @@ -281,7 +281,7 @@ void IosTool::didStartApp(const QString &bundlePath, const QString &deviceId, outFile.flush(); } if (!debug) { - gdbRunner = new GdbRunner(this, gdbFd); + gdbRunner = new 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(); diff --git a/src/tools/iostool/iostool.h b/src/tools/iostool/iostool.h index 24e78c66810..3519982c9b9 100644 --- a/src/tools/iostool/iostool.h +++ b/src/tools/iostool/iostool.h @@ -63,7 +63,7 @@ private: void didTransferApp(const QString &bundlePath, const QString &deviceId, Ios::IosDeviceManager::OpStatus status); void didStartApp(const QString &bundlePath, const QString &deviceId, - IosDeviceManager::OpStatus status, int gdbFd, + IosDeviceManager::OpStatus status, ServiceConnRef conn, int gdbFd, DeviceSession *deviceSession); void deviceInfo(const QString &deviceId, const Ios::IosDeviceManager::Dict &info); void appOutput(const QString &output); diff --git a/src/tools/iostool/iostooltypes.h b/src/tools/iostool/iostooltypes.h index 766afe143d2..d665ebb44b0 100644 --- a/src/tools/iostool/iostooltypes.h +++ b/src/tools/iostool/iostooltypes.h @@ -31,8 +31,12 @@ #include - extern "C" { +struct service_conn_t { + char unknown[0x10]; + int sockfd; + void *sslContext = nullptr; +}; +typedef service_conn_t *ServiceConnRef; typedef unsigned int ServiceSocket; // match_port_t (i.e. natural_t) or socket (on windows, i.e sock_t) -typedef unsigned int *ServiceConnRef; } // extern C diff --git a/src/tools/iostool/mobiledevicelib.cpp b/src/tools/iostool/mobiledevicelib.cpp index 87ce4fd8d34..7f18f49a33c 100644 --- a/src/tools/iostool/mobiledevicelib.cpp +++ b/src/tools/iostool/mobiledevicelib.cpp @@ -130,6 +130,18 @@ bool MobileDeviceLib::load() if (m_AMDServiceConnectionGetSocket == nullptr) addError("MobileDeviceLib does not define AMDServiceConnectionGetSocket"); m_AMDeviceUninstallApplication = reinterpret_cast(lib.resolve("AMDeviceUninstallApplication")); + m_AMDServiceConnectionSend = reinterpret_cast(lib.resolve("AMDServiceConnectionSend")); + if (m_AMDServiceConnectionSend == nullptr) + addError("MobileDeviceLib does not define AMDServiceConnectionSend"); + m_AMDServiceConnectionReceive = reinterpret_cast(lib.resolve("AMDServiceConnectionReceive")); + if (m_AMDServiceConnectionReceive == nullptr) + addError("MobileDeviceLib does not define AMDServiceConnectionReceive"); + m_AMDServiceConnectionInvalidate = reinterpret_cast(lib.resolve("AMDServiceConnectionInvalidate")); + if (m_AMDServiceConnectionInvalidate == nullptr) + addError("MobileDeviceLib does not define AMDServiceConnectionInvalidate"); + m_AMDeviceIsAtLeastVersionOnPlatform = reinterpret_cast(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(lib.resolve("AMDeviceLookupApplications")); @@ -347,4 +359,36 @@ int MobileDeviceLib::deviceConnectionGetSocket(ServiceConnRef ref) { fd = m_AMDServiceConnectionGetSocket(ref); return fd; } + +int MobileDeviceLib::serviceConnectionSend(ServiceConnRef ref, const void *data, size_t size) +{ + int bytesSent = -1; + if (m_AMDServiceConnectionSend) { + bytesSent = m_AMDServiceConnectionSend(ref, data, size); + } + return bytesSent; +} + +int MobileDeviceLib::serviceConnectionReceive(ServiceConnRef ref, void *data, size_t size) +{ + int bytestRead = 0; + if (m_AMDServiceConnectionReceive) { + bytestRead = m_AMDServiceConnectionReceive(ref, data, size); + } + return bytestRead; +} + +void MobileDeviceLib::serviceConnectionInvalidate(ServiceConnRef serviceConnRef) +{ + if (m_AMDServiceConnectionInvalidate) + m_AMDServiceConnectionInvalidate(serviceConnRef); +} + +bool MobileDeviceLib::deviceIsAtLeastVersionOnPlatform(AMDeviceRef device, CFDictionaryRef versions) +{ + if (m_AMDeviceIsAtLeastVersionOnPlatform) + return m_AMDeviceIsAtLeastVersionOnPlatform(device, versions); + return false; +} + } // IOS diff --git a/src/tools/iostool/mobiledevicelib.h b/src/tools/iostool/mobiledevicelib.h index 7fdac229038..37eae664302 100644 --- a/src/tools/iostool/mobiledevicelib.h +++ b/src/tools/iostool/mobiledevicelib.h @@ -103,6 +103,11 @@ typedef am_res_t (MDEV_API *AMDeviceSecureStartServicePtr)(AMDeviceRef, CFString typedef int (MDEV_API *AMDeviceSecureTransferPathPtr)(int, AMDeviceRef, CFURLRef, CFDictionaryRef, AMDeviceSecureInstallApplicationCallback, int); typedef int (MDEV_API *AMDeviceSecureInstallApplicationPtr)(int, AMDeviceRef, CFURLRef, CFDictionaryRef, AMDeviceSecureInstallApplicationCallback, int); typedef int (MDEV_API *AMDServiceConnectionGetSocketPtr)(ServiceConnRef); + +typedef int (MDEV_API *AMDServiceConnectionSendPtr)(ServiceConnRef, const void *, size_t); +typedef int (MDEV_API *AMDServiceConnectionReceivePtr)(ServiceConnRef, void *, size_t); +typedef void (MDEV_API *AMDServiceConnectionInvalidatePtr)(ServiceConnRef); +typedef bool (MDEV_API *AMDeviceIsAtLeastVersionOnPlatformPtr)(AMDeviceRef, CFDictionaryRef); } class MobileDeviceLib { @@ -147,9 +152,18 @@ public : am_res_t deviceSecureStartService(AMDeviceRef, CFStringRef, ServiceConnRef *); int deviceConnectionGetSocket(ServiceConnRef); int deviceSecureTransferApplicationPath(int, AMDeviceRef, CFURLRef, - CFDictionaryRef, AMDeviceSecureInstallApplicationCallback callback, int); + CFDictionaryRef, + AMDeviceSecureInstallApplicationCallback callback, int); int deviceSecureInstallApplication(int zero, AMDeviceRef device, CFURLRef url, - CFDictionaryRef options, AMDeviceSecureInstallApplicationCallback callback, int arg); + CFDictionaryRef options, + AMDeviceSecureInstallApplicationCallback callback, int arg); + + // Use MobileDevice API's to communicate with service launched on the device. + // The communication is encrypted if ServiceConnRef::sslContext is valid. + int serviceConnectionSend(ServiceConnRef ref, const void *data, size_t size); + int serviceConnectionReceive(ServiceConnRef ref, void *data, size_t size); + void serviceConnectionInvalidate(ServiceConnRef serviceConnRef); + bool deviceIsAtLeastVersionOnPlatform(AMDeviceRef device, CFDictionaryRef versions); QStringList m_errors; @@ -175,6 +189,10 @@ private: AMDeviceSecureTransferPathPtr m_AMDeviceSecureTransferPath; AMDeviceSecureInstallApplicationPtr m_AMDeviceSecureInstallApplication; AMDServiceConnectionGetSocketPtr m_AMDServiceConnectionGetSocket; + AMDServiceConnectionSendPtr m_AMDServiceConnectionSend; + AMDServiceConnectionReceivePtr m_AMDServiceConnectionReceive; + AMDServiceConnectionInvalidatePtr m_AMDServiceConnectionInvalidate; + AMDeviceIsAtLeastVersionOnPlatformPtr m_AMDeviceIsAtLeastVersionOnPlatform; AMDeviceUninstallApplicationPtr m_AMDeviceUninstallApplication; AMDeviceLookupApplicationsPtr m_AMDeviceLookupApplications; AMDErrorStringPtr m_AMDErrorString;