FBSimulatorControl/Management/FBSimulator.m (270 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 "FBSimulator.h"
#import "FBSimulator+Private.h"
#import <CoreSimulator/SimDevice.h>
#import <CoreSimulator/SimDeviceSet.h>
#import <CoreSimulator/SimDeviceType.h>
#import <CoreSimulator/SimRuntime.h>
#import <Foundation/Foundation.h>
#import <FBControlCore/FBControlCore.h>
#import "FBAppleSimctlCommandExecutor.h"
#import "FBSimulatorApplicationCommands.h"
#import "FBSimulatorConfiguration+CoreSimulator.h"
#import "FBSimulatorConfiguration.h"
#import "FBSimulatorControlConfiguration.h"
#import "FBSimulatorCrashLogCommands.h"
#import "FBSimulatorDebuggerCommands.h"
#import "FBSimulatorDapServerCommands.h"
#import "FBSimulatorError.h"
#import "FBSimulatorFileCommands.h"
#import "FBSimulatorHIDEvent.h"
#import "FBSimulatorLifecycleCommands.h"
#import "FBSimulatorLocationCommands.h"
#import "FBSimulatorMemoryCommands.h"
#import "FBSimulatorNotificationCommands.h"
#import "FBSimulatorLogCommands.h"
#import "FBSimulatorMediaCommands.h"
#import "FBSimulatorProcessSpawnCommands.h"
#import "FBSimulatorScreenshotCommands.h"
#import "FBSimulatorSet.h"
#import "FBSimulatorSettingsCommands.h"
#import "FBSimulatorVideoRecordingCommands.h"
#import "FBSimulatorXCTestCommands.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wprotocol"
#pragma clang diagnostic ignored "-Wincomplete-implementation"
static NSString *const DefaultDeviceSet = @"~/Library/Developer/CoreSimulator/Devices";
@implementation FBSimulator
@synthesize auxillaryDirectory = _auxillaryDirectory;
@synthesize temporaryDirectory = _temporaryDirectory;
@synthesize logger = _logger;
@dynamic xctestPath;
#pragma mark Lifecycle
+ (instancetype)fromSimDevice:(SimDevice *)device configuration:(nullable FBSimulatorConfiguration *)configuration set:(FBSimulatorSet *)set
{
return [[FBSimulator alloc]
initWithDevice:device
configuration:configuration ?: [FBSimulatorConfiguration inferSimulatorConfigurationFromDeviceSynthesizingMissing:device]
set:set
auxillaryDirectory:[FBSimulator auxillaryDirectoryFromSimDevice:device]
logger:set.logger
reporter:set.reporter];
}
- (instancetype)initWithDevice:(SimDevice *)device configuration:(FBSimulatorConfiguration *)configuration set:(FBSimulatorSet *)set auxillaryDirectory:(NSString *)auxillaryDirectory logger:(id<FBControlCoreLogger>)logger reporter:(id<FBEventReporter>)reporter
{
self = [super init];
if (!self) {
return nil;
}
_device = device;
_configuration = configuration;
_set = set;
_auxillaryDirectory = auxillaryDirectory;
_logger = [logger withName:device.UDID.UUIDString];
_forwarder = [FBLoggingWrapper
wrap:[FBiOSTargetCommandForwarder forwarderWithTarget:self commandClasses:FBSimulator.commandResponders statefulCommands:FBSimulator.statefulCommands]
simplifiedNaming:NO
eventReporter:reporter
logger:logger];
return self;
}
#pragma mark FBiOSTarget
- (NSString *)uniqueIdentifier
{
return self.udid;
}
- (NSString *)udid
{
return self.device.UDID.UUIDString;
}
- (NSString *)name
{
return self.device.name;
}
- (FBiOSTargetState)state
{
return self.device.state;
}
- (FBiOSTargetType)targetType
{
return FBiOSTargetTypeSimulator;
}
- (FBArchitecture)architecture
{
return self.configuration.device.simulatorArchitecture;
}
- (FBDeviceType *)deviceType
{
return self.configuration.device;
}
- (FBOSVersion *)osVersion
{
return self.configuration.os;
}
- (NSString *)runtimeRootDirectory
{
return self.device.runtime.root;
}
- (NSString *)platformRootDirectory
{
return [FBXcodeConfiguration.developerDirectory stringByAppendingPathComponent:@"Platforms/iPhoneSimulator.platform"];
}
- (FBiOSTargetScreenInfo *)screenInfo
{
SimDeviceType *deviceType = self.device.deviceType;
return [[FBiOSTargetScreenInfo alloc] initWithWidthPixels:(NSUInteger)deviceType.mainScreenSize.width heightPixels:(NSUInteger)deviceType.mainScreenSize.height scale:deviceType.mainScreenScale];
}
- (FBTemporaryDirectory *)temporaryDirectory
{
if (_temporaryDirectory) {
return _temporaryDirectory;
}
_temporaryDirectory = [FBTemporaryDirectory temporaryDirectoryWithLogger:self.logger];
return _temporaryDirectory;
}
- (dispatch_queue_t)workQueue
{
return dispatch_get_main_queue();
}
- (dispatch_queue_t)asyncQueue
{
return dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
}
- (NSDictionary<NSString *, id> *)extendedInformation
{
return @{};
}
- (NSComparisonResult)compare:(id<FBiOSTarget>)target
{
return FBiOSTargetComparison(self, target);
}
- (NSDictionary<NSString *, NSString *> *)replacementMapping
{
return @{
@"%%SIM_ROOT%%": self.dataDirectory,
};
}
- (BOOL)requiresBundlesToBeSigned {
return YES;
}
#pragma mark Properties
- (FBControlCoreProductFamily)productFamily
{
int familyID = self.device.deviceType.productFamilyID;
switch (familyID) {
case 1:
return FBControlCoreProductFamilyiPhone;
case 2:
return FBControlCoreProductFamilyiPad;
case 3:
return FBControlCoreProductFamilyAppleTV;
case 4:
return FBControlCoreProductFamilyAppleWatch;
default:
return FBControlCoreProductFamilyUnknown;
}
}
- (NSString *)stateString
{
return FBiOSTargetStateStringFromState(self.state);
}
- (NSString *)dataDirectory
{
return self.device.dataPath;
}
- (NSString *)customDeviceSetPath
{
return [self.device.deviceSet.setPath isEqualToString:[DefaultDeviceSet stringByExpandingTildeInPath]] ? nil : self.device.deviceSet.setPath;
}
- (FBAppleSimctlCommandExecutor *)simctlExecutor
{
return [FBAppleSimctlCommandExecutor executorForSimulator:self];
}
- (NSString *)coreSimulatorLogsDirectory
{
return [[NSHomeDirectory()
stringByAppendingPathComponent:@"Library/Logs/CoreSimulator"]
stringByAppendingPathComponent:self.udid];
}
- (NSString *)xctestBinaryPath
{
return [FBXcodeConfiguration.developerDirectory
stringByAppendingPathComponent:@"Platforms/iPhoneSimulator.platform/Developer/Library/Xcode/Agents/xctest"];
}
#pragma mark NSObject
- (NSUInteger)hash
{
return self.device.hash;
}
- (BOOL)isEqual:(FBSimulator *)simulator
{
if (![simulator isKindOfClass:self.class]) {
return NO;
}
return [self.device isEqual:simulator.device];
}
- (NSString *)description
{
return FBiOSTargetDescribe(self);
}
#pragma mark Forwarding
- (id)forwardingTargetForSelector:(SEL)selector
{
return [self.forwarder forwardingTargetForSelector:selector];
}
- (void)forwardInvocation:(NSInvocation *)invocation
{
[self.forwarder forwardInvocation:invocation];
}
+ (NSArray<Class> *)commandResponders
{
static dispatch_once_t onceToken;
static NSArray<Class> *commandClasses;
dispatch_once(&onceToken, ^{
commandClasses = @[
FBInstrumentsCommands.class,
FBSimulatorAccessibilityCommands.class,
FBSimulatorApplicationCommands.class,
FBSimulatorCrashLogCommands.class,
FBSimulatorDebuggerCommands.class,
FBSimulatorDapServerCommand.class,
FBSimulatorFileCommands.class,
FBSimulatorKeychainCommands.class,
FBSimulatorLaunchCtlCommands.class,
FBSimulatorLifecycleCommands.class,
FBSimulatorLocationCommands.class,
FBSimulatorLogCommands.class,
FBSimulatorMediaCommands.class,
FBSimulatorProcessSpawnCommands.class,
FBSimulatorScreenshotCommands.class,
FBSimulatorSettingsCommands.class,
FBSimulatorVideoRecordingCommands.class,
FBSimulatorXCTestCommands.class,
FBXCTraceRecordCommands.class,
FBSimulatorNotificationCommands.class,
FBSimulatorMemoryCommands.class,
];
});
return commandClasses;
}
#pragma mark Private
+ (NSString *)auxillaryDirectoryFromSimDevice:(SimDevice *)device
{
return [device.dataPath stringByAppendingPathComponent:@"fbsimulatorcontrol"];
}
+ (NSSet<Class> *)statefulCommands
{
static dispatch_once_t onceToken;
static NSSet<Class> *statefulCommands;
dispatch_once(&onceToken, ^{
statefulCommands = [NSSet setWithArray:@[
FBSimulatorCrashLogCommands.class,
FBSimulatorLifecycleCommands.class,
FBSimulatorScreenshotCommands.class,
FBSimulatorVideoRecordingCommands.class,
FBSimulatorXCTestCommands.class,
]];
});
return statefulCommands;
}
@end
#pragma clang diagnostic pop