forked from qt-creator/qt-creator
Use secure apis and mount developer disk image on device
Add code to find the developer disk image in xcode installation based on the device version and build number Change-Id: Ic05795ad9411ef0f3713c58dc9d286bf6ad1fa19 Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
@@ -51,6 +51,12 @@
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <CoreFoundation/CFRunLoop.h>
|
||||
#include <CoreFoundation/CFDictionary.h>
|
||||
#include <CoreFoundation/CFData.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QProcess>
|
||||
|
||||
#ifdef MOBILE_DEV_DIRECT_LINK
|
||||
#include "MobileDevice.h"
|
||||
@@ -89,9 +95,12 @@ struct AMDeviceNotificationCallbackInfo {
|
||||
};
|
||||
typedef void (MDEV_API *AMDeviceNotificationCallback)(AMDeviceNotificationCallbackInfo *, void *);
|
||||
typedef am_res_t (MDEV_API *AMDeviceInstallApplicationCallback)(CFDictionaryRef, void *);
|
||||
typedef mach_error_t (MDEV_API *AMDeviceSecureInstallApplicationCallback)(CFDictionaryRef, int);
|
||||
|
||||
|
||||
typedef AMDevice *AMDeviceRef;
|
||||
#endif
|
||||
typedef am_res_t (MDEV_API *AMDeviceMountImageCallback)(void *, void *);
|
||||
typedef void (MDEV_API *AMDeviceMountImageCallback)(CFDictionaryRef, int);
|
||||
|
||||
|
||||
|
||||
@@ -113,17 +122,16 @@ typedef am_res_t (MDEV_API *AMDeviceDisconnectPtr)(AMDeviceRef);
|
||||
typedef am_res_t (MDEV_API *AMDeviceMountImagePtr)(AMDeviceRef, CFStringRef, CFDictionaryRef,
|
||||
AMDeviceMountImageCallback, void *);
|
||||
typedef am_res_t (MDEV_API *AMDeviceStartServicePtr)(AMDeviceRef, CFStringRef, ServiceSocket *, void *);
|
||||
typedef am_res_t (MDEV_API *AMDeviceTransferApplicationPtr)(ServiceSocket, CFStringRef, CFDictionaryRef,
|
||||
AMDeviceInstallApplicationCallback,
|
||||
void *);
|
||||
typedef am_res_t (MDEV_API *AMDeviceInstallApplicationPtr)(ServiceSocket, CFStringRef, CFDictionaryRef,
|
||||
AMDeviceInstallApplicationCallback,
|
||||
void*);
|
||||
typedef am_res_t (MDEV_API *AMDeviceUninstallApplicationPtr)(ServiceSocket, CFStringRef, CFDictionaryRef,
|
||||
AMDeviceInstallApplicationCallback,
|
||||
void*);
|
||||
typedef am_res_t (MDEV_API *AMDeviceLookupApplicationsPtr)(AMDeviceRef, CFDictionaryRef, CFDictionaryRef *);
|
||||
typedef am_res_t (MDEV_API *USBMuxConnectByPortPtr)(unsigned int, int, ServiceSocket*);
|
||||
// secure Api's
|
||||
typedef am_res_t (MDEV_API *AMDeviceSecureStartServicePtr)(AMDeviceRef, CFStringRef, void *, ServiceSocket *);
|
||||
typedef int (MDEV_API *AMDeviceSecureTransferPathPtr)(int, AMDeviceRef, CFURLRef, CFDictionaryRef, AMDeviceSecureInstallApplicationCallback, int);
|
||||
typedef int (MDEV_API *AMDeviceSecureInstallApplicationPtr)(int, AMDeviceRef, CFURLRef, CFDictionaryRef, AMDeviceSecureInstallApplicationCallback, int);
|
||||
|
||||
|
||||
} // extern C
|
||||
|
||||
@@ -372,12 +380,6 @@ public :
|
||||
am_res_t deviceMountImage(AMDeviceRef, CFStringRef, CFDictionaryRef,
|
||||
AMDeviceMountImageCallback, void *);
|
||||
am_res_t deviceStartService(AMDeviceRef, CFStringRef, ServiceSocket *, void *);
|
||||
am_res_t deviceTransferApplication(int, CFStringRef, CFDictionaryRef,
|
||||
AMDeviceInstallApplicationCallback,
|
||||
void *);
|
||||
am_res_t deviceInstallApplication(int, CFStringRef, CFDictionaryRef,
|
||||
AMDeviceInstallApplicationCallback,
|
||||
void*);
|
||||
am_res_t deviceUninstallApplication(int, CFStringRef, CFDictionaryRef,
|
||||
AMDeviceInstallApplicationCallback,
|
||||
void*);
|
||||
@@ -386,6 +388,14 @@ public :
|
||||
|
||||
void addError(const QString &msg);
|
||||
void addError(const char *msg);
|
||||
|
||||
// Secure API's
|
||||
am_res_t deviceSecureStartService(AMDeviceRef, CFStringRef, void *, ServiceSocket *);
|
||||
int deviceSecureTransferApplicationPath(int, AMDeviceRef, CFURLRef,
|
||||
CFDictionaryRef, AMDeviceSecureInstallApplicationCallback callback, int);
|
||||
int deviceSecureInstallApplication(int zero, AMDeviceRef device, CFURLRef url,
|
||||
CFDictionaryRef options, AMDeviceSecureInstallApplicationCallback callback, int arg);
|
||||
|
||||
QStringList m_errors;
|
||||
private:
|
||||
QLibrary lib;
|
||||
@@ -405,8 +415,9 @@ private:
|
||||
AMDeviceDisconnectPtr m_AMDeviceDisconnect;
|
||||
AMDeviceMountImagePtr m_AMDeviceMountImage;
|
||||
AMDeviceStartServicePtr m_AMDeviceStartService;
|
||||
AMDeviceTransferApplicationPtr m_AMDeviceTransferApplication;
|
||||
AMDeviceInstallApplicationPtr m_AMDeviceInstallApplication;
|
||||
AMDeviceSecureStartServicePtr m_AMDeviceSecureStartService;
|
||||
AMDeviceSecureTransferPathPtr m_AMDeviceSecureTransferPath;
|
||||
AMDeviceSecureInstallApplicationPtr m_AMDeviceSecureInstallApplication;
|
||||
AMDeviceUninstallApplicationPtr m_AMDeviceUninstallApplication;
|
||||
AMDeviceLookupApplicationsPtr m_AMDeviceLookupApplications;
|
||||
USBMuxConnectByPortPtr m_USBMuxConnectByPort;
|
||||
@@ -446,10 +457,12 @@ public:
|
||||
int qmljsDebugPort() const override;
|
||||
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);
|
||||
|
||||
MobileDeviceLib *lib();
|
||||
|
||||
@@ -457,6 +470,11 @@ public:
|
||||
int progressBase;
|
||||
int unexpectedChars;
|
||||
bool aknowledge;
|
||||
|
||||
private:
|
||||
bool developerDiskImagePath(QString *path, QString *signaturePath);
|
||||
bool findDeveloperDiskImage(QString *diskImagePath, QString versionString, QString buildString);
|
||||
|
||||
private:
|
||||
bool checkRead(qptrdiff nRead, int &maxRetry);
|
||||
int handleChar(int sock, QByteArray &res, char c, int status);
|
||||
@@ -598,6 +616,38 @@ extern "C" am_res_t appTransferSessionCallback(CFDictionaryRef dict, void *userD
|
||||
return session->appTransferCallback(dict);
|
||||
}
|
||||
|
||||
|
||||
extern "C" mach_error_t appSecureTransferSessionCallback(CFDictionaryRef dict, int arg)
|
||||
{
|
||||
Q_UNUSED(arg)
|
||||
CFStringRef cfStatus = reinterpret_cast<CFStringRef>(CFDictionaryGetValue(dict, CFSTR("Status")));
|
||||
const QString status = QString::fromCFString(cfStatus);
|
||||
|
||||
quint32 percent = 0;
|
||||
CFNumberRef cfProgress;
|
||||
if (CFDictionaryGetValueIfPresent(dict, CFSTR("PercentComplete"), reinterpret_cast<const void **>(&cfProgress))) {
|
||||
if (cfProgress && CFGetTypeID(cfProgress) == CFNumberGetTypeID())
|
||||
CFNumberGetValue(cfProgress, kCFNumberSInt32Type, reinterpret_cast<const void **>(&percent));
|
||||
}
|
||||
|
||||
QString path;
|
||||
if (status == "CopyingFile") {
|
||||
CFStringRef cfPath = reinterpret_cast<CFStringRef>(CFDictionaryGetValue(dict, CFSTR("Path")));
|
||||
path = QString::fromCFString(cfPath);
|
||||
}
|
||||
|
||||
if (debugAll) {
|
||||
qDebug() << "["<<percent<<"]" << status << path;
|
||||
} else {
|
||||
static QString oldStatus;
|
||||
if (oldStatus != status) {
|
||||
qDebug() << status;
|
||||
oldStatus = status;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" am_res_t appInstallSessionCallback(CFDictionaryRef dict, void *userData)
|
||||
{
|
||||
if (debugAll) {
|
||||
@@ -936,26 +986,27 @@ bool CommandSession::connectDevice()
|
||||
{
|
||||
if (!device)
|
||||
return false;
|
||||
|
||||
if (am_res_t error1 = lib()->deviceConnect(device)) {
|
||||
addError(QString::fromLatin1("connectDevice %1 failed, AMDeviceConnect returned %2")
|
||||
.arg(deviceId).arg(error1));
|
||||
addError(QString::fromLatin1("connectDevice %1 failed, AMDeviceConnect returned %2 (0x%3)")
|
||||
.arg(deviceId).arg(mobileDeviceErrorString(error1)).arg(error1));
|
||||
return false;
|
||||
}
|
||||
if (lib()->deviceIsPaired(device) == 0) { // not paired
|
||||
if (am_res_t error = lib()->devicePair(device)) {
|
||||
addError(QString::fromLatin1("connectDevice %1 failed, AMDevicePair returned %2")
|
||||
.arg(deviceId).arg(error));
|
||||
addError(QString::fromLatin1("connectDevice %1 failed, AMDevicePair returned %2 (0x%3)")
|
||||
.arg(deviceId).arg(mobileDeviceErrorString(error)).arg(error));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (am_res_t error2 = lib()->deviceValidatePairing(device)) {
|
||||
addError(QString::fromLatin1("connectDevice %1 failed, AMDeviceValidatePairing returned %2")
|
||||
.arg(deviceId).arg(error2));
|
||||
addError(QString::fromLatin1("connectDevice %1 failed, AMDeviceValidatePairing returned %2 (0x%3)")
|
||||
.arg(deviceId).arg(mobileDeviceErrorString(error2)).arg(error2));
|
||||
return false;
|
||||
}
|
||||
if (am_res_t error3 = lib()->deviceStartSession(device)) {
|
||||
addError(QString::fromLatin1("connectDevice %1 failed, AMDeviceStartSession returned %2")
|
||||
.arg(deviceId).arg(error3));
|
||||
addError(QString::fromLatin1("connectDevice %1 failed, AMDeviceStartSession returned %2 (0x%3)")
|
||||
.arg(deviceId).arg(mobileDeviceErrorString(error3)).arg(error3));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -964,13 +1015,13 @@ bool CommandSession::connectDevice()
|
||||
bool CommandSession::disconnectDevice()
|
||||
{
|
||||
if (am_res_t error = lib()->deviceStopSession(device)) {
|
||||
addError(QString::fromLatin1("stopSession %1 failed, AMDeviceStopSession returned %2")
|
||||
.arg(deviceId).arg(error));
|
||||
addError(QString::fromLatin1("stopSession %1 failed, AMDeviceStopSession returned %2 (0x%3)")
|
||||
.arg(deviceId).arg(mobileDeviceErrorString(error)).arg(error));
|
||||
return false;
|
||||
}
|
||||
if (am_res_t error = lib()->deviceDisconnect(device)) {
|
||||
addError(QString::fromLatin1("disconnectDevice %1 failed, AMDeviceDisconnect returned %2")
|
||||
.arg(deviceId).arg(error));
|
||||
addError(QString::fromLatin1("disconnectDevice %1 failed, AMDeviceDisconnect returned %2 (0x%3)")
|
||||
.arg(deviceId).arg(mobileDeviceErrorString(error)).arg(error));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -978,20 +1029,50 @@ bool CommandSession::disconnectDevice()
|
||||
|
||||
bool CommandSession::startService(const QString &serviceName, ServiceSocket &fd)
|
||||
{
|
||||
bool failure = false;
|
||||
fd = 0;
|
||||
if (!connectDevice())
|
||||
return false;
|
||||
CFStringRef cfsService = serviceName.toCFString();
|
||||
if (am_res_t error = lib()->deviceStartService(device, cfsService, &fd, 0)) {
|
||||
addError(QString::fromLatin1("Starting service \"%1\" on device %2 failed, AMDeviceStartService returned %3 (0x%4)")
|
||||
.arg(serviceName).arg(deviceId).arg(mobileDeviceErrorString(error)).arg(QString::number(error, 16)));
|
||||
failure = true;
|
||||
fd = -1;
|
||||
bool success = true;
|
||||
|
||||
// Connect device. AMDeviceConnect + AMDeviceIsPaired + AMDeviceValidatePairing + AMDeviceStartSession
|
||||
if (connectDevice()) {
|
||||
fd = 0;
|
||||
CFStringRef cfsService = serviceName.toCFString();
|
||||
if (am_res_t error = lib()->deviceStartService(device, cfsService, &fd, 0)) {
|
||||
addError(QString::fromLatin1("Starting service \"%1\" on device %2 failed, AMDeviceStartService returned %3 (0x%4)")
|
||||
.arg(serviceName).arg(deviceId).arg(mobileDeviceErrorString(error)).arg(QString::number(error, 16)));
|
||||
success = false;
|
||||
fd = -1;
|
||||
}
|
||||
disconnectDevice();
|
||||
CFRelease(cfsService);
|
||||
} else {
|
||||
addError(QString::fromLatin1("Starting service \"%1\" on device %2 failed. Cannot connect to device.")
|
||||
.arg(serviceName).arg(deviceId));
|
||||
success = false;
|
||||
}
|
||||
CFRelease(cfsService);
|
||||
disconnectDevice();
|
||||
return !failure;
|
||||
return success;
|
||||
}
|
||||
|
||||
bool CommandSession::startServiceSecure(const QString &serviceName, ServiceSocket &fd)
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
// Connect device. AMDeviceConnect + AMDeviceIsPaired + AMDeviceValidatePairing + AMDeviceStartSession
|
||||
if (connectDevice()) {
|
||||
fd = 0;
|
||||
CFStringRef cfsService = serviceName.toCFString();
|
||||
if (am_res_t error = lib()->deviceSecureStartService(device, cfsService, &fd, 0)) {
|
||||
addError(QString::fromLatin1("Starting(Secure) service \"%1\" on device %2 failed, AMDeviceStartSecureService returned %3 (0x%4)")
|
||||
.arg(serviceName).arg(deviceId).arg(mobileDeviceErrorString(error)).arg(QString::number(error, 16)));
|
||||
success = false;
|
||||
fd = -1;
|
||||
}
|
||||
disconnectDevice();
|
||||
CFRelease(cfsService);
|
||||
} else {
|
||||
addError(QString::fromLatin1("Starting(Secure) service \"%1\" on device %2 failed. Cannot connect to device.")
|
||||
.arg(serviceName).arg(deviceId));
|
||||
success = false;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool CommandSession::connectToPort(quint16 port, ServiceSocket *fd)
|
||||
@@ -1076,6 +1157,55 @@ bool CommandSession::writeAll(ServiceSocket fd, const char *cmd, qptrdiff len)
|
||||
return true;
|
||||
}
|
||||
|
||||
void mountCallback(CFDictionaryRef dict, int arg)
|
||||
{
|
||||
Q_UNUSED(arg)
|
||||
CFStringRef cfStatus = reinterpret_cast<CFStringRef>(CFDictionaryGetValue(dict, CFSTR("Status")));
|
||||
qDebug() << "Mounting dev Image :"<<QString::fromCFString(cfStatus);
|
||||
}
|
||||
|
||||
bool CommandSession::mountDeveloperDiskImage() {
|
||||
bool success = false;
|
||||
QString imagePath;
|
||||
QString signaturePath;
|
||||
if (developerDiskImagePath(&imagePath, &signaturePath)) {
|
||||
QFile sigFile(signaturePath);
|
||||
if (sigFile.open(QFile::ReadOnly)) {
|
||||
// Read the signature.
|
||||
const QByteArray signatureData = sigFile.read(128);
|
||||
sigFile.close();
|
||||
|
||||
CFDataRef sig_data = signatureData.toRawCFData();
|
||||
CFTypeRef keys[] = { CFSTR("ImageSignature"), CFSTR("ImageType") };
|
||||
CFTypeRef values[] = { sig_data, CFSTR("Developer") };
|
||||
CFDictionaryRef options = CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&values,
|
||||
2, &kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
|
||||
if (connectDevice()) {
|
||||
CFStringRef cfImgPath = imagePath.toCFString();
|
||||
if (am_res_t result = lib()->deviceMountImage(device, cfImgPath, options, &mountCallback, 0)) {
|
||||
addError(QString::fromLatin1("Mount Developer Disk Image \"%1\" failed, AMDeviceMountImage returned %2 (0x%3)")
|
||||
.arg(imagePath).arg(mobileDeviceErrorString(result)).arg(QString::number(result, 16)));
|
||||
} else {
|
||||
// Mounting succeeded.
|
||||
success = true;
|
||||
}
|
||||
CFRelease(cfImgPath);
|
||||
disconnectDevice();
|
||||
} else
|
||||
addError(QString::fromLatin1("Mount Developer Disk Image \"%1\" failed. Cannot connect to device \"%2\".")
|
||||
.arg(imagePath).arg(deviceId));
|
||||
} else {
|
||||
addError(QString::fromLatin1("Mount Developer Disk Image \"%1\" failed. Unable to open disk image.")
|
||||
.arg(imagePath));
|
||||
}
|
||||
} else {
|
||||
addError(QString::fromLatin1("Mount Developer Disk Image failed. Unable to fetch developer disk image path."));
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool CommandSession::sendGdbCommand(ServiceSocket fd, const char *cmd, qptrdiff len)
|
||||
{
|
||||
if (len == -1)
|
||||
@@ -1248,6 +1378,101 @@ MobileDeviceLib *CommandSession::lib()
|
||||
return IosDeviceManagerPrivate::instance()->lib();
|
||||
}
|
||||
|
||||
bool CommandSession::developerDiskImagePath(QString *path, QString *signaturePath)
|
||||
{
|
||||
bool success = false;
|
||||
if (device && path && connectDevice()) {
|
||||
CFPropertyListRef cfProductVersion = lib()->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"));
|
||||
QString buildString;
|
||||
if (cfBuildVersion && CFGetTypeID(cfBuildVersion) == CFStringGetTypeID()) {
|
||||
buildString = QString::fromCFString(reinterpret_cast<CFStringRef>(cfBuildVersion));
|
||||
}
|
||||
CFRelease(cfBuildVersion);
|
||||
disconnectDevice();
|
||||
|
||||
if (findDeveloperDiskImage(path, versionString, buildString)) {
|
||||
success = QFile::exists(*path);
|
||||
if (success && debugAll)
|
||||
qDebug() << "Developers disk image found at" << path;
|
||||
if (success && signaturePath) {
|
||||
*signaturePath = QString("%1.%2").arg(*path).arg("signature");
|
||||
success = QFile::exists(*signaturePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool CommandSession::findDeveloperDiskImage(QString *diskImagePath, QString versionString, QString buildString)
|
||||
{
|
||||
if (!diskImagePath || versionString.isEmpty())
|
||||
return false;
|
||||
|
||||
*diskImagePath = QString();
|
||||
QProcess process;
|
||||
process.start("/bin/bash", QStringList() << "-c" << "xcode-select -p");
|
||||
if (!process.waitForFinished(3000))
|
||||
addError("Error getting xcode installation path. Command did not finish in time");
|
||||
|
||||
const QString xcodePath = QString::fromLatin1(process.readAllStandardOutput()).trimmed();
|
||||
|
||||
if (process.exitStatus() == QProcess::NormalExit && QFile::exists(xcodePath)) {
|
||||
|
||||
auto imageExists = [xcodePath](QString *foundPath, QString subFolder, QString version, QString build) -> bool {
|
||||
Q_ASSERT(foundPath);
|
||||
const QString subFolderPath = QString("%1/%2").arg(xcodePath).arg(subFolder);
|
||||
if (QFile::exists(subFolderPath)) {
|
||||
*foundPath = QString("%1/%2 (%3)/DeveloperDiskImage.dmg").arg(subFolderPath).arg(version).arg(build);
|
||||
if (QFile::exists(*foundPath)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
QDir subFolderDir(subFolderPath);
|
||||
QStringList nameFilterList;
|
||||
nameFilterList << QString("%1 (*)").arg(version);
|
||||
QFileInfoList builds = subFolderDir.entryInfoList(nameFilterList, QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name | QDir::Reversed);
|
||||
foreach (QFileInfo buildPathInfo, builds) {
|
||||
*foundPath = QString("%1/DeveloperDiskImage.dmg").arg(buildPathInfo.absoluteFilePath());
|
||||
if (QFile::exists(*foundPath)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
*foundPath = QString("%1/%2/DeveloperDiskImage.dmg").arg(subFolderPath).arg(version);
|
||||
if (QFile::exists(*foundPath)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
*foundPath = QString();
|
||||
return false;
|
||||
};
|
||||
|
||||
QStringList versionParts = versionString.split(".", QString::SkipEmptyParts);
|
||||
while (versionParts.count() > 0) {
|
||||
if (imageExists(diskImagePath,"iOS DeviceSupport", versionParts.join("."), buildString))
|
||||
break;
|
||||
if (imageExists(diskImagePath,"Platforms/iPhoneOS.platform/DeviceSupport", versionParts.join("."), buildString))
|
||||
break;
|
||||
|
||||
const QString latestImagePath = QString("%1/Platforms/iPhoneOS.platform/DeviceSupport/Latest/DeveloperDiskImage.dmg").arg(xcodePath);
|
||||
if (QFile::exists(latestImagePath)) {
|
||||
*diskImagePath = latestImagePath;
|
||||
break;
|
||||
}
|
||||
versionParts.removeLast();
|
||||
}
|
||||
}
|
||||
return !diskImagePath->isEmpty();
|
||||
}
|
||||
|
||||
AppOpSession::AppOpSession(const QString &deviceId, const QString &bundlePath,
|
||||
const QStringList &extraArgs, IosDeviceManager::AppOp appOp):
|
||||
CommandSession(deviceId), bundlePath(bundlePath), extraArgs(extraArgs), appOp(appOp)
|
||||
@@ -1260,66 +1485,70 @@ QString AppOpSession::commandName()
|
||||
|
||||
bool AppOpSession::installApp()
|
||||
{
|
||||
ServiceSocket fd;
|
||||
bool failure = (device == 0);
|
||||
if (!failure) {
|
||||
failure = !startService(QLatin1String("com.apple.afc"), fd);
|
||||
if (!failure) {
|
||||
CFStringRef cfsBundlePath = bundlePath.toCFString();
|
||||
if (am_res_t error = lib()->deviceTransferApplication(fd, cfsBundlePath, 0,
|
||||
&appTransferSessionCallback,
|
||||
static_cast<CommandSession *>(this))) {
|
||||
addError(QString::fromLatin1("TransferAppSession(%1,%2) failed, AMDeviceTransferApplication returned %3 (0x%4)")
|
||||
.arg(bundlePath, deviceId).arg(mobileDeviceErrorString(error)).arg(error));
|
||||
failure = true;
|
||||
}
|
||||
progressBase += 100;
|
||||
CFRelease(cfsBundlePath);
|
||||
}
|
||||
stopService(fd);
|
||||
}
|
||||
if (debugAll)
|
||||
qDebug() << "AMDeviceTransferApplication finished request with " << failure;
|
||||
if (!failure) {
|
||||
failure = !startService(QLatin1String("com.apple.mobile.installation_proxy"), fd);
|
||||
if (!failure) {
|
||||
CFStringRef cfsBundlePath = bundlePath.toCFString();
|
||||
bool success = false;
|
||||
if (device != 0) {
|
||||
CFURLRef bundleUrl = QUrl::fromLocalFile(bundlePath).toCFURL();
|
||||
CFStringRef key[1] = {CFSTR("PackageType")};
|
||||
CFStringRef value[1] = {CFSTR("Developer")};
|
||||
CFDictionaryRef options = CFDictionaryCreate(0, reinterpret_cast<const void**>(&key[0]),
|
||||
reinterpret_cast<const void**>(&value[0]), 1,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
|
||||
CFStringRef key[1] = {CFSTR("PackageType")};
|
||||
CFStringRef value[1] = {CFSTR("Developer")};
|
||||
CFDictionaryRef options = CFDictionaryCreate(0, reinterpret_cast<const void**>(&key[0]),
|
||||
reinterpret_cast<const void**>(&value[0]), 1,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
|
||||
if (am_res_t error = lib()->deviceInstallApplication(fd, cfsBundlePath, options,
|
||||
&appInstallSessionCallback,
|
||||
static_cast<CommandSession *>(this))) {
|
||||
const QString errorString = mobileDeviceErrorString(error);
|
||||
if (!errorString.isEmpty())
|
||||
addError(errorString
|
||||
+ QStringLiteral(" (0x")
|
||||
+ QString::number(error, 16)
|
||||
+ QStringLiteral(")"));
|
||||
else
|
||||
addError(QString::fromLatin1("InstallAppSession(%1,%2) failed, "
|
||||
"AMDeviceInstallApplication returned 0x%3")
|
||||
.arg(bundlePath, deviceId).arg(QString::number(error, 16)));
|
||||
failure = true;
|
||||
// Transfer bundle with secure API AMDeviceTransferApplication.
|
||||
if (int error = lib()->deviceSecureTransferApplicationPath(0, device, bundleUrl, options,
|
||||
&appSecureTransferSessionCallback,0)) {
|
||||
addError(QString::fromLatin1("TransferAppSession(%1,%2) failed, AMDeviceTransferApplication returned %3 (0x%4)")
|
||||
.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,
|
||||
&appSecureTransferSessionCallback,0)) {
|
||||
const QString errorString = mobileDeviceErrorString(error);
|
||||
if (!errorString.isEmpty()) {
|
||||
addError(errorString
|
||||
+ QStringLiteral(" (0x")
|
||||
+ QString::number(error, 16)
|
||||
+ QStringLiteral(")"));
|
||||
} else {
|
||||
addError(QString::fromLatin1("InstallAppSession(%1,%2) failed, "
|
||||
"AMDeviceInstallApplication returned 0x%3")
|
||||
.arg(bundlePath, deviceId).arg(QString::number(error, 16)));
|
||||
}
|
||||
success = false;
|
||||
} else {
|
||||
// App is installed.
|
||||
success = true;
|
||||
}
|
||||
disconnectDevice();
|
||||
}
|
||||
progressBase += 100;
|
||||
CFRelease(options);
|
||||
CFRelease(cfsBundlePath);
|
||||
}
|
||||
stopService(fd);
|
||||
|
||||
if (debugAll) {
|
||||
qDebug() << "AMDeviceSecureTransferApplication finished request with " << (success ? "Success" : "Failure");
|
||||
}
|
||||
|
||||
CFRelease(options);
|
||||
CFRelease(bundleUrl);
|
||||
|
||||
progressBase += 100;
|
||||
}
|
||||
if (!failure)
|
||||
|
||||
|
||||
if (success) {
|
||||
sleep(5); // after installation the device needs a bit of quiet....
|
||||
if (debugAll)
|
||||
qDebug() << "AMDeviceInstallApplication finished request with " << failure;
|
||||
}
|
||||
|
||||
if (debugAll) {
|
||||
qDebug() << "AMDeviceSecureInstallApplication finished request with " << (success ? "Success" : "Failure");
|
||||
}
|
||||
|
||||
IosDeviceManagerPrivate::instance()->didTransferApp(bundlePath, deviceId,
|
||||
(failure ? IosDeviceManager::Failure : IosDeviceManager::Success));
|
||||
return !failure;
|
||||
(success ? IosDeviceManager::Success : IosDeviceManager::Failure));
|
||||
return success;
|
||||
}
|
||||
|
||||
void AppOpSession::deviceCallbackReturned()
|
||||
@@ -1354,13 +1583,19 @@ int AppOpSession::qmljsDebugPort() const
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
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 && !startService(QLatin1String("com.apple.debugserver"), gdbFd))
|
||||
gdbFd = -1;
|
||||
|
||||
if (gdbFd > 0) {
|
||||
// gdbServer protocol, see http://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html#Remote-Protocol
|
||||
// and the lldb handling of that (with apple specific stuff)
|
||||
@@ -1648,12 +1883,15 @@ bool MobileDeviceLib::load()
|
||||
m_AMDeviceStartService = reinterpret_cast<AMDeviceStartServicePtr>(lib.resolve("AMDeviceStartService"));
|
||||
if (m_AMDeviceStartService == 0)
|
||||
addError("MobileDeviceLib does not define AMDeviceStartService");
|
||||
m_AMDeviceTransferApplication = reinterpret_cast<AMDeviceTransferApplicationPtr>(lib.resolve("AMDeviceTransferApplication"));
|
||||
if (m_AMDeviceTransferApplication == 0)
|
||||
addError("MobileDeviceLib does not define AMDeviceTransferApplication");
|
||||
m_AMDeviceInstallApplication = reinterpret_cast<AMDeviceInstallApplicationPtr>(lib.resolve("AMDeviceInstallApplication"));
|
||||
if (m_AMDeviceInstallApplication == 0)
|
||||
addError("MobileDeviceLib does not define AMDeviceInstallApplication");
|
||||
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_AMDeviceUninstallApplication = reinterpret_cast<AMDeviceUninstallApplicationPtr>(lib.resolve("AMDeviceUninstallApplication"));
|
||||
if (m_AMDeviceUninstallApplication == 0)
|
||||
addError("MobileDeviceLib does not define AMDeviceUninstallApplication");
|
||||
@@ -1772,7 +2010,7 @@ am_res_t MobileDeviceLib::deviceDisconnect(AMDeviceRef device)
|
||||
am_res_t MobileDeviceLib::deviceMountImage(AMDeviceRef device, CFStringRef imagePath,
|
||||
CFDictionaryRef options,
|
||||
AMDeviceMountImageCallback callback,
|
||||
void * callbackExtraArgs)
|
||||
void *callbackExtraArgs)
|
||||
{
|
||||
if (m_AMDeviceMountImage)
|
||||
return m_AMDeviceMountImage(device, imagePath, options, callback, callbackExtraArgs);
|
||||
@@ -1787,30 +2025,11 @@ am_res_t MobileDeviceLib::deviceStartService(AMDeviceRef device, CFStringRef ser
|
||||
return -1;
|
||||
}
|
||||
|
||||
am_res_t MobileDeviceLib::deviceTransferApplication(int serviceFd, CFStringRef appPath,
|
||||
CFDictionaryRef options,
|
||||
AMDeviceInstallApplicationCallback callback,
|
||||
void *callbackExtraArgs)
|
||||
{
|
||||
if (m_AMDeviceTransferApplication)
|
||||
return m_AMDeviceTransferApplication(serviceFd, appPath, options, callback, callbackExtraArgs);
|
||||
return -1;
|
||||
}
|
||||
|
||||
am_res_t MobileDeviceLib::deviceInstallApplication(int serviceFd, CFStringRef appPath,
|
||||
CFDictionaryRef options,
|
||||
AMDeviceInstallApplicationCallback callback,
|
||||
void *callbackExtraArgs)
|
||||
{
|
||||
if (m_AMDeviceInstallApplication)
|
||||
return m_AMDeviceInstallApplication(serviceFd, appPath, options, callback, callbackExtraArgs);
|
||||
return -1;
|
||||
}
|
||||
|
||||
am_res_t MobileDeviceLib::deviceUninstallApplication(int serviceFd, CFStringRef bundleId,
|
||||
CFDictionaryRef options,
|
||||
AMDeviceInstallApplicationCallback callback,
|
||||
void* callbackExtraArgs)
|
||||
void *callbackExtraArgs)
|
||||
{
|
||||
if (m_AMDeviceUninstallApplication)
|
||||
return m_AMDeviceUninstallApplication(serviceFd, bundleId, options, callback, callbackExtraArgs);
|
||||
@@ -1843,6 +2062,31 @@ void MobileDeviceLib::addError(const char *msg)
|
||||
addError(QLatin1String(msg));
|
||||
}
|
||||
|
||||
am_res_t MobileDeviceLib::deviceSecureStartService(AMDeviceRef device, CFStringRef serviceName, void *extra, ServiceSocket *fdRef)
|
||||
{
|
||||
int returnCode = -1;
|
||||
if (m_AMDeviceSecureStartService)
|
||||
returnCode = m_AMDeviceSecureStartService(device, serviceName, extra, fdRef);
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int MobileDeviceLib::deviceSecureInstallApplication(int zero, AMDeviceRef device, CFURLRef url, CFDictionaryRef options, AMDeviceSecureInstallApplicationCallback callback, int arg)
|
||||
{
|
||||
int returnCode = -1;
|
||||
if (m_AMDeviceSecureInstallApplication) {
|
||||
returnCode = m_AMDeviceSecureInstallApplication(zero, device, url, options, callback, arg);
|
||||
}
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
void CommandSession::internalDeviceAvailableCallback(QString deviceId, AMDeviceRef device)
|
||||
{
|
||||
if (deviceId != this->deviceId && !this->deviceId.isEmpty())
|
||||
|
Reference in New Issue
Block a user