diff options
author | Vikas Pachdha <vikas.pachdha@qt.io> | 2021-03-10 13:20:25 +0100 |
---|---|---|
committer | Vikas Pachdha <vikas.pachdha@qt.io> | 2021-03-16 08:44:39 +0000 |
commit | b152a7287c3655652842a98d97e82da5531818be (patch) | |
tree | 082c1dca41ecedf5b6d1bac0ce27e7678f494ad7 | |
parent | 4d1e3276fc91fbd62d2a18e80fadc01b47d873b8 (diff) |
iOS: Create single instance of mobile device library wrapper
Task-number: QTCREATORBUG-24672
Change-Id: I30f0022735409dbbd03b6bdadf7138ff6294b131
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
-rw-r--r-- | src/tools/iostool/gdbrunner.cpp | 3 | ||||
-rw-r--r-- | src/tools/iostool/iosdevicemanager.cpp | 126 | ||||
-rw-r--r-- | src/tools/iostool/mobiledevicelib.cpp | 13 | ||||
-rw-r--r-- | src/tools/iostool/mobiledevicelib.h | 10 |
4 files changed, 86 insertions, 66 deletions
diff --git a/src/tools/iostool/gdbrunner.cpp b/src/tools/iostool/gdbrunner.cpp index e39d82cac2b..4f4f110c125 100644 --- a/src/tools/iostool/gdbrunner.cpp +++ b/src/tools/iostool/gdbrunner.cpp @@ -61,7 +61,8 @@ void GdbRunner::run() } m_iosTool->outFile.flush(); } - close(m_conn->sockfd); + MobileDeviceLib::instance().serviceConnectionInvalidate(m_conn); + m_conn = nullptr; m_iosTool->doExit(); emit finished(); } diff --git a/src/tools/iostool/iosdevicemanager.cpp b/src/tools/iostool/iosdevicemanager.cpp index 53914f1d590..cab1d69ed3f 100644 --- a/src/tools/iostool/iosdevicemanager.cpp +++ b/src/tools/iostool/iosdevicemanager.cpp @@ -77,12 +77,13 @@ static const QString DebugServiceName = "com.apple.debugserver"; static const QString DebugSecureServiceName = "com.apple.debugserver.DVTSecureSocketProxy"; -static QString mobileDeviceErrorString(MobileDeviceLib *lib, am_res_t code) +static QString mobileDeviceErrorString(am_res_t code) { QString s = QStringLiteral("Unknown error (0x%08x)").arg(code); + MobileDeviceLib &mLib = MobileDeviceLib::instance(); // AMDErrors, 0x0, 0xe8000001-0xe80000db - if (char *ptr = lib->errorString(code)) { + if (char *ptr = mLib.errorString(code)) { CFStringRef key = QString::fromLatin1(ptr).toCFString(); CFURLRef url = QUrl::fromLocalFile( @@ -98,7 +99,7 @@ static QString mobileDeviceErrorString(MobileDeviceLib *lib, am_res_t code) } CFRelease(key); - } else if (CFStringRef str = lib->misErrorStringForErrorCode(code)) { + } else if (CFStringRef str = mLib.misErrorStringForErrorCode(code)) { // MIS errors, 0xe8008001-0xe800801e s = QString::fromCFString(str); CFRelease(str); @@ -254,8 +255,6 @@ public: bool expectGdbOkReply(ServiceConnRef conn); bool startServiceSecure(const QString &serviceName, ServiceConnRef &conn); - MobileDeviceLib *lib(); - AMDeviceRef device; int progressBase; int unexpectedChars; @@ -301,7 +300,6 @@ private: QHash<QString, AMDeviceRef> m_devices; QMultiHash<QString, PendingDeviceLookup *> m_pendingLookups; AMDeviceNotificationRef m_notification; - MobileDeviceLib m_lib; }; class DevInfoSession: public CommandSession { @@ -472,14 +470,8 @@ IosDeviceManagerPrivate::IosDeviceManagerPrivate (IosDeviceManager *q) : q(q), m bool IosDeviceManagerPrivate::watchDevices() { - if (!m_lib.load()) - addError(QLatin1String("Error loading MobileDevice.framework")); - if (!m_lib.errors().isEmpty()) { - foreach (const QString &msg, m_lib.errors()) - addError(msg); - } - m_lib.setLogLevel(5); - am_res_t e = m_lib.deviceNotificationSubscribe(&deviceNotificationCallback, 0, 0, + MobileDeviceLib &mLib = MobileDeviceLib::instance(); + am_res_t e = mLib.deviceNotificationSubscribe(&deviceNotificationCallback, 0, 0, 0, &m_notification); if (e != 0) { addError(QLatin1String("AMDeviceNotificationSubscribe failed")); @@ -508,7 +500,8 @@ void IosDeviceManagerPrivate::requestDeviceInfo(const QString &deviceId, int tim QStringList IosDeviceManagerPrivate::errors() { - return m_lib.errors(); + MobileDeviceLib &mLib = MobileDeviceLib::instance(); + return mLib.errors(); } void IosDeviceManagerPrivate::addError(QString errorMsg) @@ -520,7 +513,8 @@ void IosDeviceManagerPrivate::addError(QString errorMsg) QString IosDeviceManagerPrivate::deviceId(AMDeviceRef device) { - CFStringRef s = m_lib.deviceCopyDeviceIdentifier(device); + MobileDeviceLib &mLib = MobileDeviceLib::instance(); + CFStringRef s = mLib.deviceCopyDeviceIdentifier(device); // remove dashes as a hotfix for QTCREATORBUG-21291 const auto id = QString::fromCFString(s).remove('-'); if (s) CFRelease(s); @@ -532,7 +526,8 @@ void IosDeviceManagerPrivate::addDevice(AMDeviceRef device) const QString devId = deviceId(device); CFRetain(device); - DeviceInterfaceType interfaceType = static_cast<DeviceInterfaceType>(lib()->deviceGetInterfaceType(device)); + MobileDeviceLib &mLib = MobileDeviceLib::instance(); + DeviceInterfaceType interfaceType = static_cast<DeviceInterfaceType>(mLib.deviceGetInterfaceType(device)); if (interfaceType == DeviceInterfaceType::UNKNOWN) { if (debugAll) qDebug() << "Skipping device." << devId << "Interface type: Unknown."; @@ -603,11 +598,6 @@ void IosDeviceManagerPrivate::checkPendingLookups() } } -MobileDeviceLib *IosDeviceManagerPrivate::lib() -{ - return &m_lib; -} - void IosDeviceManagerPrivate::didTransferApp(const QString &bundlePath, const QString &deviceId, IosDeviceManager::OpStatus status) { @@ -782,8 +772,9 @@ void IosDeviceManagerPrivate::stopGdbServer(ServiceConnRef conn, int phase) { CommandSession session((QString())); QMutexLocker l(&m_sendMutex); + MobileDeviceLib &mLib = MobileDeviceLib::instance(); if (phase == 0) - lib()->serviceConnectionSend(conn, "\x03", 1); + mLib.serviceConnectionSend(conn, "\x03", 1); else session.sendGdbCommand(conn, "k", 1); } @@ -801,26 +792,27 @@ bool CommandSession::connectDevice() if (!device) return false; - if (am_res_t error1 = lib()->deviceConnect(device)) { + MobileDeviceLib &mLib = MobileDeviceLib::instance(); + if (am_res_t error1 = mLib.deviceConnect(device)) { addError(QString::fromLatin1("connectDevice %1 failed, AMDeviceConnect returned %2 (0x%3)") - .arg(deviceId).arg(mobileDeviceErrorString(lib(), error1)).arg(error1)); + .arg(deviceId).arg(mobileDeviceErrorString(error1)).arg(error1)); return false; } - if (lib()->deviceIsPaired(device) == 0) { // not paired - if (am_res_t error = lib()->devicePair(device)) { + if (mLib.deviceIsPaired(device) == 0) { // not paired + if (am_res_t error = mLib.devicePair(device)) { addError(QString::fromLatin1("connectDevice %1 failed, AMDevicePair returned %2 (0x%3)") - .arg(deviceId).arg(mobileDeviceErrorString(lib(), error)).arg(error)); + .arg(deviceId).arg(mobileDeviceErrorString(error)).arg(error)); return false; } } - if (am_res_t error2 = lib()->deviceValidatePairing(device)) { + if (am_res_t error2 = mLib.deviceValidatePairing(device)) { addError(QString::fromLatin1("connectDevice %1 failed, AMDeviceValidatePairing returned %2 (0x%3)") - .arg(deviceId).arg(mobileDeviceErrorString(lib(), error2)).arg(error2)); + .arg(deviceId).arg(mobileDeviceErrorString(error2)).arg(error2)); return false; } - if (am_res_t error3 = lib()->deviceStartSession(device)) { + if (am_res_t error3 = mLib.deviceStartSession(device)) { addError(QString::fromLatin1("connectDevice %1 failed, AMDeviceStartSession returned %2 (0x%3)") - .arg(deviceId).arg(mobileDeviceErrorString(lib(), error3)).arg(error3)); + .arg(deviceId).arg(mobileDeviceErrorString(error3)).arg(error3)); return false; } return true; @@ -828,14 +820,15 @@ bool CommandSession::connectDevice() bool CommandSession::disconnectDevice() { - if (am_res_t error = lib()->deviceStopSession(device)) { + MobileDeviceLib &mLib = MobileDeviceLib::instance(); + if (am_res_t error = mLib.deviceStopSession(device)) { addError(QString::fromLatin1("stopSession %1 failed, AMDeviceStopSession returned %2 (0x%3)") - .arg(deviceId).arg(mobileDeviceErrorString(lib(), error)).arg(error)); + .arg(deviceId).arg(mobileDeviceErrorString(error)).arg(error)); return false; } - if (am_res_t error = lib()->deviceDisconnect(device)) { + if (am_res_t error = mLib.deviceDisconnect(device)) { addError(QString::fromLatin1("disconnectDevice %1 failed, AMDeviceDisconnect returned %2 (0x%3)") - .arg(deviceId).arg(mobileDeviceErrorString(lib(), error)).arg(error)); + .arg(deviceId).arg(mobileDeviceErrorString(error)).arg(error)); return false; } return true; @@ -848,9 +841,10 @@ bool CommandSession::startServiceSecure(const QString &serviceName, ServiceConnR // Connect device. AMDeviceConnect + AMDeviceIsPaired + AMDeviceValidatePairing + AMDeviceStartSession if (connectDevice()) { CFStringRef cfsService = serviceName.toCFString(); - if (am_res_t error = lib()->deviceSecureStartService(device, cfsService, &conn)) { + MobileDeviceLib &mLib = MobileDeviceLib::instance(); + if (am_res_t error = mLib.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))); + .arg(serviceName).arg(deviceId).arg(mobileDeviceErrorString(error)).arg(QString::number(error, 16))); success = false; } else { if (!conn) { @@ -877,7 +871,9 @@ bool CommandSession::connectToPort(quint16 port, ServiceSocket *fd) ServiceSocket fileDescriptor; if (!connectDevice()) return false; - if (am_res_t error = lib()->connectByPort(lib()->deviceGetConnectionID(device), htons(port), &fileDescriptor)) { + + MobileDeviceLib &mLib = MobileDeviceLib::instance(); + if (am_res_t error = mLib.connectByPort(mLib.deviceGetConnectionID(device), htons(port), &fileDescriptor)) { addError(QString::fromLatin1("connectByPort on device %1 port %2 failed, AMDeviceStartService returned %3") .arg(deviceId).arg(port).arg(error)); failure = true; @@ -977,13 +973,14 @@ bool CommandSession::mountDeveloperDiskImage() { if (connectDevice()) { CFStringRef cfImgPath = imagePath.toCFString(); - am_res_t result = lib()->deviceMountImage(device, cfImgPath, options, &mountCallback, 0); + MobileDeviceLib &mLib = MobileDeviceLib::instance(); + am_res_t result = mLib.deviceMountImage(device, cfImgPath, options, &mountCallback, 0); if (result == 0 || result == kAMDMobileImageMounterImageMountFailed) { // Mounting succeeded or developer image already installed success = true; } else { addError(QString::fromLatin1("Mount Developer Disk Image \"%1\" failed, AMDeviceMountImage returned %2 (0x%3)") - .arg(imagePath).arg(mobileDeviceErrorString(lib(), result)).arg(QString::number(result, 16))); + .arg(imagePath).arg(mobileDeviceErrorString(result)).arg(QString::number(result, 16))); } CFRelease(cfImgPath); disconnectDevice(); @@ -1007,16 +1004,18 @@ bool CommandSession::sendGdbCommand(ServiceConnRef conn, const char *cmd, qptrdi unsigned char checkSum = 0; for (int i = 0; i < len; ++i) checkSum += static_cast<unsigned char>(cmd[i]); - bool failure = lib()->serviceConnectionSend(conn, "$", 1) == 0; + + MobileDeviceLib &mLib = MobileDeviceLib::instance(); + bool failure = mLib.serviceConnectionSend(conn, "$", 1) == 0; if (!failure) - failure = lib()->serviceConnectionSend(conn, cmd, len) == 0; + failure = mLib.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 = lib()->serviceConnectionSend(conn, buf, 3) == 0; + failure = mLib.serviceConnectionSend(conn, buf, 3) == 0; return !failure; } @@ -1079,8 +1078,10 @@ int CommandSession::handleChar(ServiceConnRef conn, QByteArray &res, char c, int ++unexpectedChars; } } - if (status == 3 && aknowledge) - lib()->serviceConnectionSend(conn, "+", 1); + if (status == 3 && aknowledge) { + MobileDeviceLib &mLib = MobileDeviceLib::instance(); + mLib.serviceConnectionSend(conn, "+", 1); + } return status + 1; case 4: addError(QString::fromLatin1("gone past end in readGdbReply")); @@ -1101,8 +1102,9 @@ QByteArray CommandSession::readGdbReply(ServiceConnRef conn) int maxRetry = 10; int status = 0; int toRead = 4; + MobileDeviceLib &mLib = MobileDeviceLib::instance(); while (status < 4 && toRead > 0) { - qptrdiff nRead = lib()->serviceConnectionReceive(conn, buf, toRead); + qptrdiff nRead = mLib.serviceConnectionReceive(conn, buf, toRead); if (!checkRead(nRead, maxRetry)) return QByteArray(); if (debugGdbServer) { @@ -1167,22 +1169,18 @@ bool CommandSession::expectGdbOkReply(ServiceConnRef conn) return expectGdbReply(conn, QByteArray("OK")); } -MobileDeviceLib *CommandSession::lib() -{ - return IosDeviceManagerPrivate::instance()->lib(); -} - bool CommandSession::developerDiskImagePath(QString *path, QString *signaturePath) { if (device && path && connectDevice()) { - CFPropertyListRef cfProductVersion = lib()->deviceCopyValue(device, 0, CFSTR("ProductVersion")); + MobileDeviceLib &mLib = MobileDeviceLib::instance(); + CFPropertyListRef cfProductVersion = mLib.deviceCopyValue(device, 0, CFSTR("ProductVersion")); QString versionString; if (cfProductVersion && CFGetTypeID(cfProductVersion) == CFStringGetTypeID()) { versionString = QString::fromCFString(reinterpret_cast<CFStringRef>(cfProductVersion)); } CFRelease(cfProductVersion); - CFPropertyListRef cfBuildVersion = lib()->deviceCopyValue(device, 0, CFSTR("BuildVersion")); + CFPropertyListRef cfBuildVersion = mLib.deviceCopyValue(device, 0, CFSTR("BuildVersion")); QString buildString; if (cfBuildVersion && CFGetTypeID(cfBuildVersion) == CFStringGetTypeID()) { buildString = QString::fromCFString(reinterpret_cast<CFStringRef>(cfBuildVersion)); @@ -1225,19 +1223,20 @@ bool AppOpSession::installApp() &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + MobileDeviceLib &mLib = MobileDeviceLib::instance(); // Transfer bundle with secure API AMDeviceTransferApplication. - if (int error = lib()->deviceSecureTransferApplicationPath(0, device, bundleUrl, options, + if (int error = mLib.deviceSecureTransferApplicationPath(0, device, bundleUrl, options, &appSecureTransferSessionCallback,0)) { addError(QString::fromLatin1("TransferAppSession(%1,%2) failed, AMDeviceTransferApplication returned %3 (0x%4)") - .arg(bundlePath, deviceId).arg(mobileDeviceErrorString(lib(), error)).arg(error)); + .arg(bundlePath, deviceId).arg(mobileDeviceErrorString(error)).arg(error)); success = false; } else { // App is transferred. Try installing. if (connectDevice()) { // Secure install app api requires device to be connected. - if (am_res_t error = lib()->deviceSecureInstallApplication(0, device, bundleUrl, options, + if (am_res_t error = mLib.deviceSecureInstallApplication(0, device, bundleUrl, options, &appSecureTransferSessionCallback,0)) { - const QString errorString = mobileDeviceErrorString(lib(), error); + const QString errorString = mobileDeviceErrorString(error); if (!errorString.isEmpty()) { addError(errorString + QStringLiteral(" (0x") @@ -1329,7 +1328,8 @@ bool AppOpSession::runApp() CFDictionaryRef version = CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - bool useSecureProxy = lib()->deviceIsAtLeastVersionOnPlatform(device, version); + MobileDeviceLib &mLib = MobileDeviceLib::instance(); + bool useSecureProxy = mLib.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; @@ -1376,7 +1376,7 @@ bool AppOpSession::runApp() failure = true; } - CFSocketNativeHandle fd = failure ? 0 : lib()->deviceConnectionGetSocket(conn); + CFSocketNativeHandle fd = failure ? 0 : mLib.deviceConnectionGetSocket(conn); auto status = failure ? IosDeviceManager::Failure : IosDeviceManager::Success; IosDeviceManagerPrivate::instance()->didStartApp(bundlePath, deviceId, status, conn, fd, this); return !failure; @@ -1413,7 +1413,8 @@ QString AppOpSession::appPathOnDevice() (const void**)(&lookupKeys), 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFRelease(lookupKeys); - if (int err = lib()->deviceLookupApplications(device, options, &apps)) { + MobileDeviceLib &mLib = MobileDeviceLib::instance(); + if (int err = mLib.deviceLookupApplications(device, options, &apps)) { addError(QString::fromLatin1("app lookup failed, AMDeviceLookupApplications returned %1") .arg(err)); } @@ -1475,7 +1476,8 @@ QString DevInfoSession::getStringValue(AMDevice *device, const QString &fallback) { QString value = fallback; - CFPropertyListRef cfValue = lib()->deviceCopyValue(device, domain, key); + MobileDeviceLib &mLib = MobileDeviceLib::instance(); + CFPropertyListRef cfValue = mLib.deviceCopyValue(device, domain, key); if (cfValue) { if (CFGetTypeID(cfValue) == CFStringGetTypeID()) value = QString::fromCFString(reinterpret_cast<CFStringRef>(cfValue)); diff --git a/src/tools/iostool/mobiledevicelib.cpp b/src/tools/iostool/mobiledevicelib.cpp index 7f18f49a33c..79c4054a0d4 100644 --- a/src/tools/iostool/mobiledevicelib.cpp +++ b/src/tools/iostool/mobiledevicelib.cpp @@ -33,8 +33,21 @@ #endif namespace Ios { +MobileDeviceLib &MobileDeviceLib::instance() +{ + static MobileDeviceLib lib; + return lib; +} + MobileDeviceLib::MobileDeviceLib() { + if (!load()) + addError(QLatin1String("Error loading MobileDevice.framework")); + if (!errors().isEmpty()) { + foreach (const QString &msg, errors()) + addError(msg); + } + setLogLevel(5); } bool MobileDeviceLib::load() diff --git a/src/tools/iostool/mobiledevicelib.h b/src/tools/iostool/mobiledevicelib.h index 37eae664302..97735fdcb1a 100644 --- a/src/tools/iostool/mobiledevicelib.h +++ b/src/tools/iostool/mobiledevicelib.h @@ -111,13 +111,17 @@ typedef bool (MDEV_API *AMDeviceIsAtLeastVersionOnPlatformPtr)(AMDeviceRef, CFDi } class MobileDeviceLib { -public : MobileDeviceLib(); - bool load(); + +public: + MobileDeviceLib( const MobileDeviceLib& ) = delete; + MobileDeviceLib &operator=( const MobileDeviceLib& ) = delete; + + static MobileDeviceLib &instance(); + bool isLoaded(); QStringList errors(); -// void setLogLevel(int i) ; am_res_t deviceNotificationSubscribe(AMDeviceNotificationCallback callback, |