OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <asl.h> | 5 #include <asl.h> |
6 #import <Foundation/Foundation.h> | 6 #import <Foundation/Foundation.h> |
7 #include <libgen.h> | 7 #include <libgen.h> |
8 #include <stdarg.h> | 8 #include <stdarg.h> |
9 #include <stdio.h> | 9 #include <stdio.h> |
10 | 10 |
11 // An executable (iossim) that runs an app in the iOS Simulator. | 11 // An executable (iossim) that runs an app in the iOS Simulator. |
12 // Run 'iossim -h' for usage information. | 12 // Run 'iossim -h' for usage information. |
13 // | 13 // |
14 // For best results, the iOS Simulator application should not be running when | 14 // For best results, the iOS Simulator application should not be running when |
15 // iossim is invoked. | 15 // iossim is invoked. |
16 // | 16 // |
17 // Headers for iPhoneSimulatorRemoteClient and other frameworks used in this | 17 // Headers for iPhoneSimulatorRemoteClient and other frameworks used in this |
18 // tool are generated by class-dump, via GYP. | 18 // tool are generated by class-dump, via GYP. |
19 // (class-dump is available at http://www.codethecode.com/projects/class-dump/) | 19 // (class-dump is available at http://www.codethecode.com/projects/class-dump/) |
20 // | 20 // |
21 // However, there are some forward declarations required to get things to | 21 // However, there are some forward declarations required to get things to |
22 // compile. | 22 // compile. |
23 | 23 |
24 // TODO(lliabraa): Once all builders are on Xcode 6 this ifdef can be removed | |
25 // (crbug.com/385030). | |
26 #if defined(IOSSIM_USE_XCODE_6) | |
27 @class DVTStackBacktrace; | 24 @class DVTStackBacktrace; |
28 #import "DVTFoundation.h" | 25 #import "DVTFoundation.h" |
29 #endif // IOSSIM_USE_XCODE_6 | |
30 | 26 |
31 // TODO(lliabraa): Once all builders are on Xcode 6 this ifdef can be removed | |
32 // (crbug.com/385030). | |
33 #if defined(IOSSIM_USE_XCODE_6) | |
34 @protocol SimBridge; | 27 @protocol SimBridge; |
35 @class DVTSimulatorApplication; | 28 @class DVTSimulatorApplication; |
36 @class SimDeviceSet; | 29 @class SimDeviceSet; |
37 @class SimDeviceType; | 30 @class SimDeviceType; |
38 @class SimProfilesPathMonitor; | 31 @class SimProfilesPathMonitor; |
39 @class SimRuntime; | 32 @class SimRuntime; |
40 @class SimServiceConnectionManager; | 33 @class SimServiceConnectionManager; |
41 #import "CoreSimulator.h" | 34 #import "CoreSimulator.h" |
42 #endif // IOSSIM_USE_XCODE_6 | |
43 | 35 |
44 @interface DVTPlatform : NSObject | 36 @interface DVTPlatform : NSObject |
45 + (BOOL)loadAllPlatformsReturningError:(id*)arg1; | 37 + (BOOL)loadAllPlatformsReturningError:(id*)arg1; |
46 @end | 38 @end |
47 @class DTiPhoneSimulatorApplicationSpecifier; | 39 @class DTiPhoneSimulatorApplicationSpecifier; |
48 @class DTiPhoneSimulatorSession; | 40 @class DTiPhoneSimulatorSession; |
49 @class DTiPhoneSimulatorSessionConfig; | 41 @class DTiPhoneSimulatorSessionConfig; |
50 @class DTiPhoneSimulatorSystemRoot; | 42 @class DTiPhoneSimulatorSystemRoot; |
51 @class DVTConfinementServiceConnection; | 43 @class DVTConfinementServiceConnection; |
52 @class DVTDispatchLock; | 44 @class DVTDispatchLock; |
(...skipping 17 matching lines...) Expand all Loading... |
70 // is the PID of the process the message is about (as opposed to launchd's PID). | 62 // is the PID of the process the message is about (as opposed to launchd's PID). |
71 #define ASL_KEY_REF_PID "RefPID" | 63 #define ASL_KEY_REF_PID "RefPID" |
72 | 64 |
73 namespace { | 65 namespace { |
74 | 66 |
75 // Name of environment variables that control the user's home directory in the | 67 // Name of environment variables that control the user's home directory in the |
76 // simulator. | 68 // simulator. |
77 const char* const kUserHomeEnvVariable = "CFFIXED_USER_HOME"; | 69 const char* const kUserHomeEnvVariable = "CFFIXED_USER_HOME"; |
78 const char* const kHomeEnvVariable = "HOME"; | 70 const char* const kHomeEnvVariable = "HOME"; |
79 | 71 |
80 // Device family codes for iPhone and iPad. | |
81 const int kIPhoneFamily = 1; | |
82 const int kIPadFamily = 2; | |
83 | |
84 // Max number of seconds to wait for the simulator session to start. | 72 // Max number of seconds to wait for the simulator session to start. |
85 // This timeout must allow time to start up iOS Simulator, install the app | 73 // This timeout must allow time to start up iOS Simulator, install the app |
86 // and perform any other black magic that is encoded in the | 74 // and perform any other black magic that is encoded in the |
87 // iPhoneSimulatorRemoteClient framework to kick things off. Normal start up | 75 // iPhoneSimulatorRemoteClient framework to kick things off. Normal start up |
88 // time is only a couple seconds but machine load, disk caches, etc., can all | 76 // time is only a couple seconds but machine load, disk caches, etc., can all |
89 // affect startup time in the wild so the timeout needs to be fairly generous. | 77 // affect startup time in the wild so the timeout needs to be fairly generous. |
90 // If this timeout occurs iossim will likely exit with non-zero status; the | 78 // If this timeout occurs iossim will likely exit with non-zero status; the |
91 // exception being if the app is invoked and completes execution before the | 79 // exception being if the app is invoked and completes execution before the |
92 // session is started (this case is handled in session:didStart:withError). | 80 // session is started (this case is handled in session:didStart:withError). |
93 const NSTimeInterval kDefaultSessionStartTimeoutSeconds = 30; | 81 const NSTimeInterval kDefaultSessionStartTimeoutSeconds = 30; |
(...skipping 17 matching lines...) Expand all Loading... |
111 | 99 |
112 const char* gToolName = "iossim"; | 100 const char* gToolName = "iossim"; |
113 | 101 |
114 // Exit status codes. | 102 // Exit status codes. |
115 const int kExitSuccess = EXIT_SUCCESS; | 103 const int kExitSuccess = EXIT_SUCCESS; |
116 const int kExitFailure = EXIT_FAILURE; | 104 const int kExitFailure = EXIT_FAILURE; |
117 const int kExitInvalidArguments = 2; | 105 const int kExitInvalidArguments = 2; |
118 const int kExitInitializationFailure = 3; | 106 const int kExitInitializationFailure = 3; |
119 const int kExitAppFailedToStart = 4; | 107 const int kExitAppFailedToStart = 4; |
120 const int kExitAppCrashed = 5; | 108 const int kExitAppCrashed = 5; |
121 const int kExitUnsupportedXcodeVersion = 6; | |
122 | 109 |
123 void LogError(NSString* format, ...) { | 110 void LogError(NSString* format, ...) { |
124 va_list list; | 111 va_list list; |
125 va_start(list, format); | 112 va_start(list, format); |
126 | 113 |
127 NSString* message = | 114 NSString* message = |
128 [[[NSString alloc] initWithFormat:format arguments:list] autorelease]; | 115 [[[NSString alloc] initWithFormat:format arguments:list] autorelease]; |
129 | 116 |
130 fprintf(stderr, "%s: ERROR: %s\n", gToolName, [message UTF8String]); | 117 fprintf(stderr, "%s: ERROR: %s\n", gToolName, [message UTF8String]); |
131 fflush(stderr); | 118 fflush(stderr); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
178 LogError(@"Task '%@ %@' exited with return code %d.", | 165 LogError(@"Task '%@ %@' exited with return code %d.", |
179 toolPath, | 166 toolPath, |
180 [args componentsJoinedByString:@" "], | 167 [args componentsJoinedByString:@" "], |
181 [task terminationStatus]); | 168 [task terminationStatus]); |
182 return nil; | 169 return nil; |
183 } | 170 } |
184 return [[[NSString alloc] initWithData:outputData | 171 return [[[NSString alloc] initWithData:outputData |
185 encoding:NSUTF8StringEncoding] autorelease]; | 172 encoding:NSUTF8StringEncoding] autorelease]; |
186 } | 173 } |
187 | 174 |
188 // Finds the Xcode version via xcodebuild -version. Output from xcodebuild is | |
189 // expected to look like: | |
190 // Xcode <version> | |
191 // Build version 5B130a | |
192 // where <version> is the string returned by this function (e.g. 6.0). | |
193 NSString* FindXcodeVersion() { | |
194 NSString* output = GetOutputFromTask(@"/usr/bin/xcodebuild", | |
195 @[ @"-version" ]); | |
196 // Scan past the "Xcode ", then scan the rest of the line into |version|. | |
197 NSScanner* scanner = [NSScanner scannerWithString:output]; | |
198 BOOL valid = [scanner scanString:@"Xcode " intoString:NULL]; | |
199 NSString* version; | |
200 valid = | |
201 [scanner scanUpToCharactersFromSet:[NSCharacterSet newlineCharacterSet] | |
202 intoString:&version]; | |
203 if (!valid) { | |
204 LogError(@"Unable to find Xcode version. 'xcodebuild -version' " | |
205 @"returned \n%@", output); | |
206 return nil; | |
207 } | |
208 return version; | |
209 } | |
210 | |
211 // Returns true if iossim is running with Xcode 6 or later installed on the | |
212 // host. | |
213 BOOL IsRunningWithXcode6OrLater() { | |
214 static NSString* xcodeVersion = FindXcodeVersion(); | |
215 if (!xcodeVersion) { | |
216 return false; | |
217 } | |
218 NSArray* components = [xcodeVersion componentsSeparatedByString:@"."]; | |
219 if ([components count] < 1) { | |
220 return false; | |
221 } | |
222 NSInteger majorVersion = [[components objectAtIndex:0] integerValue]; | |
223 return majorVersion >= 6; | |
224 } | |
225 | |
226 // Prints supported devices and SDKs. | 175 // Prints supported devices and SDKs. |
227 void PrintSupportedDevices() { | 176 void PrintSupportedDevices() { |
228 if (IsRunningWithXcode6OrLater()) { | 177 printf("Supported device/SDK combinations:\n"); |
229 #if defined(IOSSIM_USE_XCODE_6) | 178 Class simDeviceSetClass = FindClassByName(@"SimDeviceSet"); |
230 printf("Supported device/SDK combinations:\n"); | 179 id deviceSet = |
231 Class simDeviceSetClass = FindClassByName(@"SimDeviceSet"); | 180 [simDeviceSetClass setForSetPath:[simDeviceSetClass defaultSetPath]]; |
232 id deviceSet = | 181 for (id simDevice in [deviceSet availableDevices]) { |
233 [simDeviceSetClass setForSetPath:[simDeviceSetClass defaultSetPath]]; | 182 NSString* deviceInfo = |
234 for (id simDevice in [deviceSet availableDevices]) { | 183 [NSString stringWithFormat:@" -d '%@' -s '%@'\n", |
235 NSString* deviceInfo = | 184 [simDevice name], [[simDevice runtime] versionString]]; |
236 [NSString stringWithFormat:@" -d '%@' -s '%@'\n", | 185 printf("%s", [deviceInfo UTF8String]); |
237 [simDevice name], [[simDevice runtime] versionString]]; | |
238 printf("%s", [deviceInfo UTF8String]); | |
239 } | |
240 #endif // IOSSIM_USE_XCODE_6 | |
241 } else { | |
242 printf("Supported SDK versions:\n"); | |
243 Class rootClass = FindClassByName(@"DTiPhoneSimulatorSystemRoot"); | |
244 for (id root in [rootClass knownRoots]) { | |
245 printf(" '%s'\n", [[root sdkVersion] UTF8String]); | |
246 } | |
247 // This is the list of devices supported on Xcode 5.1.x. | |
248 printf("Supported devices:\n"); | |
249 printf(" 'iPhone'\n"); | |
250 printf(" 'iPhone Retina (3.5-inch)'\n"); | |
251 printf(" 'iPhone Retina (4-inch)'\n"); | |
252 printf(" 'iPhone Retina (4-inch 64-bit)'\n"); | |
253 printf(" 'iPad'\n"); | |
254 printf(" 'iPad Retina'\n"); | |
255 printf(" 'iPad Retina (64-bit)'\n"); | |
256 } | 186 } |
257 } | 187 } |
258 } // namespace | 188 } // namespace |
259 | 189 |
260 // A delegate that is called when the simulated app is started or ended in the | 190 // A delegate that is called when the simulated app is started or ended in the |
261 // simulator. | 191 // simulator. |
262 @interface SimulatorDelegate : NSObject <DTiPhoneSimulatorSessionDelegate> { | 192 @interface SimulatorDelegate : NSObject <DTiPhoneSimulatorSessionDelegate> { |
263 @private | 193 @private |
264 NSString* stdioPath_; | 194 NSString* stdioPath_; |
265 NSString* developerDir_; | 195 NSString* developerDir_; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
305 // Reads data from the simulated app's output and writes it to stdout. This | 235 // Reads data from the simulated app's output and writes it to stdout. This |
306 // method blocks, so it should be called in a separate thread. The iOS | 236 // method blocks, so it should be called in a separate thread. The iOS |
307 // Simulator takes a file path for the simulated app's stdout and stderr, but | 237 // Simulator takes a file path for the simulated app's stdout and stderr, but |
308 // this path isn't always available (e.g. when the stdout is Xcode's build | 238 // this path isn't always available (e.g. when the stdout is Xcode's build |
309 // window). As a workaround, iossim creates a temp file to hold output, which | 239 // window). As a workaround, iossim creates a temp file to hold output, which |
310 // this method reads and copies to stdout. | 240 // this method reads and copies to stdout. |
311 - (void)tailOutputForSession:(DTiPhoneSimulatorSession*)session { | 241 - (void)tailOutputForSession:(DTiPhoneSimulatorSession*)session { |
312 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; | 242 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
313 | 243 |
314 NSFileHandle* simio = [NSFileHandle fileHandleForReadingAtPath:stdioPath_]; | 244 NSFileHandle* simio = [NSFileHandle fileHandleForReadingAtPath:stdioPath_]; |
315 if (IsRunningWithXcode6OrLater()) { | 245 NSString* versionString = |
316 #if defined(IOSSIM_USE_XCODE_6) | 246 [[[session sessionConfig] simulatedSystemRoot] sdkVersion]; |
317 // With iOS 8 simulators on Xcode 6, the app output is relative to the | 247 NSInteger majorVersion = [[[versionString componentsSeparatedByString:@"."] |
318 // simulator's data directory. | 248 objectAtIndex:0] intValue]; |
319 NSString* versionString = | 249 if (majorVersion >= 8) { |
320 [[[session sessionConfig] simulatedSystemRoot] sdkVersion]; | 250 NSString* dataPath = session.sessionConfig.device.dataPath; |
321 NSInteger majorVersion = [[[versionString componentsSeparatedByString:@"."] | 251 NSString* appOutput = |
322 objectAtIndex:0] intValue]; | 252 [dataPath stringByAppendingPathComponent:stdioPath_]; |
323 if (majorVersion >= 8) { | 253 simio = [NSFileHandle fileHandleForReadingAtPath:appOutput]; |
324 NSString* dataPath = session.sessionConfig.device.dataPath; | |
325 NSString* appOutput = | |
326 [dataPath stringByAppendingPathComponent:stdioPath_]; | |
327 simio = [NSFileHandle fileHandleForReadingAtPath:appOutput]; | |
328 } | |
329 #endif // IOSSIM_USE_XCODE_6 | |
330 } | 254 } |
331 NSFileHandle* standardOutput = [NSFileHandle fileHandleWithStandardOutput]; | 255 NSFileHandle* standardOutput = [NSFileHandle fileHandleWithStandardOutput]; |
332 // Copy data to stdout/stderr while the app is running. | 256 // Copy data to stdout/stderr while the app is running. |
333 while (appRunning_) { | 257 while (appRunning_) { |
334 NSAutoreleasePool* innerPool = [[NSAutoreleasePool alloc] init]; | 258 NSAutoreleasePool* innerPool = [[NSAutoreleasePool alloc] init]; |
335 [standardOutput writeData:[simio readDataToEndOfFile]]; | 259 [standardOutput writeData:[simio readDataToEndOfFile]]; |
336 [NSThread sleepForTimeInterval:kOutputPollIntervalSeconds]; | 260 [NSThread sleepForTimeInterval:kOutputPollIntervalSeconds]; |
337 [innerPool drain]; | 261 [innerPool drain]; |
338 } | 262 } |
339 | 263 |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
470 LogWarning(@"Console message: %s", message); | 394 LogWarning(@"Console message: %s", message); |
471 // Some messages are harmless, so don't trigger a failure for them. | 395 // Some messages are harmless, so don't trigger a failure for them. |
472 if (strstr(message, "The following job tried to hijack the service")) | 396 if (strstr(message, "The following job tried to hijack the service")) |
473 continue; | 397 continue; |
474 badEntryFound = YES; | 398 badEntryFound = YES; |
475 } | 399 } |
476 } else { | 400 } else { |
477 // Otherwise, the iOS Simulator's system logging is sandboxed, so parse the | 401 // Otherwise, the iOS Simulator's system logging is sandboxed, so parse the |
478 // sandboxed system.log file for known errors. | 402 // sandboxed system.log file for known errors. |
479 NSString* path; | 403 NSString* path; |
480 if (IsRunningWithXcode6OrLater()) { | 404 NSString* dataPath = session.sessionConfig.device.dataPath; |
481 #if defined(IOSSIM_USE_XCODE_6) | 405 path = |
482 NSString* dataPath = session.sessionConfig.device.dataPath; | 406 [dataPath stringByAppendingPathComponent:@"Library/Logs/system.log"]; |
483 path = | |
484 [dataPath stringByAppendingPathComponent:@"Library/Logs/system.log"]; | |
485 #endif // IOSSIM_USE_XCODE_6 | |
486 } else { | |
487 NSString* relativePathToSystemLog = | |
488 [NSString stringWithFormat: | |
489 @"Library/Logs/iOS Simulator/%@/system.log", versionString]; | |
490 path = [simulatorHome_ | |
491 stringByAppendingPathComponent:relativePathToSystemLog]; | |
492 } | |
493 NSFileManager* fileManager = [NSFileManager defaultManager]; | 407 NSFileManager* fileManager = [NSFileManager defaultManager]; |
494 if ([fileManager fileExistsAtPath:path]) { | 408 if ([fileManager fileExistsAtPath:path]) { |
495 NSString* content = | 409 NSString* content = |
496 [NSString stringWithContentsOfFile:path | 410 [NSString stringWithContentsOfFile:path |
497 encoding:NSUTF8StringEncoding | 411 encoding:NSUTF8StringEncoding |
498 error:NULL]; | 412 error:NULL]; |
499 NSArray* lines = [content componentsSeparatedByCharactersInSet: | 413 NSArray* lines = [content componentsSeparatedByCharactersInSet: |
500 [NSCharacterSet newlineCharacterSet]]; | 414 [NSCharacterSet newlineCharacterSet]]; |
501 NSString* simulatedAppPID = | 415 NSString* simulatedAppPID = |
502 [NSString stringWithFormat:@"%d", session.simulatedApplicationPID]; | 416 [NSString stringWithFormat:@"%d", session.simulatedApplicationPID]; |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
579 NSError* error; | 493 NSError* error; |
580 Class DVTPlatformClass = FindClassByName(@"DVTPlatform"); | 494 Class DVTPlatformClass = FindClassByName(@"DVTPlatform"); |
581 if (![DVTPlatformClass loadAllPlatformsReturningError:&error]) { | 495 if (![DVTPlatformClass loadAllPlatformsReturningError:&error]) { |
582 LogError(@"Unable to loadAllPlatformsReturningError. Error: %@", | 496 LogError(@"Unable to loadAllPlatformsReturningError. Error: %@", |
583 [error localizedDescription]); | 497 [error localizedDescription]); |
584 return nil; | 498 return nil; |
585 } | 499 } |
586 | 500 |
587 // The path within the developer dir of the private Simulator frameworks. | 501 // The path within the developer dir of the private Simulator frameworks. |
588 NSString* simulatorFrameworkRelativePath; | 502 NSString* simulatorFrameworkRelativePath; |
589 if (IsRunningWithXcode6OrLater()) { | 503 simulatorFrameworkRelativePath = |
590 simulatorFrameworkRelativePath = | 504 @"../SharedFrameworks/DVTiPhoneSimulatorRemoteClient.framework"; |
591 @"../SharedFrameworks/DVTiPhoneSimulatorRemoteClient.framework"; | 505 NSString* const kCoreSimulatorRelativePath = |
592 NSString* const kCoreSimulatorRelativePath = | 506 @"Library/PrivateFrameworks/CoreSimulator.framework"; |
593 @"Library/PrivateFrameworks/CoreSimulator.framework"; | 507 NSString* coreSimulatorPath = [developerDir |
594 NSString* coreSimulatorPath = [developerDir | 508 stringByAppendingPathComponent:kCoreSimulatorRelativePath]; |
595 stringByAppendingPathComponent:kCoreSimulatorRelativePath]; | 509 NSBundle* coreSimulatorBundle = |
596 NSBundle* coreSimulatorBundle = | 510 [NSBundle bundleWithPath:coreSimulatorPath]; |
597 [NSBundle bundleWithPath:coreSimulatorPath]; | 511 if (![coreSimulatorBundle load]) |
598 if (![coreSimulatorBundle load]) | 512 return nil; |
599 return nil; | |
600 } else { | |
601 simulatorFrameworkRelativePath = | |
602 @"Platforms/iPhoneSimulator.platform/Developer/Library/PrivateFrameworks/" | |
603 @"DVTiPhoneSimulatorRemoteClient.framework"; | |
604 } | |
605 NSString* simBundlePath = [developerDir | 513 NSString* simBundlePath = [developerDir |
606 stringByAppendingPathComponent:simulatorFrameworkRelativePath]; | 514 stringByAppendingPathComponent:simulatorFrameworkRelativePath]; |
607 NSBundle* simBundle = [NSBundle bundleWithPath:simBundlePath]; | 515 NSBundle* simBundle = [NSBundle bundleWithPath:simBundlePath]; |
608 if (![simBundle load]) | 516 if (![simBundle load]) |
609 return nil; | 517 return nil; |
610 return simBundle; | 518 return simBundle; |
611 } | 519 } |
612 | 520 |
613 // Converts the given app path to an application spec, which requires an | 521 // Converts the given app path to an application spec, which requires an |
614 // absolute path. | 522 // absolute path. |
(...skipping 11 matching lines...) Expand all Loading... |
626 exit(kExitInvalidArguments); | 534 exit(kExitInvalidArguments); |
627 } | 535 } |
628 return [applicationSpecifierClass specifierWithApplicationPath:appPath]; | 536 return [applicationSpecifierClass specifierWithApplicationPath:appPath]; |
629 } | 537 } |
630 | 538 |
631 // Returns the system root for the given SDK version. If sdkVersion is nil, the | 539 // Returns the system root for the given SDK version. If sdkVersion is nil, the |
632 // default system root is returned. Will return nil if the sdkVersion is not | 540 // default system root is returned. Will return nil if the sdkVersion is not |
633 // valid. | 541 // valid. |
634 DTiPhoneSimulatorSystemRoot* BuildSystemRoot(NSString* sdkVersion) { | 542 DTiPhoneSimulatorSystemRoot* BuildSystemRoot(NSString* sdkVersion) { |
635 Class systemRootClass = FindClassByName(@"DTiPhoneSimulatorSystemRoot"); | 543 Class systemRootClass = FindClassByName(@"DTiPhoneSimulatorSystemRoot"); |
636 #if defined(IOSSIM_USE_XCODE_6) | |
637 Class simRuntimeClass = FindClassByName(@"SimRuntime"); | 544 Class simRuntimeClass = FindClassByName(@"SimRuntime"); |
638 NSArray* sorted = | 545 NSArray* sorted = |
639 [[simRuntimeClass supportedRuntimes] sortedArrayUsingDescriptors:@[ | 546 [[simRuntimeClass supportedRuntimes] sortedArrayUsingDescriptors:@[ |
640 [NSSortDescriptor sortDescriptorWithKey:@"version" ascending:YES] | 547 [NSSortDescriptor sortDescriptorWithKey:@"version" ascending:YES] |
641 ]]; | 548 ]]; |
642 NSString* versionString = [[sorted lastObject] versionString]; | 549 NSString* versionString = [[sorted lastObject] versionString]; |
643 DTiPhoneSimulatorSystemRoot* systemRoot = | 550 DTiPhoneSimulatorSystemRoot* systemRoot = |
644 [systemRootClass rootWithSDKVersion:versionString]; | 551 [systemRootClass rootWithSDKVersion:versionString]; |
645 #else | |
646 DTiPhoneSimulatorSystemRoot* systemRoot = [systemRootClass defaultRoot]; | |
647 #endif | |
648 if (sdkVersion) | 552 if (sdkVersion) |
649 systemRoot = [systemRootClass rootWithSDKVersion:sdkVersion]; | 553 systemRoot = [systemRootClass rootWithSDKVersion:sdkVersion]; |
650 | 554 |
651 return systemRoot; | 555 return systemRoot; |
652 } | 556 } |
653 | 557 |
654 // Builds a config object for starting the specified app. | 558 // Builds a config object for starting the specified app. |
655 DTiPhoneSimulatorSessionConfig* BuildSessionConfig( | 559 DTiPhoneSimulatorSessionConfig* BuildSessionConfig( |
656 DTiPhoneSimulatorApplicationSpecifier* appSpec, | 560 DTiPhoneSimulatorApplicationSpecifier* appSpec, |
657 DTiPhoneSimulatorSystemRoot* systemRoot, | 561 DTiPhoneSimulatorSystemRoot* systemRoot, |
658 NSString* stdoutPath, | 562 NSString* stdoutPath, |
659 NSString* stderrPath, | 563 NSString* stderrPath, |
660 NSArray* appArgs, | 564 NSArray* appArgs, |
661 NSDictionary* appEnv, | 565 NSDictionary* appEnv, |
662 NSNumber* deviceFamily, | 566 NSNumber* deviceFamily, |
663 NSString* deviceName) { | 567 NSString* deviceName) { |
664 Class sessionConfigClass = FindClassByName(@"DTiPhoneSimulatorSessionConfig"); | 568 Class sessionConfigClass = FindClassByName(@"DTiPhoneSimulatorSessionConfig"); |
665 DTiPhoneSimulatorSessionConfig* sessionConfig = | 569 DTiPhoneSimulatorSessionConfig* sessionConfig = |
666 [[[sessionConfigClass alloc] init] autorelease]; | 570 [[[sessionConfigClass alloc] init] autorelease]; |
667 sessionConfig.applicationToSimulateOnStart = appSpec; | 571 sessionConfig.applicationToSimulateOnStart = appSpec; |
668 sessionConfig.simulatedSystemRoot = systemRoot; | 572 sessionConfig.simulatedSystemRoot = systemRoot; |
669 sessionConfig.localizedClientName = @"chromium"; | 573 sessionConfig.localizedClientName = @"chromium"; |
670 sessionConfig.simulatedApplicationStdErrPath = stderrPath; | 574 sessionConfig.simulatedApplicationStdErrPath = stderrPath; |
671 sessionConfig.simulatedApplicationStdOutPath = stdoutPath; | 575 sessionConfig.simulatedApplicationStdOutPath = stdoutPath; |
672 sessionConfig.simulatedApplicationLaunchArgs = appArgs; | 576 sessionConfig.simulatedApplicationLaunchArgs = appArgs; |
673 sessionConfig.simulatedApplicationLaunchEnvironment = appEnv; | 577 sessionConfig.simulatedApplicationLaunchEnvironment = appEnv; |
674 sessionConfig.simulatedDeviceInfoName = deviceName; | 578 sessionConfig.simulatedDeviceInfoName = deviceName; |
675 sessionConfig.simulatedDeviceFamily = deviceFamily; | 579 sessionConfig.simulatedDeviceFamily = deviceFamily; |
676 | 580 |
677 if (IsRunningWithXcode6OrLater()) { | 581 Class simDeviceTypeClass = FindClassByName(@"SimDeviceType"); |
678 #if defined(IOSSIM_USE_XCODE_6) | 582 id simDeviceType = |
679 Class simDeviceTypeClass = FindClassByName(@"SimDeviceType"); | 583 [simDeviceTypeClass supportedDeviceTypesByAlias][deviceName]; |
680 id simDeviceType = | 584 Class simRuntimeClass = FindClassByName(@"SimRuntime"); |
681 [simDeviceTypeClass supportedDeviceTypesByAlias][deviceName]; | 585 NSString* identifier = systemRoot.runtime.identifier; |
682 Class simRuntimeClass = FindClassByName(@"SimRuntime"); | 586 id simRuntime = [simRuntimeClass supportedRuntimesByIdentifier][identifier]; |
683 NSString* identifier = systemRoot.runtime.identifier; | |
684 id simRuntime = [simRuntimeClass supportedRuntimesByIdentifier][identifier]; | |
685 | 587 |
686 // Attempt to use an existing device, but create one if a suitable match | 588 // Attempt to use an existing device, but create one if a suitable match |
687 // can't be found. For example, if the simulator is running with a | 589 // can't be found. For example, if the simulator is running with a |
688 // non-default home directory (e.g. via iossim's -u command line arg) then | 590 // non-default home directory (e.g. via iossim's -u command line arg) then |
689 // there won't be any devices so one will have to be created. | 591 // there won't be any devices so one will have to be created. |
690 Class simDeviceSetClass = FindClassByName(@"SimDeviceSet"); | 592 Class simDeviceSetClass = FindClassByName(@"SimDeviceSet"); |
691 id deviceSet = | 593 id deviceSet = |
692 [simDeviceSetClass setForSetPath:[simDeviceSetClass defaultSetPath]]; | 594 [simDeviceSetClass setForSetPath:[simDeviceSetClass defaultSetPath]]; |
693 id simDevice = nil; | 595 id simDevice = nil; |
694 for (id device in [deviceSet availableDevices]) { | 596 for (id device in [deviceSet availableDevices]) { |
695 if ([device runtime] == simRuntime && | 597 if ([device runtime] == simRuntime && |
696 [device deviceType] == simDeviceType) { | 598 [device deviceType] == simDeviceType) { |
697 simDevice = device; | 599 simDevice = device; |
698 break; | 600 break; |
699 } | |
700 } | 601 } |
701 if (!simDevice) { | 602 } |
702 NSError* error = nil; | 603 if (!simDevice) { |
703 // n.b. only the device name is necessary because the iOS Simulator menu | 604 NSError* error = nil; |
704 // already splits devices by runtime version. | 605 // n.b. only the device name is necessary because the iOS Simulator menu |
705 NSString* name = [NSString stringWithFormat:@"iossim - %@ ", deviceName]; | 606 // already splits devices by runtime version. |
706 simDevice = [deviceSet createDeviceWithType:simDeviceType | 607 NSString* name = [NSString stringWithFormat:@"iossim - %@ ", deviceName]; |
707 runtime:simRuntime | 608 simDevice = [deviceSet createDeviceWithType:simDeviceType |
708 name:name | 609 runtime:simRuntime |
709 error:&error]; | 610 name:name |
710 if (error) { | 611 error:&error]; |
711 LogError(@"Failed to create device: %@", error); | 612 if (error) { |
712 exit(kExitInitializationFailure); | 613 LogError(@"Failed to create device: %@", error); |
713 } | 614 exit(kExitInitializationFailure); |
714 } | 615 } |
715 sessionConfig.device = simDevice; | |
716 #endif // IOSSIM_USE_XCODE_6 | |
717 } | 616 } |
| 617 sessionConfig.device = simDevice; |
718 return sessionConfig; | 618 return sessionConfig; |
719 } | 619 } |
720 | 620 |
721 // Builds a simulator session that will use the given delegate. | 621 // Builds a simulator session that will use the given delegate. |
722 DTiPhoneSimulatorSession* BuildSession(SimulatorDelegate* delegate) { | 622 DTiPhoneSimulatorSession* BuildSession(SimulatorDelegate* delegate) { |
723 Class sessionClass = FindClassByName(@"DTiPhoneSimulatorSession"); | 623 Class sessionClass = FindClassByName(@"DTiPhoneSimulatorSession"); |
724 DTiPhoneSimulatorSession* session = | 624 DTiPhoneSimulatorSession* session = |
725 [[[sessionClass alloc] init] autorelease]; | 625 [[[sessionClass alloc] init] autorelease]; |
726 session.delegate = delegate; | 626 session.delegate = delegate; |
727 return session; | 627 return session; |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
788 // variable's value if it has already been set. | 688 // variable's value if it has already been set. |
789 if ((setenv(kUserHomeEnvVariable, [userHomePath UTF8String], YES) == -1) || | 689 if ((setenv(kUserHomeEnvVariable, [userHomePath UTF8String], YES) == -1) || |
790 (setenv(kHomeEnvVariable, [userHomePath UTF8String], YES) == -1)) { | 690 (setenv(kHomeEnvVariable, [userHomePath UTF8String], YES) == -1)) { |
791 LogError(@"Unable to set environment variables for home directory."); | 691 LogError(@"Unable to set environment variables for home directory."); |
792 return NO; | 692 return NO; |
793 } | 693 } |
794 | 694 |
795 return YES; | 695 return YES; |
796 } | 696 } |
797 | 697 |
798 // Performs a case-insensitive search to see if |stringToSearch| begins with | |
799 // |prefixToFind|. Returns true if a match is found. | |
800 BOOL CaseInsensitivePrefixSearch(NSString* stringToSearch, | |
801 NSString* prefixToFind) { | |
802 NSStringCompareOptions options = (NSAnchoredSearch | NSCaseInsensitiveSearch); | |
803 NSRange range = [stringToSearch rangeOfString:prefixToFind | |
804 options:options]; | |
805 return range.location != NSNotFound; | |
806 } | |
807 | |
808 // Prints the usage information to stderr. | 698 // Prints the usage information to stderr. |
809 void PrintUsage() { | 699 void PrintUsage() { |
810 fprintf(stderr, "Usage: iossim [-d device] [-s sdkVersion] [-u homeDir] " | 700 fprintf(stderr, "Usage: iossim [-d device] [-s sdkVersion] [-u homeDir] " |
811 "[-e envKey=value]* [-t startupTimeout] <appPath> [<appArgs>]\n" | 701 "[-e envKey=value]* [-t startupTimeout] <appPath> [<appArgs>]\n" |
812 " where <appPath> is the path to the .app directory and appArgs are any" | 702 " where <appPath> is the path to the .app directory and appArgs are any" |
813 " arguments to send the simulated app.\n" | 703 " arguments to send the simulated app.\n" |
814 "\n" | 704 "\n" |
815 "Options:\n" | 705 "Options:\n" |
816 " -d Specifies the device (must be one of the values from the iOS" | 706 " -d Specifies the device (must be one of the values from the iOS" |
817 " Simulator's Hardware -> Device menu. Defaults to 'iPhone'.\n" | 707 " Simulator's Hardware -> Device menu. Defaults to 'iPhone'.\n" |
818 " -s Specifies the SDK version to use (e.g '4.3')." | 708 " -s Specifies the SDK version to use (e.g '4.3')." |
819 " Will use system default if not specified.\n" | 709 " Will use system default if not specified.\n" |
820 " -u Specifies a user home directory for the simulator." | 710 " -u Specifies a user home directory for the simulator." |
821 " Will create a new directory if not specified.\n" | 711 " Will create a new directory if not specified.\n" |
822 " -e Specifies an environment key=value pair that will be" | 712 " -e Specifies an environment key=value pair that will be" |
823 " set in the simulated application's environment.\n" | 713 " set in the simulated application's environment.\n" |
824 " -t Specifies the session startup timeout (in seconds)." | 714 " -t Specifies the session startup timeout (in seconds)." |
825 " Defaults to %d.\n" | 715 " Defaults to %d.\n" |
826 " -l List supported devices and iOS versions.\n", | 716 " -l List supported devices and iOS versions.\n", |
827 static_cast<int>(kDefaultSessionStartTimeoutSeconds)); | 717 static_cast<int>(kDefaultSessionStartTimeoutSeconds)); |
828 } | 718 } |
829 } // namespace | 719 } // namespace |
830 | 720 |
831 void EnsureSupportForCurrentXcodeVersion() { | |
832 if (IsRunningWithXcode6OrLater()) { | |
833 #if !IOSSIM_USE_XCODE_6 | |
834 LogError(@"Running on Xcode 6, but Xcode 6 support was not compiled in."); | |
835 exit(kExitUnsupportedXcodeVersion); | |
836 #endif // IOSSIM_USE_XCODE_6 | |
837 } | |
838 } | |
839 | |
840 int main(int argc, char* const argv[]) { | 721 int main(int argc, char* const argv[]) { |
841 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; | 722 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
842 | 723 |
843 EnsureSupportForCurrentXcodeVersion(); | |
844 | |
845 // basename() may modify the passed in string and it returns a pointer to an | 724 // basename() may modify the passed in string and it returns a pointer to an |
846 // internal buffer. Give it a copy to modify, and copy what it returns. | 725 // internal buffer. Give it a copy to modify, and copy what it returns. |
847 char* worker = strdup(argv[0]); | 726 char* worker = strdup(argv[0]); |
848 char* toolName = basename(worker); | 727 char* toolName = basename(worker); |
849 if (toolName != NULL) { | 728 if (toolName != NULL) { |
850 toolName = strdup(toolName); | 729 toolName = strdup(toolName); |
851 if (toolName != NULL) | 730 if (toolName != NULL) |
852 gToolName = toolName; | 731 gToolName = toolName; |
853 } | 732 } |
854 if (worker != NULL) | 733 if (worker != NULL) |
855 free(worker); | 734 free(worker); |
856 | 735 |
857 NSString* appPath = nil; | 736 NSString* appPath = nil; |
858 NSString* appName = nil; | 737 NSString* appName = nil; |
859 NSString* sdkVersion = nil; | 738 NSString* sdkVersion = nil; |
860 NSString* deviceName = | 739 NSString* deviceName = @"iPhone 5s"; |
861 IsRunningWithXcode6OrLater() ? @"iPhone 5s" : @"iPhone"; | |
862 NSString* simHomePath = nil; | 740 NSString* simHomePath = nil; |
863 NSMutableArray* appArgs = [NSMutableArray array]; | 741 NSMutableArray* appArgs = [NSMutableArray array]; |
864 NSMutableDictionary* appEnv = [NSMutableDictionary dictionary]; | 742 NSMutableDictionary* appEnv = [NSMutableDictionary dictionary]; |
865 NSTimeInterval sessionStartTimeout = kDefaultSessionStartTimeoutSeconds; | 743 NSTimeInterval sessionStartTimeout = kDefaultSessionStartTimeoutSeconds; |
866 | 744 |
867 NSString* developerDir = FindDeveloperDir(); | 745 NSString* developerDir = FindDeveloperDir(); |
868 if (!developerDir) { | 746 if (!developerDir) { |
869 LogError(@"Unable to find developer directory."); | 747 LogError(@"Unable to find developer directory."); |
870 exit(kExitInitializationFailure); | 748 exit(kExitInitializationFailure); |
871 } | 749 } |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
958 exit(kExitInitializationFailure); | 836 exit(kExitInitializationFailure); |
959 } | 837 } |
960 | 838 |
961 // Get the paths for stdout and stderr so the simulated app's output will show | 839 // Get the paths for stdout and stderr so the simulated app's output will show |
962 // up in the caller's stdout/stderr. | 840 // up in the caller's stdout/stderr. |
963 NSString* outputDir = CreateTempDirectory(@"iossim-XXXXXX"); | 841 NSString* outputDir = CreateTempDirectory(@"iossim-XXXXXX"); |
964 NSString* stdioPath = [outputDir stringByAppendingPathComponent:@"stdio.txt"]; | 842 NSString* stdioPath = [outputDir stringByAppendingPathComponent:@"stdio.txt"]; |
965 | 843 |
966 // Determine the deviceFamily based on the deviceName | 844 // Determine the deviceFamily based on the deviceName |
967 NSNumber* deviceFamily = nil; | 845 NSNumber* deviceFamily = nil; |
968 if (IsRunningWithXcode6OrLater()) { | 846 Class simDeviceTypeClass = FindClassByName(@"SimDeviceType"); |
969 #if defined(IOSSIM_USE_XCODE_6) | 847 if ([simDeviceTypeClass supportedDeviceTypesByAlias][deviceName] == nil) { |
970 Class simDeviceTypeClass = FindClassByName(@"SimDeviceType"); | 848 LogError(@"Invalid device name: %@.", deviceName); |
971 if ([simDeviceTypeClass supportedDeviceTypesByAlias][deviceName] == nil) { | 849 PrintSupportedDevices(); |
972 LogError(@"Invalid device name: %@.", deviceName); | 850 exit(kExitInvalidArguments); |
973 PrintSupportedDevices(); | |
974 exit(kExitInvalidArguments); | |
975 } | |
976 #endif // IOSSIM_USE_XCODE_6 | |
977 } else { | |
978 if (!deviceName || CaseInsensitivePrefixSearch(deviceName, @"iPhone")) { | |
979 deviceFamily = [NSNumber numberWithInt:kIPhoneFamily]; | |
980 } else if (CaseInsensitivePrefixSearch(deviceName, @"iPad")) { | |
981 deviceFamily = [NSNumber numberWithInt:kIPadFamily]; | |
982 } | |
983 else { | |
984 LogError(@"Invalid device name: %@. Must begin with 'iPhone' or 'iPad'", | |
985 deviceName); | |
986 exit(kExitInvalidArguments); | |
987 } | |
988 } | 851 } |
989 | 852 |
990 // Set up the user home directory for the simulator only if a non-default | 853 // Set up the user home directory for the simulator only if a non-default |
991 // value was specified. | 854 // value was specified. |
992 if (simHomePath) { | 855 if (simHomePath) { |
993 if (!InitializeSimulatorUserHome(simHomePath)) { | 856 if (!InitializeSimulatorUserHome(simHomePath)) { |
994 LogError(@"Unable to initialize home directory for simulator: %@", | 857 LogError(@"Unable to initialize home directory for simulator: %@", |
995 simHomePath); | 858 simHomePath); |
996 exit(kExitInitializationFailure); | 859 exit(kExitInitializationFailure); |
997 } | 860 } |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1029 [error localizedDescription], | 892 [error localizedDescription], |
1030 [error domain], static_cast<long int>([error code])); | 893 [error domain], static_cast<long int>([error code])); |
1031 } | 894 } |
1032 | 895 |
1033 // Note that this code is only executed if the simulator fails to start | 896 // Note that this code is only executed if the simulator fails to start |
1034 // because once the main run loop is started, only the delegate calling | 897 // because once the main run loop is started, only the delegate calling |
1035 // exit() will end the program. | 898 // exit() will end the program. |
1036 [pool drain]; | 899 [pool drain]; |
1037 return kExitFailure; | 900 return kExitFailure; |
1038 } | 901 } |
OLD | NEW |