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 #import <Foundation/Foundation.h> | 5 #import <Foundation/Foundation.h> |
6 #include <asl.h> | 6 #include <asl.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 |
(...skipping 10 matching lines...) Expand all Loading... | |
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. Also, the DTiPhoneSimulatorSessionDelegate protocol is referenced | 22 // compile. Also, the DTiPhoneSimulatorSessionDelegate protocol is referenced |
23 // by the iPhoneSimulatorRemoteClient framework, but not defined in the object | 23 // by the iPhoneSimulatorRemoteClient framework, but not defined in the object |
24 // file, so it must be defined here before importing the generated | 24 // file, so it must be defined here before importing the generated |
25 // iPhoneSimulatorRemoteClient.h file. | 25 // iPhoneSimulatorRemoteClient.h file. |
26 | 26 |
27 @class DTiPhoneSimulatorApplicationSpecifier; | 27 @class DTiPhoneSimulatorApplicationSpecifier; |
28 @class DTiPhoneSimulatorSession; | 28 @class DTiPhoneSimulatorSession; |
29 @class DTiPhoneSimulatorSessionConfig; | 29 @class DTiPhoneSimulatorSessionConfig; |
30 @class DTiPhoneSimulatorSystemRoot; | 30 @class DTiPhoneSimulatorSystemRoot; |
31 @class DVTiPhoneSimulatorMessenger; | |
32 | |
33 @interface DVTPlatform : NSObject | |
34 + (BOOL)loadAllPlatformsReturningError:(id *)arg1; | |
35 @end | |
36 | |
37 @protocol OS_dispatch_source | |
38 @end | |
39 @protocol OS_dispatch_queue | |
40 @end | |
41 @class DVTDispatchLock; | |
42 @class DVTConfinementServiceConnection; | |
43 @class DVTTask; | |
31 | 44 |
32 @protocol DTiPhoneSimulatorSessionDelegate | 45 @protocol DTiPhoneSimulatorSessionDelegate |
33 - (void)session:(DTiPhoneSimulatorSession*)session | 46 - (void)session:(DTiPhoneSimulatorSession*)session |
34 didEndWithError:(NSError*)error; | 47 didEndWithError:(NSError*)error; |
35 - (void)session:(DTiPhoneSimulatorSession*)session | 48 - (void)session:(DTiPhoneSimulatorSession*)session |
36 didStart:(BOOL)started | 49 didStart:(BOOL)started |
37 withError:(NSError*)error; | 50 withError:(NSError*)error; |
38 @end | 51 @end |
39 | 52 |
40 #import "iPhoneSimulatorRemoteClient.h" | 53 #import "DVTiPhoneSimulatorRemoteClient.h" |
41 | 54 |
42 // An undocumented system log key included in messages from launchd. The value | 55 // An undocumented system log key included in messages from launchd. The value |
43 // is the PID of the process the message is about (as opposed to launchd's PID). | 56 // is the PID of the process the message is about (as opposed to launchd's PID). |
44 #define ASL_KEY_REF_PID "RefPID" | 57 #define ASL_KEY_REF_PID "RefPID" |
45 | 58 |
46 namespace { | 59 namespace { |
47 | 60 |
48 // Name of environment variables that control the user's home directory in the | 61 // Name of environment variables that control the user's home directory in the |
49 // simulator. | 62 // simulator. |
50 const char* const kUserHomeEnvVariable = "CFFIXED_USER_HOME"; | 63 const char* const kUserHomeEnvVariable = "CFFIXED_USER_HOME"; |
(...skipping 15 matching lines...) Expand all Loading... | |
66 const NSTimeInterval kDefaultSessionStartTimeoutSeconds = 30; | 79 const NSTimeInterval kDefaultSessionStartTimeoutSeconds = 30; |
67 | 80 |
68 // While the simulated app is running, its stdout is redirected to a file which | 81 // While the simulated app is running, its stdout is redirected to a file which |
69 // is polled by iossim and written to iossim's stdout using the following | 82 // is polled by iossim and written to iossim's stdout using the following |
70 // polling interval. | 83 // polling interval. |
71 const NSTimeInterval kOutputPollIntervalSeconds = 0.1; | 84 const NSTimeInterval kOutputPollIntervalSeconds = 0.1; |
72 | 85 |
73 // The path within the developer dir of the private Simulator frameworks. | 86 // The path within the developer dir of the private Simulator frameworks. |
74 NSString* const kSimulatorFrameworkRelativePath = | 87 NSString* const kSimulatorFrameworkRelativePath = |
75 @"Platforms/iPhoneSimulator.platform/Developer/Library/PrivateFrameworks/" | 88 @"Platforms/iPhoneSimulator.platform/Developer/Library/PrivateFrameworks/" |
76 @"iPhoneSimulatorRemoteClient.framework"; | 89 @"DVTiPhoneSimulatorRemoteClient.framework"; |
90 NSString* const kDVTFoundationRelativePath = | |
91 @"../SharedFrameworks/DVTFoundation.framework"; | |
77 NSString* const kDevToolsFoundationRelativePath = | 92 NSString* const kDevToolsFoundationRelativePath = |
78 @"../OtherFrameworks/DevToolsFoundation.framework"; | 93 @"../OtherFrameworks/DevToolsFoundation.framework"; |
79 NSString* const kSimulatorRelativePath = | 94 NSString* const kSimulatorRelativePath = |
80 @"Platforms/iPhoneSimulator.platform/Developer/Applications/" | 95 @"Platforms/iPhoneSimulator.platform/Developer/Applications/" |
81 @"iPhone Simulator.app"; | 96 @"iPhone Simulator.app"; |
82 | 97 |
83 // Simulator Error String Key. This can be found by looking in the Simulator's | 98 // Simulator Error String Key. This can be found by looking in the Simulator's |
84 // Localizable.strings files. | 99 // Localizable.strings files. |
85 NSString* const kSimulatorAppQuitErrorKey = @"The simulated application quit."; | 100 NSString* const kSimulatorAppQuitErrorKey = @"The simulated application quit."; |
86 | 101 |
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
293 objectAtIndex:0] intValue]; | 308 objectAtIndex:0] intValue]; |
294 if (majorVersion <= 6) { | 309 if (majorVersion <= 6) { |
295 // In iOS 6 and before, logging from the simulated apps went to the main | 310 // In iOS 6 and before, logging from the simulated apps went to the main |
296 // system logs, so use ASL to check if the simulated app exited abnormally | 311 // system logs, so use ASL to check if the simulated app exited abnormally |
297 // by looking for system log messages from launchd that refer to the | 312 // by looking for system log messages from launchd that refer to the |
298 // simulated app's PID. Limit query to messages in the last minute since | 313 // simulated app's PID. Limit query to messages in the last minute since |
299 // PIDs are cyclical. | 314 // PIDs are cyclical. |
300 aslmsg query = asl_new(ASL_TYPE_QUERY); | 315 aslmsg query = asl_new(ASL_TYPE_QUERY); |
301 asl_set_query(query, ASL_KEY_SENDER, "launchd", | 316 asl_set_query(query, ASL_KEY_SENDER, "launchd", |
302 ASL_QUERY_OP_EQUAL | ASL_QUERY_OP_SUBSTRING); | 317 ASL_QUERY_OP_EQUAL | ASL_QUERY_OP_SUBSTRING); |
303 asl_set_query(query, ASL_KEY_REF_PID, | 318 asl_set_query( |
304 [[[session simulatedApplicationPID] stringValue] UTF8String], | 319 query, |
305 ASL_QUERY_OP_EQUAL); | 320 ASL_KEY_REF_PID, |
321 [[NSString stringWithFormat:@"%d", [session simulatedApplicationPID]] | |
lliabraa
2013/12/12 15:01:15
why change from stringValue to stringWithFormat?
justincohen
2013/12/12 15:02:03
Because it's not a NSNumber anymore, it's an int.
TVL
2013/12/12 16:08:27
This whole thing would be less scary with a char[2
justincohen
2013/12/16 18:44:37
Done, converted to snprintf.
On 2013/12/12 16:08:
| |
322 UTF8String], | |
323 ASL_QUERY_OP_EQUAL); | |
306 asl_set_query(query, ASL_KEY_TIME, "-1m", ASL_QUERY_OP_GREATER_EQUAL); | 324 asl_set_query(query, ASL_KEY_TIME, "-1m", ASL_QUERY_OP_GREATER_EQUAL); |
307 | 325 |
308 // Log any messages found, and take note of any messages that may indicate | 326 // Log any messages found, and take note of any messages that may indicate |
309 // the app crashed or did not exit cleanly. | 327 // the app crashed or did not exit cleanly. |
310 aslresponse response = asl_search(NULL, query); | 328 aslresponse response = asl_search(NULL, query); |
311 aslmsg entry; | 329 aslmsg entry; |
312 while ((entry = aslresponse_next(response)) != NULL) { | 330 while ((entry = aslresponse_next(response)) != NULL) { |
313 const char* message = asl_get(entry, ASL_KEY_MSG); | 331 const char* message = asl_get(entry, ASL_KEY_MSG); |
314 LogWarning(@"Console message: %s", message); | 332 LogWarning(@"Console message: %s", message); |
315 // Some messages are harmless, so don't trigger a failure for them. | 333 // Some messages are harmless, so don't trigger a failure for them. |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
386 NSString* output = | 404 NSString* output = |
387 [[[NSString alloc] initWithData:outputData | 405 [[[NSString alloc] initWithData:outputData |
388 encoding:NSUTF8StringEncoding] autorelease]; | 406 encoding:NSUTF8StringEncoding] autorelease]; |
389 output = [output stringByTrimmingCharactersInSet: | 407 output = [output stringByTrimmingCharactersInSet: |
390 [NSCharacterSet whitespaceAndNewlineCharacterSet]]; | 408 [NSCharacterSet whitespaceAndNewlineCharacterSet]]; |
391 if ([output length] == 0) | 409 if ([output length] == 0) |
392 output = nil; | 410 output = nil; |
393 return output; | 411 return output; |
394 } | 412 } |
395 | 413 |
414 // Helper to find a class by name and die if it isn't found. | |
TVL
2013/12/12 16:08:27
any reason this got moved?
justincohen
2013/12/16 18:44:37
Forward declaration.
On 2013/12/12 16:08:27, TVL
| |
415 Class FindClassByName(NSString* nameOfClass) { | |
416 Class theClass = NSClassFromString(nameOfClass); | |
417 if (!theClass) { | |
418 LogError(@"Failed to find class %@ at runtime.", nameOfClass); | |
419 exit(kExitInitializationFailure); | |
420 } | |
421 return theClass; | |
422 } | |
423 | |
396 // Loads the Simulator framework from the given developer dir. | 424 // Loads the Simulator framework from the given developer dir. |
397 NSBundle* LoadSimulatorFramework(NSString* developerDir) { | 425 NSBundle* LoadSimulatorFramework(NSString* developerDir) { |
398 // The Simulator framework depends on some of the other Xcode private | 426 // The Simulator framework depends on some of the other Xcode private |
399 // frameworks; manually load them first so everything can be linked up. | 427 // frameworks; manually load them first so everything can be linked up. |
428 NSString* dvtFoundationPath = [developerDir | |
429 stringByAppendingPathComponent:kDVTFoundationRelativePath]; | |
430 NSBundle* dvtFoundationBundle = | |
431 [NSBundle bundleWithPath:dvtFoundationPath]; | |
432 if (![dvtFoundationBundle load]) | |
433 return nil; | |
434 | |
400 NSString* devToolsFoundationPath = [developerDir | 435 NSString* devToolsFoundationPath = [developerDir |
401 stringByAppendingPathComponent:kDevToolsFoundationRelativePath]; | 436 stringByAppendingPathComponent:kDevToolsFoundationRelativePath]; |
402 NSBundle* devToolsFoundationBundle = | 437 NSBundle* devToolsFoundationBundle = |
403 [NSBundle bundleWithPath:devToolsFoundationPath]; | 438 [NSBundle bundleWithPath:devToolsFoundationPath]; |
404 if (![devToolsFoundationBundle load]) | 439 if (![devToolsFoundationBundle load]) |
405 return nil; | 440 return nil; |
441 | |
442 // Prime DVTPlatform. | |
443 Class DVTPlatformClass = FindClassByName(@"DVTPlatform"); | |
444 [DVTPlatformClass loadAllPlatformsReturningError:nil]; | |
TVL
2013/12/12 16:08:27
You should check the bool return result, and would
justincohen
2013/12/16 18:44:37
Done.
| |
445 | |
406 NSString* simBundlePath = [developerDir | 446 NSString* simBundlePath = [developerDir |
407 stringByAppendingPathComponent:kSimulatorFrameworkRelativePath]; | 447 stringByAppendingPathComponent:kSimulatorFrameworkRelativePath]; |
408 NSBundle* simBundle = [NSBundle bundleWithPath:simBundlePath]; | 448 NSBundle* simBundle = [NSBundle bundleWithPath:simBundlePath]; |
409 if (![simBundle load]) | 449 if (![simBundle load]) |
410 return nil; | 450 return nil; |
411 return simBundle; | 451 return simBundle; |
412 } | 452 } |
413 | 453 |
414 // Helper to find a class by name and die if it isn't found. | |
415 Class FindClassByName(NSString* nameOfClass) { | |
416 Class theClass = NSClassFromString(nameOfClass); | |
417 if (!theClass) { | |
418 LogError(@"Failed to find class %@ at runtime.", nameOfClass); | |
419 exit(kExitInitializationFailure); | |
420 } | |
421 return theClass; | |
422 } | |
423 | |
424 // Converts the given app path to an application spec, which requires an | 454 // Converts the given app path to an application spec, which requires an |
425 // absolute path. | 455 // absolute path. |
426 DTiPhoneSimulatorApplicationSpecifier* BuildAppSpec(NSString* appPath) { | 456 DTiPhoneSimulatorApplicationSpecifier* BuildAppSpec(NSString* appPath) { |
427 Class applicationSpecifierClass = | 457 Class applicationSpecifierClass = |
428 FindClassByName(@"DTiPhoneSimulatorApplicationSpecifier"); | 458 FindClassByName(@"DTiPhoneSimulatorApplicationSpecifier"); |
429 if (![appPath isAbsolutePath]) { | 459 if (![appPath isAbsolutePath]) { |
430 NSString* cwd = [[NSFileManager defaultManager] currentDirectoryPath]; | 460 NSString* cwd = [[NSFileManager defaultManager] currentDirectoryPath]; |
431 appPath = [cwd stringByAppendingPathComponent:appPath]; | 461 appPath = [cwd stringByAppendingPathComponent:appPath]; |
432 } | 462 } |
433 appPath = [appPath stringByStandardizingPath]; | 463 appPath = [appPath stringByStandardizingPath]; |
(...skipping 13 matching lines...) Expand all Loading... | |
447 } | 477 } |
448 | 478 |
449 // Builds a config object for starting the specified app. | 479 // Builds a config object for starting the specified app. |
450 DTiPhoneSimulatorSessionConfig* BuildSessionConfig( | 480 DTiPhoneSimulatorSessionConfig* BuildSessionConfig( |
451 DTiPhoneSimulatorApplicationSpecifier* appSpec, | 481 DTiPhoneSimulatorApplicationSpecifier* appSpec, |
452 DTiPhoneSimulatorSystemRoot* systemRoot, | 482 DTiPhoneSimulatorSystemRoot* systemRoot, |
453 NSString* stdoutPath, | 483 NSString* stdoutPath, |
454 NSString* stderrPath, | 484 NSString* stderrPath, |
455 NSArray* appArgs, | 485 NSArray* appArgs, |
456 NSDictionary* appEnv, | 486 NSDictionary* appEnv, |
457 NSNumber* deviceFamily) { | 487 NSNumber* deviceFamily, |
488 NSString* deviceName) { | |
458 Class sessionConfigClass = FindClassByName(@"DTiPhoneSimulatorSessionConfig"); | 489 Class sessionConfigClass = FindClassByName(@"DTiPhoneSimulatorSessionConfig"); |
459 DTiPhoneSimulatorSessionConfig* sessionConfig = | 490 DTiPhoneSimulatorSessionConfig* sessionConfig = |
460 [[[sessionConfigClass alloc] init] autorelease]; | 491 [[[sessionConfigClass alloc] init] autorelease]; |
461 sessionConfig.applicationToSimulateOnStart = appSpec; | 492 sessionConfig.applicationToSimulateOnStart = appSpec; |
462 sessionConfig.simulatedSystemRoot = systemRoot; | 493 sessionConfig.simulatedSystemRoot = systemRoot; |
463 sessionConfig.localizedClientName = @"chromium"; | 494 sessionConfig.localizedClientName = @"chromium"; |
464 sessionConfig.simulatedApplicationStdErrPath = stderrPath; | 495 sessionConfig.simulatedApplicationStdErrPath = stderrPath; |
465 sessionConfig.simulatedApplicationStdOutPath = stdoutPath; | 496 sessionConfig.simulatedApplicationStdOutPath = stdoutPath; |
466 sessionConfig.simulatedApplicationLaunchArgs = appArgs; | 497 sessionConfig.simulatedApplicationLaunchArgs = appArgs; |
467 sessionConfig.simulatedApplicationLaunchEnvironment = appEnv; | 498 sessionConfig.simulatedApplicationLaunchEnvironment = appEnv; |
499 sessionConfig.simulatedDeviceInfoName = deviceName; | |
468 sessionConfig.simulatedDeviceFamily = deviceFamily; | 500 sessionConfig.simulatedDeviceFamily = deviceFamily; |
469 return sessionConfig; | 501 return sessionConfig; |
470 } | 502 } |
471 | 503 |
472 // Builds a simulator session that will use the given delegate. | 504 // Builds a simulator session that will use the given delegate. |
473 DTiPhoneSimulatorSession* BuildSession(SimulatorDelegate* delegate) { | 505 DTiPhoneSimulatorSession* BuildSession(SimulatorDelegate* delegate) { |
474 Class sessionClass = FindClassByName(@"DTiPhoneSimulatorSession"); | 506 Class sessionClass = FindClassByName(@"DTiPhoneSimulatorSession"); |
475 DTiPhoneSimulatorSession* session = | 507 DTiPhoneSimulatorSession* session = |
476 [[[sessionClass alloc] init] autorelease]; | 508 [[[sessionClass alloc] init] autorelease]; |
477 session.delegate = delegate; | 509 session.delegate = delegate; |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
522 } | 554 } |
523 } | 555 } |
524 | 556 |
525 return YES; | 557 return YES; |
526 } | 558 } |
527 | 559 |
528 // Creates the necessary directory structure under the given user home directory | 560 // Creates the necessary directory structure under the given user home directory |
529 // path, then sets the path in the appropriate environment variable. | 561 // path, then sets the path in the appropriate environment variable. |
530 // Returns YES if successful, NO if unable to create or initialize the given | 562 // Returns YES if successful, NO if unable to create or initialize the given |
531 // directory. | 563 // directory. |
532 BOOL InitializeSimulatorUserHome(NSString* userHomePath, NSString* deviceName) { | 564 BOOL InitializeSimulatorUserHome(NSString* userHomePath) { |
533 if (!CreateHomeDirSubDirs(userHomePath)) | 565 if (!CreateHomeDirSubDirs(userHomePath)) |
534 return NO; | 566 return NO; |
535 | 567 |
536 // Set the device to simulate. Note that the iOS Simulator must not be running | |
537 // for this setting to take effect. | |
538 CFStringRef iPhoneSimulatorAppID = CFSTR("com.apple.iphonesimulator"); | |
539 CFPreferencesSetAppValue(CFSTR("SimulateDevice"), | |
540 deviceName, | |
541 iPhoneSimulatorAppID); | |
542 CFPreferencesAppSynchronize(iPhoneSimulatorAppID); | |
543 | |
544 // Update the environment to use the specified directory as the user home | 568 // Update the environment to use the specified directory as the user home |
545 // directory. | 569 // directory. |
546 // Note: the third param of setenv specifies whether or not to overwrite the | 570 // Note: the third param of setenv specifies whether or not to overwrite the |
547 // variable's value if it has already been set. | 571 // variable's value if it has already been set. |
548 if ((setenv(kUserHomeEnvVariable, [userHomePath UTF8String], YES) == -1) || | 572 if ((setenv(kUserHomeEnvVariable, [userHomePath UTF8String], YES) == -1) || |
549 (setenv(kHomeEnvVariable, [userHomePath UTF8String], YES) == -1)) { | 573 (setenv(kHomeEnvVariable, [userHomePath UTF8String], YES) == -1)) { |
550 LogError(@"Unable to set environment variables for home directory."); | 574 LogError(@"Unable to set environment variables for home directory."); |
551 return NO; | 575 return NO; |
552 } | 576 } |
553 | 577 |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
721 if (!simHomePath) { | 745 if (!simHomePath) { |
722 NSString* dirNameTemplate = | 746 NSString* dirNameTemplate = |
723 [NSString stringWithFormat:@"iossim-%@-%@-XXXXXX", appName, deviceName]; | 747 [NSString stringWithFormat:@"iossim-%@-%@-XXXXXX", appName, deviceName]; |
724 simHomePath = CreateTempDirectory(dirNameTemplate); | 748 simHomePath = CreateTempDirectory(dirNameTemplate); |
725 if (!simHomePath) { | 749 if (!simHomePath) { |
726 LogError(@"Unable to create unique directory for template %@", | 750 LogError(@"Unable to create unique directory for template %@", |
727 dirNameTemplate); | 751 dirNameTemplate); |
728 exit(kExitInitializationFailure); | 752 exit(kExitInitializationFailure); |
729 } | 753 } |
730 } | 754 } |
731 if (!InitializeSimulatorUserHome(simHomePath, deviceName)) { | 755 if (!InitializeSimulatorUserHome(simHomePath)) { |
732 LogError(@"Unable to initialize home directory for simulator: %@", | 756 LogError(@"Unable to initialize home directory for simulator: %@", |
733 simHomePath); | 757 simHomePath); |
734 exit(kExitInitializationFailure); | 758 exit(kExitInitializationFailure); |
735 } | 759 } |
736 | 760 |
737 // Create the config and simulator session. | 761 // Create the config and simulator session. |
738 DTiPhoneSimulatorSessionConfig* config = BuildSessionConfig(appSpec, | 762 DTiPhoneSimulatorSessionConfig* config = BuildSessionConfig(appSpec, |
739 systemRoot, | 763 systemRoot, |
740 stdioPath, | 764 stdioPath, |
741 stdioPath, | 765 stdioPath, |
742 appArgs, | 766 appArgs, |
743 appEnv, | 767 appEnv, |
744 deviceFamily); | 768 deviceFamily, |
769 deviceName); | |
745 SimulatorDelegate* delegate = | 770 SimulatorDelegate* delegate = |
746 [[[SimulatorDelegate alloc] initWithStdioPath:stdioPath | 771 [[[SimulatorDelegate alloc] initWithStdioPath:stdioPath |
747 developerDir:developerDir | 772 developerDir:developerDir |
748 simulatorHome:simHomePath] autorelease]; | 773 simulatorHome:simHomePath] autorelease]; |
749 DTiPhoneSimulatorSession* session = BuildSession(delegate); | 774 DTiPhoneSimulatorSession* session = BuildSession(delegate); |
750 | 775 |
751 // Start the simulator session. | 776 // Start the simulator session. |
752 NSError* error; | 777 NSError* error; |
753 BOOL started = [session requestStartWithConfig:config | 778 BOOL started = [session requestStartWithConfig:config |
754 timeout:sessionStartTimeout | 779 timeout:sessionStartTimeout |
755 error:&error]; | 780 error:&error]; |
756 | 781 |
757 // Spin the runtime indefinitely. When the delegate gets the message that the | 782 // Spin the runtime indefinitely. When the delegate gets the message that the |
758 // app has quit it will exit this program. | 783 // app has quit it will exit this program. |
759 if (started) { | 784 if (started) { |
760 [[NSRunLoop mainRunLoop] run]; | 785 [[NSRunLoop mainRunLoop] run]; |
761 } else { | 786 } else { |
762 LogError(@"Simulator failed request to start: \"%@\" (%@:%ld)", | 787 LogError(@"Simulator failed request to start: \"%@\" (%@:%ld)", |
763 [error localizedDescription], | 788 [error localizedDescription], |
764 [error domain], static_cast<long int>([error code])); | 789 [error domain], static_cast<long int>([error code])); |
765 } | 790 } |
766 | 791 |
767 // Note that this code is only executed if the simulator fails to start | 792 // Note that this code is only executed if the simulator fails to start |
768 // because once the main run loop is started, only the delegate calling | 793 // because once the main run loop is started, only the delegate calling |
769 // exit() will end the program. | 794 // exit() will end the program. |
770 [pool drain]; | 795 [pool drain]; |
771 return kExitFailure; | 796 return kExitFailure; |
772 } | 797 } |
OLD | NEW |