Add -[FBCrashLogCommands pruneCrashes:]

Summary:
Instead of exposing the details of the Crash Log Store, it makes some sense to be able to control the availability of crash logs for a given target.

For Simulators this now means we have to specialize since we need to have knowledge of the UDID being present in (some) logs but not others.
For Devices we need to be able to prune crashes by talking to the device

Reviewed By: zeyadsalloum

Differential Revision: D8595775

fbshipit-source-id: 5fc559191d881c591842c425e1dd026f51f78cbd
This commit is contained in:
Lawrence Lomax 2018-10-01 03:58:44 -07:00 коммит произвёл Facebook Github Bot
Родитель 37cfbd0b90
Коммит de2db61465
14 изменённых файлов: 327 добавлений и 136 удалений

Просмотреть файл

@ -16,6 +16,7 @@
NS_ASSUME_NONNULL_BEGIN
@class FBCrashLogInfo;
@class FBCrashLogStore;
/**
Commands for obtaining crash logs.
@ -26,9 +27,10 @@ NS_ASSUME_NONNULL_BEGIN
Obtains all of the crash logs matching a given predicate.
@param predicate the predicate to match against.
@param useCache YES to use the cached crash logs, NO to re-fetch. Pass YES when significant events have happened.
@return a Future that resolves with crash logs.
*/
- (FBFuture<NSArray<FBCrashLogInfo *> *> *)crashes:(NSPredicate *)predicate;
- (FBFuture<NSArray<FBCrashLogInfo *> *> *)crashes:(NSPredicate *)predicate useCache:(BOOL)useCache;
/**
Notifies when a Crash Log becomes available for a given predicate.
@ -38,12 +40,13 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (FBFuture<FBCrashLogInfo *> *)notifyOfCrash:(NSPredicate *)predicate;
@end
/**
An implementation of FBCrashLogCommands, that looks for crash logs on the host.
Prunes all of the crashes that may be cached that match the given predicate.
@param predicate the predicate to match against.
@return a Future that will resolve with the pruned crash logs.
*/
@interface FBHostCrashLogCommands : NSObject <FBCrashLogCommands>
- (FBFuture<NSArray<FBCrashLogInfo *> *> *)pruneCrashes:(NSPredicate *)predicate;
@end

Просмотреть файл

@ -1,54 +0,0 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "FBCrashLogCommands.h"
#import "FBCrashLogNotifier.h"
#import "FBCrashLogStore.h"
@interface FBHostCrashLogCommands ()
@property (nonatomic, strong, readonly) FBCrashLogNotifier *notifier;
@end
@implementation FBHostCrashLogCommands
#pragma mark Initializers
+ (instancetype)commandsWithTarget:(id<FBiOSTarget>)target
{
return [[self alloc] initWithNotifier:FBCrashLogNotifier.sharedInstance];
}
- (instancetype)initWithNotifier:(FBCrashLogNotifier *)notifier
{
self = [super init];
if (!self) {
return nil;
}
_notifier = notifier;
return self;
}
#pragma mark id<FBiOSTarget>
- (FBFuture<FBCrashLogInfo *> *)notifyOfCrash:(NSPredicate *)predicate
{
return [self.notifier nextCrashLogForPredicate:predicate];
}
- (FBFuture<NSArray<FBCrashLogInfo *> *> *)crashes:(NSPredicate *)predicate
{
return [FBFuture futureWithResult:[self.notifier.store ingestedCrashLogsMatchingPredicate:predicate]];
}
@end

Просмотреть файл

@ -139,11 +139,19 @@ typedef NS_OPTIONS(NSUInteger, FBCrashLogInfoProcessType) {
/**
A Predicate for FBCrashLogInfo that passes for all Crash Logs that are newer than the given date.
@param date the start date.
@param date the date.
@return a NSPredicate.
*/
+ (NSPredicate *)predicateNewerThanDate:(NSDate *)date;
/**
A Predicate for FBCrashLogInfo that passes for all Crash Logs that are older than the given date.
@param date the date.
@return a NSPredicate.
*/
+ (NSPredicate *)predicateOlderThanDate:(NSDate *)date;
/**
A Predicate for FBCrashLogInfo that matches a identifier.
@ -160,6 +168,14 @@ typedef NS_OPTIONS(NSUInteger, FBCrashLogInfoProcessType) {
*/
+ (NSPredicate *)predicateForName:(NSString *)name;
/**
A Predicate that searches for a substring in the executable path.
@param contains the substring to search for.
@return an NSPredicate
*/
+ (NSPredicate *)predicateForExecutablePathContains:(NSString *)contains;
@end
NS_ASSUME_NONNULL_END

Просмотреть файл

@ -177,6 +177,11 @@
}];
}
+ (NSPredicate *)predicateOlderThanDate:(NSDate *)date
{
return [NSCompoundPredicate notPredicateWithSubpredicate:[self predicateNewerThanDate:date]];
}
+ (NSPredicate *)predicateForIdentifier:(NSString *)identifier
{
return [NSPredicate predicateWithBlock:^ BOOL (FBCrashLogInfo *crashLog, id _) {
@ -191,6 +196,13 @@
}];
}
+ (NSPredicate *)predicateForExecutablePathContains:(NSString *)contains
{
return [NSPredicate predicateWithBlock:^ BOOL (FBCrashLogInfo *crashLog, id _) {
return [crashLog.executablePath containsString:contains];
}];
}
#pragma mark Helpers
+ (NSArray<NSString *> *)diagnosticReportsPaths

Просмотреть файл

@ -370,7 +370,7 @@ static NSString *const FBDiagnosticQueryCrashesSystem = @"system";
[FBCrashLogInfo predicateNewerThanDate:self.date],
]];
return [[target
crashes:predicate]
crashes:predicate useCache:NO]
onQueue:target.asyncQueue map:^(NSArray<FBCrashLogInfo *> *crashes) {
NSMutableArray<FBDiagnostic *> *diagnostics = [NSMutableArray array];
for (FBCrashLogInfo *crash in crashes) {

Просмотреть файл

@ -32,7 +32,7 @@ NS_ASSUME_NONNULL_BEGIN
*/
+ (instancetype)storeForDirectories:(NSArray<NSString *> *)directories logger:(id<FBControlCoreLogger>)logger;
#pragma mark Public Methods
#pragma mark Ingestion
/**
Ingests all of the crash logs in the directory.
@ -58,13 +58,22 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (nullable FBCrashLogInfo *)ingestCrashLogData:(NSData *)data name:(NSString *)name;
#pragma mark Fetching
/**
Checks whether the crash log has already been ingested.
Returns the ingested crash log for a given name
@param name the name of the crash log.
@return YES if ingested, NO otherwise.
@return the Crash Log Info, if present.
*/
- (BOOL)hasIngestedCrashLogWithName:(NSString *)name;
- (nullable FBCrashLogInfo *)ingestedCrashLogWithName:(NSString *)name;
/**
Returns all of the ingested crash logs.
@return all of the ingested crash logs.
*/
- (NSArray<FBCrashLogInfo *> *)allIngestedCrashLogs;
/**
A future that resolves the next time a crash log becomes available that matches the given predicate.
@ -82,6 +91,14 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (NSArray<FBCrashLogInfo *> *)ingestedCrashLogsMatchingPredicate:(NSPredicate *)predicate;
/**
Prunes all of the ingested logs that match the given predicate.
@param predicate the predicate to use.
@return an array of all the pruned crash logs.
*/
- (NSArray<FBCrashLogInfo *> *)pruneCrashLogsMatchingPredicate:(NSPredicate *)predicate;
@end
NS_ASSUME_NONNULL_END

Просмотреть файл

@ -20,7 +20,7 @@ FBCrashLogNotificationName const FBCrashLogAppeared = @"FBCrashLogAppeared";
@property (nonatomic, copy, readonly) NSArray<NSString *> *directories;
@property (nonatomic, strong, readonly) id<FBControlCoreLogger> logger;
@property (nonatomic, strong, readonly) NSMutableArray<FBCrashLogInfo *> *ingestedCrashLogs;
@property (nonatomic, strong, readonly) NSMutableDictionary<NSString *, FBCrashLogInfo *> *ingestedCrashLogs;
@property (nonatomic, strong, readonly) dispatch_queue_t queue;
@end
@ -43,13 +43,13 @@ FBCrashLogNotificationName const FBCrashLogAppeared = @"FBCrashLogAppeared";
_directories = directories;
_logger = logger;
_ingestedCrashLogs = NSMutableArray.array;
_ingestedCrashLogs = NSMutableDictionary.dictionary;
_queue = dispatch_queue_create("com.facebook.fbcontrolcore.crash_store", DISPATCH_QUEUE_SERIAL);
return self;
}
#pragma mark Public Methods
#pragma mark Ingestion
- (NSArray<FBCrashLogInfo *> *)ingestAllExistingInDirectory
{
@ -67,15 +67,12 @@ FBCrashLogNotificationName const FBCrashLogAppeared = @"FBCrashLogAppeared";
if ([self hasIngestedCrashLogWithName:path.lastPathComponent]) {
return nil;
}
FBCrashLogInfo *crashLogInfo = [FBCrashLogInfo fromCrashLogAtPath:path];
if (!crashLogInfo) {
FBCrashLogInfo *crashLog = [FBCrashLogInfo fromCrashLogAtPath:path];
if (!crashLog) {
[self.logger logFormat:@"Could not obtain crash info for %@", path];
return nil;
}
[self.logger logFormat:@"Ingesting Crash Log %@", crashLogInfo];
[self.ingestedCrashLogs addObject:crashLogInfo];
[NSNotificationCenter.defaultCenter postNotificationName:FBCrashLogAppeared object:crashLogInfo];
return crashLogInfo;
return [self ingestCrashLog:crashLog];
}
- (nullable FBCrashLogInfo *)ingestCrashLogData:(NSData *)data name:(NSString *)name
@ -102,9 +99,16 @@ FBCrashLogNotificationName const FBCrashLogAppeared = @"FBCrashLogAppeared";
return nil;
}
- (BOOL)hasIngestedCrashLogWithName:(NSString *)key
#pragma mark Fetching
- (FBCrashLogInfo *)ingestedCrashLogWithName:(NSString *)name
{
return [self.ingestedNames containsObject:key];
return self.ingestedCrashLogs[name];
}
- (NSArray<FBCrashLogInfo *> *)allIngestedCrashLogs
{
return self.ingestedCrashLogs.allValues;
}
- (FBFuture<FBCrashLogInfo *> *)nextCrashLogForMatchingPredicate:(NSPredicate *)predicate
@ -117,11 +121,39 @@ FBCrashLogNotificationName const FBCrashLogAppeared = @"FBCrashLogAppeared";
- (NSArray<FBCrashLogInfo *> *)ingestedCrashLogsMatchingPredicate:(NSPredicate *)predicate
{
return [self.ingestedCrashLogs filteredArrayUsingPredicate:predicate];
return [self.ingestedCrashLogs.allValues filteredArrayUsingPredicate:predicate];
}
- (NSArray<FBCrashLogInfo *> *)pruneCrashLogsMatchingPredicate:(NSPredicate *)predicate
{
NSMutableArray<NSString *> *keys = NSMutableArray.array;
NSMutableArray<FBCrashLogInfo *> *crashLogs = NSMutableArray.array;
for (FBCrashLogInfo *crashLog in self.ingestedCrashLogs.allValues) {
if (![predicate evaluateWithObject:crashLog]) {
continue;
}
[keys addObject:crashLog.name];
[crashLogs addObject:crashLog];
}
[self.ingestedCrashLogs removeObjectsForKeys:keys];
return crashLogs;
}
#pragma mark Private
- (BOOL)hasIngestedCrashLogWithName:(NSString *)key
{
return self.ingestedCrashLogs[key] != nil;
}
- (FBCrashLogInfo *)ingestCrashLog:(FBCrashLogInfo *)crashLog
{
[self.logger logFormat:@"Ingesting Crash Log %@", crashLog];
self.ingestedCrashLogs[crashLog.name] = crashLog;
[NSNotificationCenter.defaultCenter postNotificationName:FBCrashLogAppeared object:crashLog];
return crashLog;
}
+ (FBFuture<FBCrashLogInfo *> *)oneshotCrashLogNotificationForPredicate:(NSPredicate *)predicate queue:(dispatch_queue_t)queue
{
__weak NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
@ -164,9 +196,4 @@ FBCrashLogNotificationName const FBCrashLogAppeared = @"FBCrashLogAppeared";
return [ingested copy];
}
- (NSSet<NSString *> *)ingestedNames
{
return [NSSet setWithArray:[self.ingestedCrashLogs valueForKeyPath:@"name"]];
}
@end

Просмотреть файл

@ -147,7 +147,7 @@
return [FBFuture futureWithError:[[FBControlCoreError describe:@"Unimplemented"] build]];
}
- (FBFuture<NSArray<FBCrashLogInfo *> *> *)crashes:(NSPredicate *)predicate
- (FBFuture<NSArray<FBCrashLogInfo *> *> *)crashes:(NSPredicate *)predicate useCache:(BOOL)useCache
{
return [FBFuture futureWithError:[[FBControlCoreError describe:@"Unimplemented"] build]];
}
@ -157,4 +157,9 @@
return [FBFuture futureWithError:[[FBControlCoreError describe:@"Unimplemented"] build]];
}
- (FBFuture<NSArray<FBCrashLogInfo *> *> *)pruneCrashes:(NSPredicate *)predicate
{
return [FBFuture futureWithError:[[FBControlCoreError describe:@"Unimplemented"] build]];
}
@end

Просмотреть файл

@ -58,26 +58,114 @@ static NSString *const PingSuccess = @"ping";
- (FBFuture<FBCrashLogInfo *> *)notifyOfCrash:(NSPredicate *)predicate
{
[self ingestAllCrashLogs];
[self ingestAllCrashLogs:NO];
return [self.store nextCrashLogForMatchingPredicate:predicate];
}
- (FBFuture<NSArray<FBCrashLogInfo *> *> *)crashes:(NSPredicate *)predicate
- (FBFuture<NSArray<FBCrashLogInfo *> *> *)crashes:(NSPredicate *)predicate useCache:(BOOL)useCache
{
return [[self
ingestAllCrashLogs]
ingestAllCrashLogs:useCache]
onQueue:self.device.workQueue map:^(NSArray<FBCrashLogInfo *> *_) {
return [self.store ingestedCrashLogsMatchingPredicate:predicate];
}];
}
- (FBFuture<NSArray<FBCrashLogInfo *> *> *)pruneCrashes:(NSPredicate *)predicate
{
id<FBControlCoreLogger> logger = [self.device.logger withName:@"crash_remove"];
return [[self
ingestAllCrashLogs:YES]
onQueue:self.device.workQueue fmap:^(NSArray<FBCrashLogInfo *> *_) {
NSArray<FBCrashLogInfo *> *pruned = [self.store pruneCrashLogsMatchingPredicate:predicate];
[logger logFormat:@"Pruned %@ logs from local cache", [FBCollectionInformation oneLineDescriptionFromArray:[pruned valueForKeyPath:@"name"]]];
return [self removeCrashLogsFromDevice:pruned logger:logger];
}];
}
#pragma mark Private
- (FBFuture<NSArray<FBCrashLogInfo *> *> *)ingestAllCrashLogs
- (FBFuture<NSArray<FBCrashLogInfo *> *> *)ingestAllCrashLogs:(BOOL)useCache
{
return [[[self.device.amDevice
if (self.hasPerformedInitialIngestion && useCache) {
return [FBFuture futureWithResult:@[]];
}
id<FBControlCoreLogger> logger = self.device.logger;
return [[self
copyCrashReportsAndGetFileConnection]
onQueue:self.device.workQueue fmap:^(FBAFCConnection *afc) {
if (!self.hasPerformedInitialIngestion) {
[self.store ingestAllExistingInDirectory];
self.hasPerformedInitialIngestion = YES;
}
NSError *error = nil;
NSArray<NSString *> *paths = [afc contentsOfDirectory:@"." error:&error];
if (!paths) {
return [FBFuture futureWithError:error];
}
NSMutableArray<FBCrashLogInfo *> *crashes = [NSMutableArray array];
for (NSString *path in paths) {
FBCrashLogInfo *crash = [self crashLogInfo:afc path:path error:&error];
if (!crash) {
[logger logFormat:@"Failed to ingest crash log %@: %@", path, error];
continue;
}
[crashes addObject:crash];
}
return [FBFuture futureWithResult:crashes];
}];
}
- (FBFuture<NSArray<FBCrashLogInfo *> *> *)removeCrashLogsFromDevice:(NSArray<FBCrashLogInfo *> *)crashesToRemove logger:(id<FBControlCoreLogger>)logger
{
return [[self
crashReportFileConnection]
onQueue:self.device.workQueue fmap:^(FBAFCConnection *afc) {
NSMutableArray<FBCrashLogInfo *> *removed = NSMutableArray.array;
for (FBCrashLogInfo *crash in crashesToRemove) {
NSError *error = nil;
if ([afc removePath:crash.name recursively:NO error:&error]) {
[logger logFormat:@"Crash %@ removed from device", crash.name];
[removed addObject:crash];
} else {
[logger logFormat:@"Crash %@ could not be removed from device: %@", crash.name, error];
}
}
return [FBFuture futureWithResult:removed];
}];
}
- (nullable FBCrashLogInfo *)crashLogInfo:(FBAFCConnection *)afc path:(NSString *)path error:(NSError **)error
{
NSString *name = path;
FBCrashLogInfo *existing = [self.store ingestedCrashLogWithName:path];
if (existing) {
[self.device.logger logFormat:@"No need to re-ingest %@", path];
return existing;
}
NSData *data = [afc contentsOfPath:path error:error];
if (!data) {
return nil;
}
return [self.store ingestCrashLogData:data name:name];
}
- (FBFutureContext<FBAFCConnection *> *)copyCrashReportsAndGetFileConnection
{
return [[self
moveCrashReports]
onQueue:self.device.workQueue pushTeardown:^(NSString *_) {
return [self crashReportFileConnection];
}];
}
- (FBFuture<NSString *> *)moveCrashReports
{
return [[self.device.amDevice
startService:CrashReportMoverService]
onQueue:self.device.asyncQueue fmap:^ FBFuture<FBAMDServiceConnection *> * (FBAMDServiceConnection *connection) {
// The mover is used first and can be discarded when done.
onQueue:self.device.asyncQueue fmap:^ FBFuture<NSString *> * (FBAMDServiceConnection *connection) {
NSError *error = nil;
NSData *data = [connection receive:4 error:&error];
if (!data) {
@ -93,49 +181,23 @@ static NSString *const PingSuccess = @"ping";
causedBy:error]
failFuture];
}
if (!self.hasPerformedInitialIngestion) {
[self.store ingestAllExistingInDirectory];
self.hasPerformedInitialIngestion = YES;
}
return [FBFuture futureWithResult:response];
}]
onQueue:self.device.workQueue fmap:^(id _) {
return [[self.device.amDevice
startService:CrashReportCopyService]
onQueue:self.device.asyncQueue fmap:^ FBFuture<NSArray<FBCrashLogInfo *> *> * (FBAMDServiceConnection *connection) {
NSError *error = nil;
FBAFCConnection *afc = [FBAFCConnection afcFromServiceConnection:connection calls:FBAFCConnection.defaultCalls logger:connection.logger error:&error];
if (!afc) {
return [FBFuture futureWithError:error];
}
NSArray<NSString *> *paths = [afc contentsOfDirectory:@"." error:&error];
if (!paths) {
return [FBFuture futureWithError:error];
}
NSMutableArray<FBCrashLogInfo *> *crashes = [NSMutableArray array];
for (NSString *path in paths) {
FBCrashLogInfo *crash = [self crashLogInfo:afc path:path error:nil];
if (!crash) {
continue;
}
[crashes addObject:crash];
}
return [FBFuture futureWithResult:crashes];
}];
}];
}
- (nullable FBCrashLogInfo *)crashLogInfo:(FBAFCConnection *)afc path:(NSString *)path error:(NSError **)error
- (FBFutureContext<FBAFCConnection *> *)crashReportFileConnection
{
NSString *name = path;
if ([self.store hasIngestedCrashLogWithName:name]) {
return nil;
}
NSData *data = [afc contentsOfPath:path error:error];
if (!data) {
return nil;
}
return [self.store ingestCrashLogData:data name:name];
return [[self.device.amDevice
startService:CrashReportCopyService]
// Re-map this into a AFC Connection.
onQueue:self.device.workQueue pend:^(FBAMDServiceConnection *connection) {
NSError *error = nil;
FBAFCConnection *afc = [FBAFCConnection afcFromServiceConnection:connection calls:FBAFCConnection.defaultCalls logger:self.device.logger error:&error];
if (!afc) {
return [FBFuture futureWithError:error];
}
return [FBFuture futureWithResult:afc];
}];
}
@end

Просмотреть файл

@ -63,7 +63,6 @@
AA08487E1F3F49D600A4BA60 /* FBFutureTests.m in Sources */ = {isa = PBXBuildFile; fileRef = AA08487D1F3F49D600A4BA60 /* FBFutureTests.m */; };
AA0949F31F8F4A8A00841A73 /* FBEventReporterIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = AA0949F21F8F4A8A00841A73 /* FBEventReporterIntegrationTests.m */; };
AA0CA38720643CCF00347424 /* FBCrashLogCommands.h in Headers */ = {isa = PBXBuildFile; fileRef = AA0CA38620643C6800347424 /* FBCrashLogCommands.h */; settings = {ATTRIBUTES = (Public, ); }; };
AA0CA3892064F44D00347424 /* FBCrashLogCommands.m in Sources */ = {isa = PBXBuildFile; fileRef = AA0CA3882064F44D00347424 /* FBCrashLogCommands.m */; };
AA0DC7561CE3A29F0037A8A7 /* FBTestDaemonConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = AA0DC7541CE3A29F0037A8A7 /* FBTestDaemonConnection.h */; };
AA0DC7571CE3A29F0037A8A7 /* FBTestDaemonConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = AA0DC7551CE3A29F0037A8A7 /* FBTestDaemonConnection.m */; };
AA0EB2831F16905400ABBD7E /* FBApplicationBundle+Simulator.h in Headers */ = {isa = PBXBuildFile; fileRef = AA0EB2811F16905400ABBD7E /* FBApplicationBundle+Simulator.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -408,6 +407,8 @@
AAB207C01C2099A9007C7908 /* FBSimulatorLoggingEventSink.h in Headers */ = {isa = PBXBuildFile; fileRef = AAB207BE1C2099A9007C7908 /* FBSimulatorLoggingEventSink.h */; settings = {ATTRIBUTES = (Public, ); }; };
AAB207C11C2099A9007C7908 /* FBSimulatorLoggingEventSink.m in Sources */ = {isa = PBXBuildFile; fileRef = AAB207BF1C2099A9007C7908 /* FBSimulatorLoggingEventSink.m */; };
AAB475F420C80F7D00B37634 /* FBiOSTargetCommandForwarderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = AAB475F320C80F7D00B37634 /* FBiOSTargetCommandForwarderTests.m */; };
AAB475F720C8217F00B37634 /* FBSimulatorCrashLogCommands.h in Headers */ = {isa = PBXBuildFile; fileRef = AAB475F520C8217F00B37634 /* FBSimulatorCrashLogCommands.h */; };
AAB475F820C8217F00B37634 /* FBSimulatorCrashLogCommands.m in Sources */ = {isa = PBXBuildFile; fileRef = AAB475F620C8217F00B37634 /* FBSimulatorCrashLogCommands.m */; };
AAB4AC1E1BB586930046F6A1 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AAB4AC1D1BB586930046F6A1 /* AVFoundation.framework */; };
AAB4AC271BBBC6880046F6A1 /* FBSimulatorControlTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = AAB4AC261BBBC6880046F6A1 /* FBSimulatorControlTestCase.m */; };
AAB52AD120C699E20057F947 /* FBSimulatorCrashLogTests.m in Sources */ = {isa = PBXBuildFile; fileRef = AAB52AD020C699E20057F947 /* FBSimulatorCrashLogTests.m */; };
@ -831,7 +832,6 @@
AA08487D1F3F49D600A4BA60 /* FBFutureTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBFutureTests.m; sourceTree = "<group>"; };
AA0949F21F8F4A8A00841A73 /* FBEventReporterIntegrationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBEventReporterIntegrationTests.m; sourceTree = "<group>"; };
AA0CA38620643C6800347424 /* FBCrashLogCommands.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FBCrashLogCommands.h; sourceTree = "<group>"; };
AA0CA3882064F44D00347424 /* FBCrashLogCommands.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBCrashLogCommands.m; sourceTree = "<group>"; };
AA0DC7541CE3A29F0037A8A7 /* FBTestDaemonConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBTestDaemonConnection.h; sourceTree = "<group>"; };
AA0DC7551CE3A29F0037A8A7 /* FBTestDaemonConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBTestDaemonConnection.m; sourceTree = "<group>"; };
AA0EB2811F16905400ABBD7E /* FBApplicationBundle+Simulator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "FBApplicationBundle+Simulator.h"; sourceTree = "<group>"; };
@ -1359,6 +1359,8 @@
AAB207BE1C2099A9007C7908 /* FBSimulatorLoggingEventSink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBSimulatorLoggingEventSink.h; sourceTree = "<group>"; };
AAB207BF1C2099A9007C7908 /* FBSimulatorLoggingEventSink.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBSimulatorLoggingEventSink.m; sourceTree = "<group>"; };
AAB475F320C80F7D00B37634 /* FBiOSTargetCommandForwarderTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBiOSTargetCommandForwarderTests.m; sourceTree = "<group>"; };
AAB475F520C8217F00B37634 /* FBSimulatorCrashLogCommands.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FBSimulatorCrashLogCommands.h; sourceTree = "<group>"; };
AAB475F620C8217F00B37634 /* FBSimulatorCrashLogCommands.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBSimulatorCrashLogCommands.m; sourceTree = "<group>"; };
AAB4AC1D1BB586930046F6A1 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
AAB4AC251BBBC6880046F6A1 /* FBSimulatorControlTestCase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBSimulatorControlTestCase.h; sourceTree = "<group>"; };
AAB4AC261BBBC6880046F6A1 /* FBSimulatorControlTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBSimulatorControlTestCase.m; sourceTree = "<group>"; };
@ -1799,7 +1801,6 @@
AA3EA84F1F31B0DA003FBDC1 /* FBApplicationDataCommands.h */,
AA4D30721E799C1900A9FBD0 /* FBBitmapStreamingCommands.h */,
AA0CA38620643C6800347424 /* FBCrashLogCommands.h */,
AA0CA3882064F44D00347424 /* FBCrashLogCommands.m */,
AA4424CA1F4C11A9006B5E5D /* FBiOSTargetCommandForwarder.h */,
AA4424CB1F4C11A9006B5E5D /* FBiOSTargetCommandForwarder.m */,
AA805F7E1F0D0E0000AB31DE /* FBLogCommands.h */,
@ -1840,6 +1841,8 @@
AA14B55A1DF7401700085855 /* FBSimulatorVideoRecordingCommands.m */,
AA861B6B1E5F8F270080C86B /* FBSimulatorXCTestCommands.h */,
AA861B6C1E5F8F270080C86B /* FBSimulatorXCTestCommands.m */,
AAB475F520C8217F00B37634 /* FBSimulatorCrashLogCommands.h */,
AAB475F620C8217F00B37634 /* FBSimulatorCrashLogCommands.m */,
);
path = Commands;
sourceTree = "<group>";
@ -3334,6 +3337,7 @@
AA25770A1DF16B1300789490 /* FBDefaultsModificationStrategy.h in Headers */,
AAFE93B61CE4954500A50F76 /* FBSimulatorEraseStrategy.h in Headers */,
AA19DA881C77450A009BB89B /* FBSimulatorPool+Private.h in Headers */,
AAB475F720C8217F00B37634 /* FBSimulatorCrashLogCommands.h in Headers */,
AAFE1C121FD68A7D00ADDE66 /* FBSimulatorNotificationUpdateStrategy.h in Headers */,
AA0FF9091E6DE3EC0052634B /* FBVideoEncoderConfiguration.h in Headers */,
AA14B55B1DF7401700085855 /* FBSimulatorVideoRecordingCommands.h in Headers */,
@ -3871,6 +3875,7 @@
AA5CB00D1E09B3E500F77765 /* FBUploadMediaStrategy.m in Sources */,
AA3EA8541F31B20D003FBDC1 /* FBSimulatorApplicationDataCommands.m in Sources */,
AADDED301D6D81F80011EE15 /* FBSimulatorProcessFetcher.m in Sources */,
AAB475F820C8217F00B37634 /* FBSimulatorCrashLogCommands.m in Sources */,
AA4242EE1C528338008ABD80 /* FBFramebuffer.m in Sources */,
AAE42AA91D2D77D800DCD0EA /* FBSimulatorBridge.m in Sources */,
AA14B55C1DF7401700085855 /* FBSimulatorVideoRecordingCommands.m in Sources */,
@ -4168,7 +4173,6 @@
AA308FF720E37F9A00503C90 /* FBFutureContextManager.m in Sources */,
D76C2AEF1F13F61E000EF13D /* FBEventReporterSubject.m in Sources */,
AA14B5601DF8017900085855 /* FBiOSTargetDiagnostics.m in Sources */,
AA0CA3892064F44D00347424 /* FBCrashLogCommands.m in Sources */,
EEBD60951C908F8500298A07 /* FBCollectionInformation.m in Sources */,
AAF026F11F25ED1A0091FDAB /* FBSocketServer.m in Sources */,
AA4B4B211F3DAADD005BD475 /* FBApplicationInstallConfiguration.m in Sources */,

Просмотреть файл

@ -0,0 +1,20 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import <Foundation/Foundation.h>
#import <FBControlCore/FBControlCore.h>
NS_ASSUME_NONNULL_BEGIN
@interface FBSimulatorCrashLogCommands : NSObject <FBCrashLogCommands>
@end
NS_ASSUME_NONNULL_END

Просмотреть файл

@ -0,0 +1,71 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "FBSimulatorCrashLogCommands.h"
#import "FBSimulator.h"
@interface FBSimulatorCrashLogCommands ()
@property (nonatomic, weak, readonly) FBSimulator *simulator;
@property (nonatomic, strong, readonly) FBCrashLogNotifier *notifier;
@end
@implementation FBSimulatorCrashLogCommands
#pragma mark Initializers
+ (instancetype)commandsWithTarget:(id<FBiOSTarget>)target
{
NSParameterAssert([target isKindOfClass:FBSimulator.class]);
return [[self alloc] initWithSimulator:(FBSimulator *)target notifier:FBCrashLogNotifier.sharedInstance];
}
- (instancetype)initWithSimulator:(FBSimulator *)simulator notifier:(FBCrashLogNotifier *)notifier
{
self = [super init];
if (!self) {
return nil;
}
_simulator = simulator;
_notifier = notifier;
return self;
}
#pragma mark id<FBiOSTarget>
- (FBFuture<FBCrashLogInfo *> *)notifyOfCrash:(NSPredicate *)predicate
{
return [self.notifier nextCrashLogForPredicate:predicate];
}
- (FBFuture<NSArray<FBCrashLogInfo *> *> *)crashes:(NSPredicate *)predicate useCache:(BOOL)useCache
{
return [FBFuture futureWithResult:[self.notifier.store ingestedCrashLogsMatchingPredicate:predicate]];
}
- (FBFuture<NSArray<FBCrashLogInfo *> *> *)pruneCrashes:(NSPredicate *)predicate
{
// Unfortunately, the Crash Logs that are created for Simulators may not contain the UDID of the Simulator.
// Crashes will not contain a UDID if they are launching System Apps that are present in the RuntimeRoot, not the Simulator Data Directory.
// If they are Applications installed by the User, the UDID will appear in the launch path, as the Application is installed relative to the Simulator's Simulator Data Directory.
// For this reason, we need to be conservative about which Crash Logs to prune, otherwise we may end up deleting the crash logs of another Simulator, or something running on the host.
// Deleting these behind the back of the API is not something that makes sense.
// We ensure that *any* crash logs that are to be deleted *must* contain the UDID of the Simulator.
NSPredicate *simulatorPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[
[FBCrashLogInfo predicateForExecutablePathContains:self.simulator.udid],
predicate,
]];
return [FBFuture futureWithResult:[self.notifier.store pruneCrashLogsMatchingPredicate:simulatorPredicate]];
}
@end

Просмотреть файл

@ -23,19 +23,21 @@
#import "FBMutableSimulatorEventSink.h"
#import "FBSimulatorAgentCommands.h"
#import "FBSimulatorApplicationCommands.h"
#import "FBSimulatorApplicationDataCommands.h"
#import "FBSimulatorBridgeCommands.h"
#import "FBSimulatorConfiguration+CoreSimulator.h"
#import "FBSimulatorConfiguration.h"
#import "FBSimulatorControlConfiguration.h"
#import "FBSimulatorControlOperator.h"
#import "FBSimulatorCrashLogCommands.h"
#import "FBSimulatorDiagnostics.h"
#import "FBSimulatorError.h"
#import "FBSimulatorMutableState.h"
#import "FBSimulatorEventSink.h"
#import "FBSimulatorHIDEvent.h"
#import "FBSimulatorLifecycleCommands.h"
#import "FBSimulatorLogCommands.h"
#import "FBSimulatorLoggingEventSink.h"
#import "FBSimulatorMutableState.h"
#import "FBSimulatorNotificationEventSink.h"
#import "FBSimulatorPool.h"
#import "FBSimulatorScreenshotCommands.h"
@ -43,7 +45,6 @@
#import "FBSimulatorSettingsCommands.h"
#import "FBSimulatorVideoRecordingCommands.h"
#import "FBSimulatorXCTestCommands.h"
#import "FBSimulatorApplicationDataCommands.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wprotocol"
@ -305,16 +306,16 @@
static NSArray<Class> *commandClasses;
dispatch_once(&onceToken, ^{
commandClasses = @[
FBHostCrashLogCommands.class,
FBSimulatorScreenshotCommands.class,
FBSimulatorAgentCommands.class,
FBSimulatorApplicationCommands.class,
FBSimulatorApplicationDataCommands.class,
FBSimulatorBridgeCommands.class,
FBSimulatorCrashLogCommands.class,
FBSimulatorKeychainCommands.class,
FBSimulatorLaunchCtlCommands.class,
FBSimulatorLifecycleCommands.class,
FBSimulatorLogCommands.class,
FBSimulatorScreenshotCommands.class,
FBSimulatorSettingsCommands.class,
FBSimulatorVideoRecordingCommands.class,
FBSimulatorXCTestCommands.class,
@ -339,6 +340,7 @@
static NSSet<NSString *> *statefulCommands;
dispatch_once(&onceToken, ^{
statefulCommands = [NSSet setWithArray:@[
FBSimulatorCrashLogCommands.class,
FBSimulatorVideoRecordingCommands.class,
]];
});

Просмотреть файл

@ -443,7 +443,13 @@
return nil;
}
- (FBFuture<NSArray<FBCrashLogInfo *> *> *)crashes:(NSPredicate *)predicate
- (FBFuture<NSArray<FBCrashLogInfo *> *> *)crashes:(NSPredicate *)predicate useCache:(BOOL)useCache
{
NSAssert(NO, @"-[%@ %@] is not yet supported", NSStringFromClass(self.class), NSStringFromSelector(_cmd));
return nil;
}
- (FBFuture<NSArray<FBCrashLogInfo *> *> *)pruneCrashes:(NSPredicate *)predicate
{
NSAssert(NO, @"-[%@ %@] is not yet supported", NSStringFromClass(self.class), NSStringFromSelector(_cmd));
return nil;