diff options
author | lliabraa@chromium.org <lliabraa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-26 16:11:36 +0000 |
---|---|---|
committer | lliabraa@chromium.org <lliabraa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-26 16:11:36 +0000 |
commit | 0dbae1f0f44a987fb202bb4dff3ae172741d751d (patch) | |
tree | 9493bbd89997c935b0d73b152ffa0201593a7b9a /testing/iossim | |
parent | 8eb330fe905a60d7f47fda933765a7003f8b0df0 (diff) | |
download | chromium_src-0dbae1f0f44a987fb202bb4dff3ae172741d751d.zip chromium_src-0dbae1f0f44a987fb202bb4dff3ae172741d751d.tar.gz chromium_src-0dbae1f0f44a987fb202bb4dff3ae172741d751d.tar.bz2 |
Get iossim to launch apps with Xcode 6.
The trick here is to load the CoreSimulator framework before attempting
to create the SimDevice.
Note that with this CL the SimDevice is created under the temp directory
that is used for iossim's home dir.
BUG=381213
Review URL: https://codereview.chromium.org/358693003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@280018 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'testing/iossim')
-rw-r--r-- | testing/iossim/iossim.mm | 176 |
1 files changed, 143 insertions, 33 deletions
diff --git a/testing/iossim/iossim.mm b/testing/iossim/iossim.mm index 1b00e25..b8c9ece 100644 --- a/testing/iossim/iossim.mm +++ b/testing/iossim/iossim.mm @@ -102,9 +102,13 @@ const NSTimeInterval kDefaultSessionStartTimeoutSeconds = 30; const NSTimeInterval kOutputPollIntervalSeconds = 0.1; // The path within the developer dir of the private Simulator frameworks. +// TODO(lliabraa): Once all builders are on Xcode 6 this ifdef can be removed +// (crbug.com/385030). #if defined(IOSSIM_USE_XCODE_6) NSString* const kSimulatorFrameworkRelativePath = @"../SharedFrameworks/DVTiPhoneSimulatorRemoteClient.framework"; +NSString* const kCoreSimulatorRelativePath = + @"Library/PrivateFrameworks/CoreSimulator.framework"; #else NSString* const kSimulatorFrameworkRelativePath = @"Platforms/iPhoneSimulator.platform/Developer/Library/PrivateFrameworks/" @@ -158,6 +162,51 @@ void LogWarning(NSString* format, ...) { va_end(list); } +// Helper to find a class by name and die if it isn't found. +Class FindClassByName(NSString* nameOfClass) { + Class theClass = NSClassFromString(nameOfClass); + if (!theClass) { + LogError(@"Failed to find class %@ at runtime.", nameOfClass); + exit(kExitInitializationFailure); + } + return theClass; +} + +// Prints supported devices and SDKs. +void PrintSupportedDevices() { +// TODO(lliabraa): Once all builders are on Xcode 6 this ifdef can be removed +// (crbug.com/385030). +#if defined(IOSSIM_USE_XCODE_6) + printf("Retrieving supported devices:\n"); + Class simServiceConnectionManagerClass = + FindClassByName(@"SimServiceConnectionManager"); + [[simServiceConnectionManagerClass sharedConnectionManager] connect]; + + Class simDeviceSetClass = FindClassByName(@"SimDeviceSet"); + id deviceSet = + [simDeviceSetClass setForSetPath:[simDeviceSetClass defaultSetPath]]; + for (id simDevice in [deviceSet availableDevices]) { + NSString* deviceInfo = + [NSString stringWithFormat:@" -d '%@' -s '%@'\n", + [simDevice name], [[simDevice runtime] versionString]]; + printf("%s", [deviceInfo UTF8String]); + } +#else + printf("Supported SDK versions:\n"); + Class rootClass = FindClassByName(@"DTiPhoneSimulatorSystemRoot"); + for (id root in [rootClass knownRoots]) { + printf(" '%s'\n", [[root sdkVersion] UTF8String]); + } + printf("Supported devices:\n"); + printf(" 'iPhone'\n"); + printf(" 'iPhone Retina (3.5-inch)'\n"); + printf(" 'iPhone Retina (4-inch)'\n"); + printf(" 'iPhone Retina (4-inch 64-bit)'\n"); + printf(" 'iPad'\n"); + printf(" 'iPad Retina'\n"); + printf(" 'iPad Retina (64-bit)'\n"); +#endif // defined(IOSSIM_USE_XCODE_6) +} } // namespace // A delegate that is called when the simulated app is started or ended in the @@ -211,12 +260,23 @@ void LogWarning(NSString* format, ...) { // this path isn't always available (e.g. when the stdout is Xcode's build // window). As a workaround, iossim creates a temp file to hold output, which // this method reads and copies to stdout. -- (void)tailOutput { +- (void)tailOutputForSession:(DTiPhoneSimulatorSession*)session { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - // Copy data to stdout/stderr while the app is running. NSFileHandle* simio = [NSFileHandle fileHandleForReadingAtPath:stdioPath_]; +// TODO(lliabraa): Once all builders are on Xcode 6 this ifdef can be removed +// (crbug.com/385030). +#if defined(IOSSIM_USE_XCODE_6) + // With iOS 8 simulators on Xcode 6, the app output is relative to the + // simulator's data directory. + if ([session.sessionConfig.simulatedSystemRoot.sdkVersion isEqual:@"8.0"]) { + NSString* dataPath = session.sessionConfig.device.dataPath; + NSString* appOutput = [dataPath stringByAppendingPathComponent:stdioPath_]; + simio = [NSFileHandle fileHandleForReadingAtPath:appOutput]; + } +#endif NSFileHandle* standardOutput = [NSFileHandle fileHandleWithStandardOutput]; + // Copy data to stdout/stderr while the app is running. while (appRunning_) { NSAutoreleasePool* innerPool = [[NSAutoreleasePool alloc] init]; [standardOutput writeData:[simio readDataToEndOfFile]]; @@ -263,7 +323,7 @@ void LogWarning(NSString* format, ...) { NSFileManager* fileManager = [NSFileManager defaultManager]; if ([fileManager fileExistsAtPath:stdioPath_]) { appRunning_ = NO; - [self tailOutput]; + [self tailOutputForSession:session]; // Note that exiting in this state leaves a process running // (e.g. /.../iPhoneSimulator4.3.sdk/usr/libexec/installd -t 30) that will // prevent future simulator sessions from being started for 30 seconds @@ -278,14 +338,16 @@ void LogWarning(NSString* format, ...) { LogError(@"Simulator failed to start: \"%@\" (%@:%ld)", [error localizedDescription], [error domain], static_cast<long int>([error code])); + PrintSupportedDevices(); exit(kExitAppFailedToStart); } // Start a thread to write contents of outputPath to stdout. appRunning_ = YES; - outputThread_ = [[NSThread alloc] initWithTarget:self - selector:@selector(tailOutput) - object:nil]; + outputThread_ = + [[NSThread alloc] initWithTarget:self + selector:@selector(tailOutputForSession:) + object:session]; [outputThread_ start]; } @@ -361,11 +423,19 @@ void LogWarning(NSString* format, ...) { } else { // Otherwise, the iOS Simulator's system logging is sandboxed, so parse the // sandboxed system.log file for known errors. +// TODO(lliabraa): Once all builders are on Xcode 6 this ifdef can be removed +// (crbug.com/385030). +#if defined(IOSSIM_USE_XCODE_6) + NSString* dataPath = session.sessionConfig.device.dataPath; + NSString* path = + [dataPath stringByAppendingPathComponent:@"Library/Logs/system.log"]; +#else NSString* relativePathToSystemLog = [NSString stringWithFormat: @"Library/Logs/iOS Simulator/%@/system.log", versionString]; NSString* path = [simulatorHome_ stringByAppendingPathComponent:relativePathToSystemLog]; +#endif // defined(IOSSIM_USE_XCODE_6) NSFileManager* fileManager = [NSFileManager defaultManager]; if ([fileManager fileExistsAtPath:path]) { NSString* content = @@ -386,7 +456,7 @@ void LogWarning(NSString* format, ...) { // looking at stale logs. remove([path fileSystemRepresentation]); } else { - LogWarning(@"Unable to find sandboxed system log."); + LogWarning(@"Unable to find system log at '%@'.", path); } } @@ -434,16 +504,6 @@ NSString* FindDeveloperDir() { return output; } -// Helper to find a class by name and die if it isn't found. -Class FindClassByName(NSString* nameOfClass) { - Class theClass = NSClassFromString(nameOfClass); - if (!theClass) { - LogError(@"Failed to find class %@ at runtime.", nameOfClass); - exit(kExitInitializationFailure); - } - return theClass; -} - // Loads the Simulator framework from the given developer dir. NSBundle* LoadSimulatorFramework(NSString* developerDir) { // The Simulator framework depends on some of the other Xcode private @@ -471,6 +531,17 @@ NSBundle* LoadSimulatorFramework(NSString* developerDir) { return nil; } +// TODO(lliabraa): Once all builders are on Xcode 6 this ifdef can be removed +// (crbug.com/385030). +#if defined(IOSSIM_USE_XCODE_6) + NSString* coreSimulatorPath = [developerDir + stringByAppendingPathComponent:kCoreSimulatorRelativePath]; + NSBundle* coreSimulatorBundle = + [NSBundle bundleWithPath:coreSimulatorPath]; + if (![coreSimulatorBundle load]) + return nil; +#endif // defined(IOSSIM_USE_XCODE_6) + NSString* simBundlePath = [developerDir stringByAppendingPathComponent:kSimulatorFrameworkRelativePath]; NSBundle* simBundle = [NSBundle bundleWithPath:simBundlePath]; @@ -489,6 +560,11 @@ DTiPhoneSimulatorApplicationSpecifier* BuildAppSpec(NSString* appPath) { appPath = [cwd stringByAppendingPathComponent:appPath]; } appPath = [appPath stringByStandardizingPath]; + NSFileManager* fileManager = [NSFileManager defaultManager]; + if (![fileManager fileExistsAtPath:appPath]) { + LogError(@"File not found: %@", appPath); + exit(kExitInvalidArguments); + } return [applicationSpecifierClass specifierWithApplicationPath:appPath]; } @@ -526,6 +602,30 @@ DTiPhoneSimulatorSessionConfig* BuildSessionConfig( sessionConfig.simulatedApplicationLaunchEnvironment = appEnv; sessionConfig.simulatedDeviceInfoName = deviceName; sessionConfig.simulatedDeviceFamily = deviceFamily; + +// TODO(lliabraa): Once all builders are on Xcode 6 this ifdef can be removed +// (crbug.com/385030). +#if defined(IOSSIM_USE_XCODE_6) + Class simDeviceTypeClass = FindClassByName(@"SimDeviceType"); + id simDeviceType = + [simDeviceTypeClass supportedDeviceTypesByName][deviceName]; + Class simRuntimeClass = FindClassByName(@"SimRuntime"); + NSString* identifier = systemRoot.runtime.identifier; + id simRuntime = [simRuntimeClass supportedRuntimesByIdentifier][identifier]; + + Class simDeviceSetClass = FindClassByName(@"SimDeviceSet"); + NSError* error = nil; + id simDevice = + [[simDeviceSetClass defaultSet] createDeviceWithType:simDeviceType + runtime:simRuntime + name:@"iossim" + error:&error]; + if (error) { + LogError(@"Failed to create device: %@", error); + exit(kExitInitializationFailure); + } + sessionConfig.device = simDevice; +#endif return sessionConfig; } @@ -633,10 +733,10 @@ void PrintUsage() { " -e Specifies an environment key=value pair that will be" " set in the simulated application's environment.\n" " -t Specifies the session startup timeout (in seconds)." - " Defaults to %d.\n", + " Defaults to %d.\n" + " -l List supported devices and iOS versions.\n", static_cast<int>(kDefaultSessionStartTimeoutSeconds)); } - } // namespace int main(int argc, char* const argv[]) { @@ -663,9 +763,21 @@ int main(int argc, char* const argv[]) { NSMutableDictionary* appEnv = [NSMutableDictionary dictionary]; NSTimeInterval sessionStartTimeout = kDefaultSessionStartTimeoutSeconds; + NSString* developerDir = FindDeveloperDir(); + if (!developerDir) { + LogError(@"Unable to find developer directory."); + exit(kExitInitializationFailure); + } + + NSBundle* simulatorFramework = LoadSimulatorFramework(developerDir); + if (!simulatorFramework) { + LogError(@"Failed to load the Simulator Framework."); + exit(kExitInitializationFailure); + } + // Parse the optional arguments int c; - while ((c = getopt(argc, argv, "hs:d:u:e:t:")) != -1) { + while ((c = getopt(argc, argv, "hs:d:u:e:t:l")) != -1) { switch (c) { case 's': sdkVersion = [NSString stringWithUTF8String:optarg]; @@ -701,6 +813,10 @@ int main(int argc, char* const argv[]) { } } break; + case 'l': + PrintSupportedDevices(); + exit(kExitSuccess); + break; case 'h': PrintUsage(); exit(kExitSuccess); @@ -726,18 +842,6 @@ int main(int argc, char* const argv[]) { exit(kExitInvalidArguments); } - NSString* developerDir = FindDeveloperDir(); - if (!developerDir) { - LogError(@"Unable to find developer directory."); - exit(kExitInitializationFailure); - } - - NSBundle* simulatorFramework = LoadSimulatorFramework(developerDir); - if (!simulatorFramework) { - LogError(@"Failed to load the Simulator Framework."); - exit(kExitInitializationFailure); - } - // Make sure the app path provided is legit. DTiPhoneSimulatorApplicationSpecifier* appSpec = BuildAppSpec(appPath); if (!appSpec) { @@ -749,6 +853,7 @@ int main(int argc, char* const argv[]) { DTiPhoneSimulatorSystemRoot* systemRoot = BuildSystemRoot(sdkVersion); if (!systemRoot) { LogError(@"Invalid SDK version: %@", sdkVersion); + PrintSupportedDevices(); exit(kExitInitializationFailure); } @@ -763,11 +868,16 @@ int main(int argc, char* const argv[]) { deviceFamily = [NSNumber numberWithInt:kIPhoneFamily]; } else if (CaseInsensitivePrefixSearch(deviceName, @"iPad")) { deviceFamily = [NSNumber numberWithInt:kIPadFamily]; - } else { + } +// TODO(lliabraa): Once all builders are on Xcode 6 this ifdef can be removed +// (crbug.com/385030). +#if !defined(IOSSIM_USE_XCODE_6) + else { LogError(@"Invalid device name: %@. Must begin with 'iPhone' or 'iPad'", deviceName); exit(kExitInvalidArguments); } +#endif // !defined(IOSSIM_USE_XCODE_6) // Set up the user home directory for the simulator if (!simHomePath) { |