Skip to content

Commit df28c5d

Browse files
committed
add basic support for watchos
1 parent 71f3617 commit df28c5d

File tree

3 files changed

+87
-21
lines changed

3 files changed

+87
-21
lines changed

src/ios-deploy/MobileDevice.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,9 @@ void AMDSetLogLevel(int level);
201201
* MDERR_OUT_OF_MEMORY if we ran out of memory
202202
*/
203203

204-
mach_error_t AMDeviceNotificationSubscribe(am_device_notification_callback
204+
mach_error_t AMDeviceNotificationSubscribeWithOptions(am_device_notification_callback
205205
callback, unsigned int unused0, unsigned int unused1, void* //unsigned int
206-
dn_unknown3, struct am_device_notification **notification);
206+
dn_unknown3, struct am_device_notification **notification, CFDictionaryRef options);
207207

208208

209209
/* Connects to the iPhone. Pass in the am_device structure that the

src/ios-deploy/device_db.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,4 +163,8 @@ device_desc device_db[] = {
163163
ADD_DEVICE("J33IAP", "Apple TV 3.1G", "appletvos", "armv7"),
164164
ADD_DEVICE("J42dAP", "Apple TV 4G", "appletvos", "arm64"),
165165
ADD_DEVICE("J105aAP","Apple TV 4K", "appletvos", "arm64"),
166+
167+
// Apple Watch
168+
ADD_DEVICE("N121sAP","Apple Watch Series 3 (GPS)", "watchos", "armv7k"),
169+
ADD_DEVICE("N157bAP","Apple Watch Series 6", "watchos", "arm64"),
166170
};

src/ios-deploy/ios-deploy.m

Lines changed: 81 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
* log enable -v -f /Users/vargaz/gdb-remote.log gdb-remote all
3131
*/
3232
#define LLDB_PREP_CMDS CFSTR("\
33-
platform select remote-ios --sysroot '{symbols_path}'\n\
33+
platform select remote-'{platform}' --sysroot '{symbols_path}'\n\
3434
target create \"{disk_app}\"\n\
3535
script fruitstrap_device_app=\"{device_app}\"\n\
3636
script fruitstrap_connect_url=\"connect://127.0.0.1:{device_port}\"\n\
@@ -88,6 +88,7 @@
8888
int AMDeviceMountImage(AMDeviceRef device, CFStringRef image, CFDictionaryRef options, void *callback, int cbarg);
8989
mach_error_t AMDeviceLookupApplications(AMDeviceRef device, CFDictionaryRef options, CFDictionaryRef *result);
9090
int AMDeviceGetInterfaceType(AMDeviceRef device);
91+
AMDeviceRef AMDeviceCopyPairedCompanion(AMDeviceRef device);
9192

9293
int AMDServiceConnectionSend(ServiceConnRef con, const void * data, size_t size);
9394
int AMDServiceConnectionReceive(ServiceConnRef con, void * data, size_t size);
@@ -430,7 +431,7 @@ CFStringRef get_device_full_name(const AMDeviceRef device) {
430431
CFRelease(device_name);
431432
if(model != NULL)
432433
CFRelease(model);
433-
if(model_name != NULL)
434+
if(model_name != NULL && model_name != model)
434435
CFRelease(model_name);
435436
if(product_version)
436437
CFRelease(product_version);
@@ -483,13 +484,33 @@ CFStringRef get_device_full_name(const AMDeviceRef device) {
483484
return CFAutorelease(json_dict);
484485
}
485486

487+
int get_companion_interface_type(AMDeviceRef device)
488+
{
489+
assert(AMDeviceGetInterfaceType(device) == 3);
490+
AMDeviceRef companion = AMDeviceCopyPairedCompanion(device);
491+
int type = AMDeviceGetInterfaceType(companion);
492+
AMDeviceRelease(companion);
493+
return type;
494+
}
495+
486496
CFStringRef get_device_interface_name(const AMDeviceRef device) {
487-
// AMDeviceGetInterfaceType(device) 0=Unknown, 1 = Direct/USB, 2 = Indirect/WIFI
497+
// AMDeviceGetInterfaceType(device) 0=Unknown, 1 = Direct/USB, 2 = Indirect/WIFI, 3 = Companion proxy
488498
switch(AMDeviceGetInterfaceType(device)) {
489499
case 1:
490500
return CFSTR("USB");
491501
case 2:
492502
return CFSTR("WIFI");
503+
case 3:
504+
{
505+
if (get_companion_interface_type(device) == 1)
506+
{
507+
return CFSTR("USB Companion proxy");
508+
}
509+
else
510+
{
511+
return CFSTR("WIFI Companion proxy");
512+
}
513+
}
493514
default:
494515
return CFSTR("Unknown Connection");
495516
}
@@ -512,6 +533,7 @@ CFStringRef copy_device_support_path(AMDeviceRef device, CFStringRef suffix) {
512533
CFStringRef build = AMDeviceCopyValue(device, 0, CFSTR("BuildVersion"));
513534
CFStringRef deviceClass = AMDeviceCopyValue(device, 0, CFSTR("DeviceClass"));
514535
CFStringRef deviceModel = AMDeviceCopyValue(device, 0, CFSTR("HardwareModel"));
536+
CFStringRef productType = AMDeviceCopyValue(device, 0, CFSTR("ProductType"));
515537
CFStringRef deviceArch = NULL;
516538
CFStringRef path = NULL;
517539

@@ -531,7 +553,12 @@ CFStringRef copy_device_support_path(AMDeviceRef device, CFStringRef suffix) {
531553
if (CFStringCompare(CFSTR("AppleTV"), deviceClass, 0) == kCFCompareEqualTo) {
532554
deviceClassPath[0] = CFSTR("Platforms/AppleTVOS.platform/DeviceSupport");
533555
deviceClassPath[1] = CFSTR("tvOS DeviceSupport");
534-
} else {
556+
}
557+
else if (CFStringCompare(CFSTR("Watch"), deviceClass, 0) == kCFCompareEqualTo) {
558+
deviceClassPath[0] = CFSTR("Platforms/WatchOS.platform/DeviceSupport");
559+
deviceClassPath[1] = CFSTR("watchOS DeviceSupport");
560+
}
561+
else {
535562
deviceClassPath[0] = CFSTR("Platforms/iPhoneOS.platform/DeviceSupport");
536563
deviceClassPath[1] = CFSTR("iOS DeviceSupport");
537564
}
@@ -569,6 +596,11 @@ CFStringRef copy_device_support_path(AMDeviceRef device, CFStringRef suffix) {
569596
path = copy_xcode_path_for(deviceClassPath[i], search);
570597
CFRelease(search);
571598
}
599+
if (path == NULL) {
600+
CFStringRef search = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@ %@ (%@)/%@"), productType, version, build, suffix);
601+
path = copy_xcode_path_for(deviceClassPath[i], search);
602+
CFRelease(search);
603+
}
572604
}
573605

574606
CFRelease(version);
@@ -589,6 +621,7 @@ CFStringRef copy_device_support_path(AMDeviceRef device, CFStringRef suffix) {
589621
CFRelease(version_parts);
590622
CFRelease(build);
591623
CFRelease(deviceClass);
624+
CFRelease(productType);
592625
if (deviceModel != NULL) {
593626
CFRelease(deviceModel);
594627
}
@@ -823,11 +856,31 @@ CFStringRef copy_modules_search_paths_pairs(CFStringRef symbols_path, CFStringRe
823856
return res;
824857
}
825858

859+
CFStringRef get_device_platform(AMDeviceRef device)
860+
{
861+
CFStringRef deviceClass = AMDeviceCopyValue(device, 0, CFSTR("DeviceClass"));
862+
CFStringRef platform;
863+
if (CFStringCompare(CFSTR("AppleTV"), deviceClass, 0) == kCFCompareEqualTo) {
864+
platform = CFSTR("tvos");
865+
}
866+
else if (CFStringCompare(CFSTR("Watch"), deviceClass, 0) == kCFCompareEqualTo) {
867+
platform = CFSTR("watchos");
868+
}
869+
else {
870+
platform = CFSTR("ios");
871+
}
872+
CFRelease(deviceClass);
873+
return platform;
874+
}
875+
826876
void write_lldb_prep_cmds(AMDeviceRef device, CFURLRef disk_app_url) {
827877
CFStringRef symbols_path = copy_device_support_path(device, CFSTR("Symbols"));
828878
CFMutableStringRef cmds = CFStringCreateMutableCopy(NULL, 0, LLDB_PREP_CMDS);
829879
CFRange range = { 0, CFStringGetLength(cmds) };
830880

881+
CFStringFindAndReplace(cmds, CFSTR("{platform}"), get_device_platform(device), range, 0);
882+
range.length = CFStringGetLength(cmds);
883+
831884
CFStringFindAndReplace(cmds, CFSTR("{symbols_path}"), symbols_path, range, 0);
832885
range.length = CFStringGetLength(cmds);
833886

@@ -1088,9 +1141,9 @@ void start_remote_debug_server(AMDeviceRef device) {
10881141

10891142
dbgServiceConnection = NULL;
10901143
CFStringRef serviceName = CFSTR("com.apple.debugserver");
1091-
CFStringRef keys[] = { CFSTR("MinIPhoneVersion"), CFSTR("MinAppleTVVersion") };
1092-
CFStringRef values[] = { CFSTR("14.0"), CFSTR("14.0")};
1093-
CFDictionaryRef version = CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1144+
CFStringRef keys[] = { CFSTR("MinIPhoneVersion"), CFSTR("MinAppleTVVersion"), CFSTR("MinWatchVersion") };
1145+
CFStringRef values[] = { CFSTR("14.0"), CFSTR("14.0"), CFSTR("7.0") }; // Not sure about older watchOS versions
1146+
CFDictionaryRef version = CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&values, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
10941147

10951148
bool useSecureProxy = AMDeviceIsAtLeastVersionOnPlatform(device, version);
10961149
if (useSecureProxy)
@@ -2003,6 +2056,11 @@ void handle_device(AMDeviceRef device) {
20032056
found_device = true;
20042057
return;
20052058
}
2059+
if (found_device)
2060+
{
2061+
NSLogOut(@"Skipping %@.", device_full_name);
2062+
return;
2063+
}
20062064
CFStringRef found_device_id = CFAutorelease(AMDeviceCopyDeviceIdentifier(device));
20072065
if (device_id != NULL) {
20082066
CFStringRef deviceCFSTR = CFAutorelease(CFStringCreateWithCString(NULL, device_id, kCFStringEncodingUTF8));
@@ -2089,18 +2147,10 @@ void handle_device(AMDeviceRef device) {
20892147

20902148
CFDictionaryRef options;
20912149
if (app_deltas == NULL) { // standard install
2092-
// NOTE: the secure version doesn't seem to require us to start the AFC service
2093-
ServiceConnRef afcFd;
2094-
connect_and_start_session(device);
2095-
check_error(AMDeviceSecureStartService(device, CFSTR("com.apple.afc"), NULL, &afcFd));
2096-
check_error(AMDeviceStopSession(device));
2097-
check_error(AMDeviceDisconnect(device));
2098-
20992150
CFStringRef keys[] = { CFSTR("PackageType") };
21002151
CFStringRef values[] = { CFSTR("Developer") };
21012152
options = CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
21022153
check_error(AMDeviceSecureTransferPath(0, device, url, options, transfer_callback, 0));
2103-
AMDServiceConnectionInvalidate(afcFd);
21042154

21052155
connect_and_start_session(device);
21062156
check_error(AMDeviceSecureInstallApplication(0, device, url, options, install_callback, 0));
@@ -2185,16 +2235,19 @@ void handle_device(AMDeviceRef device) {
21852235
void device_callback(struct am_device_notification_callback_info *info, void *arg) {
21862236
switch (info->msg) {
21872237
case ADNCI_MSG_CONNECTED:
2188-
if (no_wifi && AMDeviceGetInterfaceType(info->dev) == 2)
2238+
{
2239+
int itype = AMDeviceGetInterfaceType(info->dev);
2240+
if (no_wifi && (itype == 2 || ( itype == 3 && get_companion_interface_type(info->dev) == 2)))
21892241
{
2190-
NSLogVerbose(@"Skipping wifi device (type: %d)", AMDeviceGetInterfaceType(info->dev));
2242+
NSLogVerbose(@"Skipping wifi device (type: %d)", itype);
21912243
}
21922244
else
21932245
{
2194-
NSLogVerbose(@"Handling device type: %d", AMDeviceGetInterfaceType(info->dev));
2246+
NSLogVerbose(@"Handling device type: %d", itype);
21952247
handle_device(info->dev);
21962248
}
21972249
break;
2250+
}
21982251
case ADNCI_MSG_DISCONNECTED:
21992252
{
22002253
CFStringRef device_interface_name = get_device_interface_name(info->dev);
@@ -2540,6 +2593,15 @@ int main(int argc, char *argv[]) {
25402593
NSLogOut(@"[....] Waiting for iOS device to be connected");
25412594
}
25422595

2543-
AMDeviceNotificationSubscribe(&device_callback, 0, 0, NULL, &notify);
2596+
2597+
CFStringRef keys[] = {
2598+
CFSTR("NotificationOptionSearchForPairedDevices"),
2599+
};
2600+
const void* values[] = {
2601+
kCFBooleanTrue,
2602+
};
2603+
CFDictionaryRef options = CFDictionaryCreate(kCFAllocatorDefault, (const void**)keys, values, 1, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2604+
2605+
AMDeviceNotificationSubscribeWithOptions(&device_callback, 0, 0, NULL, &notify, options);
25442606
CFRunLoopRun();
25452607
}

0 commit comments

Comments
 (0)