Skip to content

Commit

Permalink
Add synchronization around GTMSessionFetcher's begin/end background t…
Browse files Browse the repository at this point in the history
…ask calls.

Prevents potential check-and-set race condition over the fetcher's background task identifier.
  • Loading branch information
thomasvl committed Mar 6, 2017
1 parent b0d2957 commit a742bdd
Showing 1 changed file with 17 additions and 11 deletions.
28 changes: 17 additions & 11 deletions Source/GTMSessionFetcher.m
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ @interface GTMSessionFetcher ()
@property(atomic, strong, readwrite, GTM_NULLABLE) NSData *downloadResumeData;

#if GTM_BACKGROUND_TASK_FETCHING
@property(assign, atomic) UIBackgroundTaskIdentifier backgroundTaskIdentifier;
// Should always be accessed within an @synchranized(self).
@property(assign, nonatomic) UIBackgroundTaskIdentifier backgroundTaskIdentifier;
#endif

@property(atomic, readwrite, getter=isUsingBackgroundSession) BOOL usingBackgroundSession;
Expand Down Expand Up @@ -837,13 +838,17 @@ - (void)beginFetchMayDelay:(BOOL)mayDelay
// Background task expiration callback - this block is always invoked by
// UIApplication on the main thread.
if (bgTaskID != UIBackgroundTaskInvalid) {
if (bgTaskID == self.backgroundTaskIdentifier) {
self.backgroundTaskIdentifier = UIBackgroundTaskInvalid;
@synchronized(self) {
if (bgTaskID == self.backgroundTaskIdentifier) {
self.backgroundTaskIdentifier = UIBackgroundTaskInvalid;
}
}
[app endBackgroundTask:bgTaskID];
}
}];
self.backgroundTaskIdentifier = bgTaskID;
@synchronized(self) {
self.backgroundTaskIdentifier = bgTaskID;
}
}
#endif

Expand Down Expand Up @@ -1534,14 +1539,15 @@ + (GTMSessionCookieStorage *)staticCookieStorage {
- (void)endBackgroundTask {
// Whenever the connection stops or background execution expires,
// we need to tell UIApplication we're done.
//
// We'll wait on _callbackGroup to ensure that any callbacks in flight have executed,
// and that we access backgroundTaskIdentifier on the main thread, as happens when the
// task has expired.
UIBackgroundTaskIdentifier bgTaskID = self.backgroundTaskIdentifier;
if (bgTaskID != UIBackgroundTaskInvalid) {
self.backgroundTaskIdentifier = UIBackgroundTaskInvalid;
UIBackgroundTaskIdentifier bgTaskID;
@synchronized(self) {
bgTaskID = self.backgroundTaskIdentifier;
if (bgTaskID != UIBackgroundTaskInvalid) {
self.backgroundTaskIdentifier = UIBackgroundTaskInvalid;
}
}

if (bgTaskID != UIBackgroundTaskInvalid) {
id<GTMUIApplicationProtocol> app = [[self class] fetcherUIApplication];
[app endBackgroundTask:bgTaskID];
}
Expand Down

0 comments on commit a742bdd

Please sign in to comment.