FBSimulatorControl/Utility/FBSimulatorLaunchedApplication.m (89 lines of code) (raw):
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "FBSimulatorLaunchedApplication.h"
#import "FBSimulator+Private.h"
#import "FBSimulator.h"
@interface FBSimulatorLaunchedApplication ()
@property (nonatomic, strong, readonly) FBProcessFileAttachment *attachment;
@property (nonatomic, weak, nullable, readonly) FBSimulator *simulator;
@end
@implementation FBSimulatorLaunchedApplication
@synthesize applicationTerminated = _applicationTerminated;
@synthesize processIdentifier = _processIdentifier;
#pragma mark Initializers
+ (FBFuture<FBSimulatorLaunchedApplication *> *)applicationWithSimulator:(FBSimulator *)simulator configuration:(FBApplicationLaunchConfiguration *)configuration attachment:(FBProcessFileAttachment *)attachment launchFuture:(FBFuture<NSNumber *> *)launchFuture
{
return [launchFuture
onQueue:simulator.workQueue map:^(NSNumber *processIdentifierNumber) {
pid_t processIdentifier = processIdentifierNumber.intValue;
FBFuture<NSNull *> *terminationFuture = [FBSimulatorLaunchedApplication terminationFutureForSimulator:simulator processIdentifier:processIdentifier];
FBSimulatorLaunchedApplication *operation = [[self alloc] initWithSimulator:simulator configuration:configuration attachment:attachment processIdentifier:processIdentifier terminationFuture:terminationFuture];
return operation;
}];
}
- (instancetype)initWithSimulator:(FBSimulator *)simulator configuration:(FBApplicationLaunchConfiguration *)configuration attachment:(FBProcessFileAttachment *)attachment processIdentifier:(pid_t)processIdentifier terminationFuture:(FBFuture<NSNull *> *)terminationFuture
{
self = [super init];
if (!self) {
return nil;
}
_simulator = simulator;
_configuration = configuration;
_attachment = attachment;
_processIdentifier = processIdentifier;
_applicationTerminated = [terminationFuture
onQueue:simulator.workQueue chain:^(FBFuture *future) {
return [[attachment detach] chainReplace:future];
}];
return self;
}
#pragma mark Properties
- (NSString *)bundleID
{
return self.configuration.bundleID;
}
- (id<FBProcessFileOutput>)stdOut
{
return self.attachment.stdOut;
}
- (id<FBProcessFileOutput>)stdErr
{
return self.attachment.stdErr;
}
#pragma mark Helpers
+ (FBFuture<NSNull *> *)terminationFutureForSimulator:(FBSimulator *)simulator processIdentifier:(pid_t)processIdentifier
{
return [[[self
processTerminationFutureNotifierForProcessIdentifier:processIdentifier]
mapReplace:NSNull.null]
onQueue:simulator.workQueue respondToCancellation:^{
return [[FBProcessTerminationStrategy
strategyWithProcessFetcher:FBProcessFetcher.new workQueue:simulator.workQueue logger:simulator.logger]
killProcessIdentifier:processIdentifier];
}];
}
+ (FBFuture<NSNumber *> *)processTerminationFutureNotifierForProcessIdentifier:(pid_t)processIdentifier
{
dispatch_queue_t queue = dispatch_queue_create("com.facebook.fbsimulatorcontrol.application_termination_notifier", DISPATCH_QUEUE_SERIAL);
dispatch_source_t source = dispatch_source_create(
DISPATCH_SOURCE_TYPE_PROC,
(unsigned long) processIdentifier,
DISPATCH_PROC_EXIT,
queue
);
FBMutableFuture<NSNumber *> *future = FBMutableFuture.future;
[future onQueue:queue respondToCancellation:^ FBFuture<NSNull *> * {
dispatch_source_cancel(source);
return FBFuture.empty;
}];
dispatch_source_set_event_handler(source, ^(){
[future resolveWithResult:@(processIdentifier)];
dispatch_source_cancel(source);
});
dispatch_resume(source);
return future;
}
#pragma mark NSObject
- (NSString *)description
{
return [NSString stringWithFormat:@"Application Operation %@ | pid %d | State %@", self.configuration.description, self.processIdentifier, self.applicationTerminated];
}
@end