From 9eedd44dd58ef9e70a5d89eb77d68d72aff16839 Mon Sep 17 00:00:00 2001 From: Lawrence Lomax Date: Thu, 8 Sep 2016 07:29:38 -0700 Subject: [PATCH] Fix 'Unclaimed' Application Fetching Summary: There is one very subtle case that will cause the 'unclaimed' (read Xcode-launched) Application fetching will fail: 1) Boot a Simulator via conventional means like via Xcode or an alias to the `Simulator.app` 2) Boot another Simulator.app via `fbsimctl` 3) `fbsimctl shutdown` will properly kill the sim from #1 but not #2 This is because the booting of #2 overwrites the `NSUserDefaults` from #1 so the 'unclaimed' simulator container app doesn't correlate. The check for the UDID in the `NSUserDefaults` is unecessary since we can reasonably assume if there is one more Simulator app that is unclaimed this must be the sole remaining Simulator.app for the `launchd_sim`. Reviewed By: marekcirkos Differential Revision: D3811248 fbshipit-source-id: e9f0fb97c8370f5966f191eebbd246f61ec722b5 --- .../Strategies/FBSimulatorInflationStrategy.m | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/FBSimulatorControl/Strategies/FBSimulatorInflationStrategy.m b/FBSimulatorControl/Strategies/FBSimulatorInflationStrategy.m index 8c3078b3..f182f415 100644 --- a/FBSimulatorControl/Strategies/FBSimulatorInflationStrategy.m +++ b/FBSimulatorControl/Strategies/FBSimulatorInflationStrategy.m @@ -72,21 +72,27 @@ - (instancetype)initWithSet:(FBSimulatorSet *)set processFetcher:(FBSimulatorPro } // Inflate the Simulators and join the array. - NSArray *inflatedSimulators = [self inflateSimulators:simulatorsToInflate.allObjects availableDevices:availableDevices]; + NSArray *previouslyIdentifiedContainerApplications = [[simulators valueForKey:@"containerApplication"] filteredArrayUsingPredicate:NSPredicate.notNullPredicate]; + NSArray *inflatedSimulators = [self + inflateSimulators:simulatorsToInflate.allObjects + availableDevices:availableDevices + previouslyIdentifiedContainerApplications:previouslyIdentifiedContainerApplications]; return [simulators arrayByAddingObjectsFromArray:inflatedSimulators]; } #pragma mark Private -- (NSArray *)inflateSimulators:(NSArray *)simulatorsToInflate availableDevices:(NSDictionary *)availableDevices +- (NSArray *)inflateSimulators:(NSArray *)simulatorsToInflate availableDevices:(NSDictionary *)availableDevices previouslyIdentifiedContainerApplications:(NSArray *)previouslyIdentifiedContainerApplications { NSArray *unclaimedContainerApplications = nil; NSDictionary *launchdSims = [self.processFetcher launchdProcessesByUDIDs:simulatorsToInflate]; NSDictionary *containerApplications = [self.processFetcher simulatorApplicationProcessesByUDIDs:simulatorsToInflate unclaimed:&unclaimedContainerApplications]; + containerApplications = [FBSimulatorInflationStrategy adjustContainerApplicationsMapping:containerApplications forLaunchdSims:launchdSims - withUnclaimedContainerApplications:unclaimedContainerApplications]; + withUnclaimedContainerApplications:unclaimedContainerApplications + previouslyIdentifiedContainerApplications:previouslyIdentifiedContainerApplications]; NSMutableArray *inflatedSimulators = [NSMutableArray array]; for (NSString *udid in simulatorsToInflate) { @@ -102,22 +108,28 @@ - (instancetype)initWithSet:(FBSimulatorSet *)set processFetcher:(FBSimulatorPro return [inflatedSimulators copy]; } -+ (NSDictionary *)adjustContainerApplicationsMapping:(NSDictionary *)containerApplications forLaunchdSims:(NSDictionary *)launchdSims withUnclaimedContainerApplications:(NSArray *)unclaimedContainerApplications ++ (NSDictionary *)adjustContainerApplicationsMapping:(NSDictionary *)containerApplications forLaunchdSims:(NSDictionary *)launchdSims withUnclaimedContainerApplications:(NSArray *)unclaimedContainerApplications previouslyIdentifiedContainerApplications:(NSArray *)previouslyIdentifiedContainerApplications { + // We can only correlate when we have one unclaimed Simulator Application. if (unclaimedContainerApplications.count != 1) { return containerApplications; } + // Confirm that this one remaining container application hasn't been previously correlated with another Simulator. + NSMutableSet *remainingUnclaimed = [NSMutableSet setWithArray:unclaimedContainerApplications]; + [remainingUnclaimed minusSet:[NSSet setWithArray:previouslyIdentifiedContainerApplications]]; + if (remainingUnclaimed.count != 1) { + return containerApplications; + } - NSMutableSet *unclaimedSimulatorUDIDs = [NSMutableSet setWithArray:launchdSims.allKeys]; + // Check the Simulators that are unclaimed, if there are none there's nothing to correlate. + NSMutableSet *unclaimedSimulatorUDIDs = [NSMutableSet setWithArray:launchdSims.allKeys]; [unclaimedSimulatorUDIDs minusSet:[NSSet setWithArray:containerApplications.allKeys]]; if (unclaimedSimulatorUDIDs.count != 1) { return containerApplications; } - NSString *untaggedAssumedUDID = FBSimulator.simulatorApplicationPreferences[@"CurrentDeviceUDID"]; - if (![untaggedAssumedUDID isEqualToString:unclaimedSimulatorUDIDs.anyObject]) { - return containerApplications; - } + // Assume that this sole unclaimed Simulator App belongs to the 'Containerless' Booted UDID. + NSString *untaggedAssumedUDID = [unclaimedSimulatorUDIDs anyObject]; NSMutableDictionary *adjustedContainerApplications = [containerApplications mutableCopy]; adjustedContainerApplications[untaggedAssumedUDID] = [unclaimedContainerApplications firstObject]; return [adjustedContainerApplications copy];