| 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 |
| (...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 357 localizedDescription, [error domain], | 357 localizedDescription, [error domain], |
| 358 static_cast<long int>([error code])); | 358 static_cast<long int>([error code])); |
| 359 exit(kExitFailure); | 359 exit(kExitFailure); |
| 360 } | 360 } |
| 361 } | 361 } |
| 362 | 362 |
| 363 // Try to determine if the simulated app crashed or quit with a non-zero | 363 // Try to determine if the simulated app crashed or quit with a non-zero |
| 364 // status code. iOS Simluator handles things a bit differently depending on | 364 // status code. iOS Simluator handles things a bit differently depending on |
| 365 // the version, so first determine the iOS version being used. | 365 // the version, so first determine the iOS version being used. |
| 366 BOOL badEntryFound = NO; | 366 BOOL badEntryFound = NO; |
| 367 NSString* versionString = | |
| 368 [[[session sessionConfig] simulatedSystemRoot] sdkVersion]; | |
| 369 NSInteger majorVersion = [[[versionString componentsSeparatedByString:@"."] | |
| 370 objectAtIndex:0] intValue]; | |
| 371 if (majorVersion <= 6) { | |
| 372 // In iOS 6 and before, logging from the simulated apps went to the main | |
| 373 // system logs, so use ASL to check if the simulated app exited abnormally | |
| 374 // by looking for system log messages from launchd that refer to the | |
| 375 // simulated app's PID. Limit query to messages in the last minute since | |
| 376 // PIDs are cyclical. | |
| 377 aslmsg query = asl_new(ASL_TYPE_QUERY); | |
| 378 asl_set_query(query, ASL_KEY_SENDER, "launchd", | |
| 379 ASL_QUERY_OP_EQUAL | ASL_QUERY_OP_SUBSTRING); | |
| 380 char session_id[20]; | |
| 381 if (snprintf(session_id, 20, "%d", [session simulatedApplicationPID]) < 0) { | |
| 382 LogError(@"Failed to get [session simulatedApplicationPID]"); | |
| 383 exit(kExitFailure); | |
| 384 } | |
| 385 asl_set_query(query, ASL_KEY_REF_PID, session_id, ASL_QUERY_OP_EQUAL); | |
| 386 asl_set_query(query, ASL_KEY_TIME, "-1m", ASL_QUERY_OP_GREATER_EQUAL); | |
| 387 | 367 |
| 388 // Log any messages found, and take note of any messages that may indicate | 368 // The iOS Simulator's system logging is sandboxed, so parse the sandboxed |
| 389 // the app crashed or did not exit cleanly. | 369 // system.log file for known errors. |
| 390 aslresponse response = asl_search(NULL, query); | 370 NSString* path; |
| 391 aslmsg entry; | 371 NSString* dataPath = session.sessionConfig.device.dataPath; |
| 392 while ((entry = aslresponse_next(response)) != NULL) { | 372 path = |
| 393 const char* message = asl_get(entry, ASL_KEY_MSG); | 373 [dataPath stringByAppendingPathComponent:@"Library/Logs/system.log"]; |
| 394 LogWarning(@"Console message: %s", message); | 374 NSFileManager* fileManager = [NSFileManager defaultManager]; |
| 395 // Some messages are harmless, so don't trigger a failure for them. | 375 if ([fileManager fileExistsAtPath:path]) { |
| 396 if (strstr(message, "The following job tried to hijack the service")) | 376 NSString* content = |
| 397 continue; | 377 [NSString stringWithContentsOfFile:path |
| 398 badEntryFound = YES; | 378 encoding:NSUTF8StringEncoding |
| 399 } | 379 error:NULL]; |
| 400 } else { | 380 NSArray* lines = [content componentsSeparatedByCharactersInSet: |
| 401 // Otherwise, the iOS Simulator's system logging is sandboxed, so parse the | 381 [NSCharacterSet newlineCharacterSet]]; |
| 402 // sandboxed system.log file for known errors. | 382 NSString* simulatedAppPID = |
| 403 NSString* path; | 383 [NSString stringWithFormat:@"%d", session.simulatedApplicationPID]; |
| 404 NSString* dataPath = session.sessionConfig.device.dataPath; | 384 NSArray* kErrorStrings = @[ |
| 405 path = | 385 @"Service exited with abnormal code:", |
| 406 [dataPath stringByAppendingPathComponent:@"Library/Logs/system.log"]; | 386 @"Service exited due to signal:", |
| 407 NSFileManager* fileManager = [NSFileManager defaultManager]; | 387 ]; |
| 408 if ([fileManager fileExistsAtPath:path]) { | 388 for (NSString* line in lines) { |
| 409 NSString* content = | 389 if ([line rangeOfString:simulatedAppPID].location != NSNotFound) { |
| 410 [NSString stringWithContentsOfFile:path | 390 for (NSString* errorString in kErrorStrings) { |
| 411 encoding:NSUTF8StringEncoding | 391 if ([line rangeOfString:errorString].location != NSNotFound) { |
| 412 error:NULL]; | 392 LogWarning(@"Console message: %@", line); |
| 413 NSArray* lines = [content componentsSeparatedByCharactersInSet: | 393 badEntryFound = YES; |
| 414 [NSCharacterSet newlineCharacterSet]]; | |
| 415 NSString* simulatedAppPID = | |
| 416 [NSString stringWithFormat:@"%d", session.simulatedApplicationPID]; | |
| 417 NSArray* kErrorStrings = @[ | |
| 418 @"Service exited with abnormal code:", | |
| 419 @"Service exited due to signal:", | |
| 420 ]; | |
| 421 for (NSString* line in lines) { | |
| 422 if ([line rangeOfString:simulatedAppPID].location != NSNotFound) { | |
| 423 for (NSString* errorString in kErrorStrings) { | |
| 424 if ([line rangeOfString:errorString].location != NSNotFound) { | |
| 425 LogWarning(@"Console message: %@", line); | |
| 426 badEntryFound = YES; | |
| 427 break; | |
| 428 } | |
| 429 } | |
| 430 if (badEntryFound) { | |
| 431 break; | 394 break; |
| 432 } | 395 } |
| 433 } | 396 } |
| 397 if (badEntryFound) { |
| 398 break; |
| 399 } |
| 434 } | 400 } |
| 435 // Remove the log file so subsequent invocations of iossim won't be | |
| 436 // looking at stale logs. | |
| 437 remove([path fileSystemRepresentation]); | |
| 438 } else { | |
| 439 LogWarning(@"Unable to find system log at '%@'.", path); | |
| 440 } | 401 } |
| 402 // Remove the log file so subsequent invocations of iossim won't be |
| 403 // looking at stale logs. |
| 404 remove([path fileSystemRepresentation]); |
| 405 } else { |
| 406 LogWarning(@"Unable to find system log at '%@'.", path); |
| 441 } | 407 } |
| 442 | 408 |
| 443 // If the query returned any nasty-looking results, iossim should exit with | 409 // If the query returned any nasty-looking results, iossim should exit with |
| 444 // non-zero status. | 410 // non-zero status. |
| 445 if (badEntryFound) { | 411 if (badEntryFound) { |
| 446 LogError(@"Simulated app crashed or exited with non-zero status"); | 412 LogError(@"Simulated app crashed or exited with non-zero status"); |
| 447 exit(kExitAppCrashed); | 413 exit(kExitAppCrashed); |
| 448 } | 414 } |
| 449 exit(kExitSuccess); | 415 exit(kExitSuccess); |
| 450 } | 416 } |
| (...skipping 441 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 892 [error localizedDescription], | 858 [error localizedDescription], |
| 893 [error domain], static_cast<long int>([error code])); | 859 [error domain], static_cast<long int>([error code])); |
| 894 } | 860 } |
| 895 | 861 |
| 896 // Note that this code is only executed if the simulator fails to start | 862 // Note that this code is only executed if the simulator fails to start |
| 897 // because once the main run loop is started, only the delegate calling | 863 // because once the main run loop is started, only the delegate calling |
| 898 // exit() will end the program. | 864 // exit() will end the program. |
| 899 [pool drain]; | 865 [pool drain]; |
| 900 return kExitFailure; | 866 return kExitFailure; |
| 901 } | 867 } |
| OLD | NEW |