Skip to content

Commit 75c2e1b

Browse files
authored
Merge pull request #943 from BranchMetrics/INTENG-7291-fix-keychain
INTENG-7291 fix keychain by moving keychain checks off main
2 parents 0bc502f + fdb04b3 commit 75c2e1b

File tree

3 files changed

+88
-29
lines changed

3 files changed

+88
-29
lines changed

Branch-SDK/Branch-SDK/BNCApplication.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
@interface BNCApplication : NSObject
1818

19+
+ (void)loadCurrentApplicationWithCompletion:(void (^_Nullable)(BNCApplication * _Nonnull application))completion;
20+
1921
/// A reference to the current running application.
2022
+ (BNCApplication*_Nonnull) currentApplication;
2123

@@ -51,4 +53,5 @@
5153

5254
/// The team identifier for the app.
5355
@property (atomic, readonly) NSString*_Nullable teamID;
56+
5457
@end

Branch-SDK/Branch-SDK/BNCApplication.m

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,17 @@
2121

2222
@implementation BNCApplication
2323

24+
// BNCApplication checks a few values in keychain
25+
// Checking keychain from main thread early in the app lifecycle can deadlock. INTENG-7291
26+
+ (void)loadCurrentApplicationWithCompletion:(void (^)(BNCApplication *application))completion {
27+
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
28+
BNCApplication *tmp = [BNCApplication currentApplication];
29+
if (completion) {
30+
completion(tmp);
31+
}
32+
});
33+
}
34+
2435
+ (BNCApplication*) currentApplication {
2536
static BNCApplication *bnc_currentApplication = nil;
2637
static dispatch_once_t onceToken = 0;

Branch-SDK/Branch-SDK/Branch.m

Lines changed: 74 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,10 @@ @interface Branch() <BranchDeepLinkingControllerCompletionDelegate> {
146146
@property (assign, nonatomic) BOOL delayForAppleAds;
147147
@property (strong, nonatomic) NSMutableArray *whiteListedSchemeList;
148148
@property (strong, nonatomic) BNCURLBlackList *URLBlackList;
149+
150+
// dedicated object for locking asyncRequestCount
151+
@property (strong, nonatomic, readwrite) NSObject *asyncRequestCountLock;
152+
149153
@end
150154

151155
@implementation Branch
@@ -236,6 +240,8 @@ - (id)initWithInterface:(BNCServerInterface *)interface
236240
self = [super init];
237241
if (!self) return self;
238242

243+
self.asyncRequestCountLock = [NSObject new];
244+
239245
// Initialize instance variables
240246

241247
_serverInterface = interface;
@@ -249,7 +255,9 @@ - (id)initWithInterface:(BNCServerInterface *)interface
249255
_shouldCallSessionInitCallback = YES;
250256
_processing_sema = dispatch_semaphore_create(1);
251257
_networkCount = 0;
252-
_asyncRequestCount = 0;
258+
@synchronized (self.asyncRequestCountLock) {
259+
_asyncRequestCount = 0;
260+
}
253261
_deepLinkControllers = [[NSMutableDictionary alloc] init];
254262
_whiteListedSchemeList = [[NSMutableArray alloc] init];
255263
_useCookieBasedMatching = YES;
@@ -649,20 +657,28 @@ - (void)initSessionWithLaunchOptions:(NSDictionary *)options
649657
if (![options.allKeys containsObject:UIApplicationLaunchOptionsURLKey] &&
650658
![options.allKeys containsObject:UIApplicationLaunchOptionsUserActivityDictionaryKey]) {
651659

652-
self.asyncRequestCount = 0;
660+
@synchronized (self.asyncRequestCountLock) {
661+
self.asyncRequestCount = 0;
662+
}
653663

654664
// These methods will increment self.asyncRequestCount if they make an async call:
655665

666+
// load application data
667+
[self loadApplicationData];
656668
// load user agent
657669
[self loadUserAgent];
658670
// If Facebook SDK is present, call deferred app link check here which will later on call initUserSession
659671
[self checkFacebookAppLinks];
660672
// If developer opted in, call deferred apple search attribution API here which will later on call initUserSession
661673
[self checkAppleSearchAdsAttribution];
662674

663-
if (self.asyncRequestCount == 0) {
664-
// If we're not looking for App Links or Apple Search Ads, initialize
665-
[self initUserSessionAndCallCallback:YES];
675+
@synchronized (self.asyncRequestCountLock) {
676+
if (self.asyncRequestCount == 0) {
677+
// If we're not looking for App Links or Apple Search Ads, initialize
678+
dispatch_async(dispatch_get_main_queue(), ^{
679+
[self initUserSessionAndCallCallback:YES];
680+
});
681+
}
666682
}
667683
}
668684
// Handle case where there is Universal Link present
@@ -937,16 +953,38 @@ - (void)handlePushNotification:(NSDictionary *)userInfo {
937953
}
938954

939955
- (void)loadUserAgent {
940-
self.asyncRequestCount++;
956+
@synchronized (self.asyncRequestCountLock) {
957+
self.asyncRequestCount++;
958+
}
959+
941960
[[BNCUserAgentCollector instance] loadUserAgentForSystemBuildVersion:[BNCDeviceInfo systemBuildVersion] withCompletion:^(NSString * _Nullable userAgent) {
942-
self.asyncRequestCount--;
943-
// If there's another async attribution check in flight, don't continue with init:
944-
if (self.asyncRequestCount > 0) return;
961+
@synchronized (self.asyncRequestCountLock) {
962+
self.asyncRequestCount--;
963+
if (self.asyncRequestCount > 0) return;
945964

946-
self.preferenceHelper.shouldWaitForInit = NO;
947-
dispatch_async(dispatch_get_main_queue(), ^{
948-
[self initUserSessionAndCallCallback:(self.initializationStatus != BNCInitStatusInitialized)];
949-
});
965+
self.preferenceHelper.shouldWaitForInit = NO;
966+
dispatch_async(dispatch_get_main_queue(), ^{
967+
[self initUserSessionAndCallCallback:(self.initializationStatus != BNCInitStatusInitialized)];
968+
});
969+
}
970+
}];
971+
}
972+
973+
- (void)loadApplicationData {
974+
@synchronized (self.asyncRequestCountLock) {
975+
self.asyncRequestCount++;
976+
}
977+
978+
[BNCApplication loadCurrentApplicationWithCompletion:^(BNCApplication *application) {
979+
@synchronized (self.asyncRequestCountLock) {
980+
self.asyncRequestCount--;
981+
if (self.asyncRequestCount > 0) return;
982+
983+
self.preferenceHelper.shouldWaitForInit = NO;
984+
dispatch_async(dispatch_get_main_queue(), ^{
985+
[self initUserSessionAndCallCallback:(self.initializationStatus != BNCInitStatusInitialized)];
986+
});
987+
}
950988
}];
951989
}
952990

@@ -989,8 +1027,10 @@ - (BOOL)checkAppleSearchAdsAttribution {
9891027

9901028
self.preferenceHelper.shouldWaitForInit = YES;
9911029
self.preferenceHelper.checkedAppleSearchAdAttribution = YES;
992-
self.asyncRequestCount++;
993-
1030+
@synchronized (self.asyncRequestCountLock) {
1031+
self.asyncRequestCount++;
1032+
}
1033+
9941034
NSDate *startDate = [NSDate date];
9951035
_Atomic __block BOOL hasBeenCalled = NO;
9961036
void (^__nullable completionBlock)(NSDictionary *attrDetails, NSError *error) =
@@ -1021,14 +1061,15 @@ - (BOOL)checkAppleSearchAdsAttribution {
10211061
BNCLogError(@"Error while getting Apple Search Ad attribution: %@.", error);
10221062
}
10231063

1024-
self.asyncRequestCount--;
1025-
// If there's another async attribution check in flight, don't continue with init:
1026-
if (self.asyncRequestCount > 0) return;
1064+
@synchronized (self.asyncRequestCountLock) {
1065+
self.asyncRequestCount--;
1066+
if (self.asyncRequestCount > 0) return;
10271067

1028-
self.preferenceHelper.shouldWaitForInit = NO;
1029-
dispatch_async(dispatch_get_main_queue(), ^{
1030-
[self initUserSessionAndCallCallback:(self.initializationStatus != BNCInitStatusInitialized)];
1031-
});
1068+
self.preferenceHelper.shouldWaitForInit = NO;
1069+
dispatch_async(dispatch_get_main_queue(), ^{
1070+
[self initUserSessionAndCallCallback:(self.initializationStatus != BNCInitStatusInitialized)];
1071+
});
1072+
}
10321073
}
10331074
};
10341075

@@ -1058,17 +1099,21 @@ - (BOOL)checkFacebookAppLinks {
10581099

10591100
if ([self.FBSDKAppLinkUtility methodForSelector:fetchDeferredAppLink]) {
10601101
void (^__nullable completionBlock)(NSURL *appLink, NSError *error) = ^void(NSURL *__nullable appLink, NSError *__nullable error) {
1061-
self.asyncRequestCount--;
1062-
1063-
// if there's another async attribution check in flight, don't continue with init
1064-
if (self.asyncRequestCount > 0) { return; }
1102+
@synchronized (self.asyncRequestCountLock) {
1103+
self.asyncRequestCount--;
10651104

1066-
self.preferenceHelper.shouldWaitForInit = NO;
1105+
if (self.asyncRequestCount > 0) { return; }
1106+
self.preferenceHelper.shouldWaitForInit = NO;
10671107

1068-
[self handleDeepLink:appLink];
1108+
dispatch_async(dispatch_get_main_queue(), ^{
1109+
[self handleDeepLink:appLink];
1110+
});
1111+
}
10691112
};
10701113

1071-
self.asyncRequestCount++;
1114+
@synchronized (self.asyncRequestCountLock) {
1115+
self.asyncRequestCount++;
1116+
}
10721117
self.preferenceHelper.checkedFacebookAppLinks = YES;
10731118
self.preferenceHelper.shouldWaitForInit = YES;
10741119

0 commit comments

Comments
 (0)