diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 1744efb32..3eac90b3b 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -926,14 +926,10 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) { continue; } - [self.editingDatabaseConnection - asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [OWSIdentityManager.sharedManager setVerificationState:OWSVerificationStateDefault - identityKey:identityKey - recipientId:recipientId - isUserInitiatedChange:YES - protocolContext:transaction]; - }]; + [OWSIdentityManager.sharedManager setVerificationState:OWSVerificationStateDefault + identityKey:identityKey + recipientId:recipientId + isUserInitiatedChange:YES]; } } diff --git a/Signal/src/ViewControllers/DebugUI/DebugUISessionState.m b/Signal/src/ViewControllers/DebugUI/DebugUISessionState.m index d21db0e81..4deb29891 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUISessionState.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUISessionState.m @@ -99,20 +99,29 @@ NS_ASSUME_NONNULL_BEGIN #if DEBUG + (void)clearSessionAndIdentityStore { - [[TSStorageManager sharedManager] resetSessionStore]; - [[OWSIdentityManager sharedManager] clearIdentityState]; + [TSStorageManager.sharedManager.newDatabaseConnection + readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [[TSStorageManager sharedManager] resetSessionStore:transaction]; + [[OWSIdentityManager sharedManager] clearIdentityState:transaction]; + }]; } + (void)snapshotSessionAndIdentityStore { - [[TSStorageManager sharedManager] snapshotSessionStore]; - [[OWSIdentityManager sharedManager] snapshotIdentityState]; + [TSStorageManager.sharedManager.newDatabaseConnection + readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [[TSStorageManager sharedManager] snapshotSessionStore:transaction]; + [[OWSIdentityManager sharedManager] snapshotIdentityState:transaction]; + }]; } + (void)restoreSessionAndIdentityStore { - [[TSStorageManager sharedManager] restoreSessionStore]; - [[OWSIdentityManager sharedManager] restoreIdentityState]; + [TSStorageManager.sharedManager.newDatabaseConnection + readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [[TSStorageManager sharedManager] restoreSessionStore:transaction]; + [[OWSIdentityManager sharedManager] restoreIdentityState:transaction]; + }]; } #endif diff --git a/Signal/src/ViewControllers/FingerprintViewScanController.m b/Signal/src/ViewControllers/FingerprintViewScanController.m index 1503fbeee..cce0be4f5 100644 --- a/Signal/src/ViewControllers/FingerprintViewScanController.m +++ b/Signal/src/ViewControllers/FingerprintViewScanController.m @@ -200,15 +200,10 @@ NS_ASSUME_NONNULL_BEGIN @"Button that marks user as verified after a successful fingerprint scan.") style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { - [TSStorageManager.sharedManager.newDatabaseConnection - asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [OWSIdentityManager.sharedManager - setVerificationState:OWSVerificationStateVerified - identityKey:identityKey - recipientId:recipientId - isUserInitiatedChange:YES - protocolContext:transaction]; - }]; + [OWSIdentityManager.sharedManager setVerificationState:OWSVerificationStateVerified + identityKey:identityKey + recipientId:recipientId + isUserInitiatedChange:YES]; [viewController dismissViewControllerAnimated:true completion:nil]; }]]; UIAlertAction *dismissAction = diff --git a/Signal/src/ViewControllers/ShowGroupMembersViewController.m b/Signal/src/ViewControllers/ShowGroupMembersViewController.m index 04f024bf8..a4dcb74f1 100644 --- a/Signal/src/ViewControllers/ShowGroupMembersViewController.m +++ b/Signal/src/ViewControllers/ShowGroupMembersViewController.m @@ -251,14 +251,10 @@ NS_ASSUME_NONNULL_BEGIN OWSFail(@"Missing identity key for: %@", recipientId); continue; } - [TSStorageManager.sharedManager.newDatabaseConnection - asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [identityManger setVerificationState:OWSVerificationStateDefault - identityKey:identityKey - recipientId:recipientId - isUserInitiatedChange:YES - protocolContext:transaction]; - }]; + [identityManger setVerificationState:OWSVerificationStateDefault + identityKey:identityKey + recipientId:recipientId + isUserInitiatedChange:YES]; } } diff --git a/SignalServiceKit/src/Account/TSAccountManager.m b/SignalServiceKit/src/Account/TSAccountManager.m index f0cd99ac6..344f161b9 100644 --- a/SignalServiceKit/src/Account/TSAccountManager.m +++ b/SignalServiceKit/src/Account/TSAccountManager.m @@ -104,9 +104,10 @@ NSString *const TSAccountManager_ServerSignalingKey = @"TSStorageServerSignaling _phoneNumberAwaitingVerification = nil; [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { [transaction removeAllObjectsInCollection:TSAccountManager_UserAccountCollection]; + + [[TSStorageManager sharedManager] resetSessionStore:transaction]; }]; } - [[TSStorageManager sharedManager] resetSessionStore]; } + (BOOL)isRegistered diff --git a/SignalServiceKit/src/Messages/OWSIdentityManager.h b/SignalServiceKit/src/Messages/OWSIdentityManager.h index d79cf4c87..515710c8e 100644 --- a/SignalServiceKit/src/Messages/OWSIdentityManager.h +++ b/SignalServiceKit/src/Messages/OWSIdentityManager.h @@ -19,7 +19,7 @@ extern const NSUInteger kIdentityKeyLength; @class OWSRecipientIdentity; @class OWSSignalServiceProtosVerified; @class OWSStorage; -@class OWSStorage; +@class YapDatabaseReadWriteTransaction; // This class can be safely accessed and used from any thread. @interface OWSIdentityManager : NSObject @@ -44,6 +44,11 @@ extern const NSUInteger kIdentityKeyLength; - (OWSVerificationState)verificationStateForRecipientId:(NSString *)recipientId transaction:(YapDatabaseReadTransaction *)transaction; +- (void)setVerificationState:(OWSVerificationState)verificationState + identityKey:(NSData *)identityKey + recipientId:(NSString *)recipientId + isUserInitiatedChange:(BOOL)isUserInitiatedChange; + - (nullable OWSRecipientIdentity *)recipientIdentityForRecipientId:(NSString *)recipientId; /** @@ -64,10 +69,10 @@ extern const NSUInteger kIdentityKeyLength; #if DEBUG // Clears everything except the local identity key. -- (void)clearIdentityState; +- (void)clearIdentityState:(YapDatabaseReadWriteTransaction *)transaction; -- (void)snapshotIdentityState; -- (void)restoreIdentityState; +- (void)snapshotIdentityState:(YapDatabaseReadWriteTransaction *)transaction; +- (void)restoreIdentityState:(YapDatabaseReadWriteTransaction *)transaction; #endif @end diff --git a/SignalServiceKit/src/Messages/OWSIdentityManager.m b/SignalServiceKit/src/Messages/OWSIdentityManager.m index 11492c9ab..d931cc6ff 100644 --- a/SignalServiceKit/src/Messages/OWSIdentityManager.m +++ b/SignalServiceKit/src/Messages/OWSIdentityManager.m @@ -23,7 +23,7 @@ #import "TSStorageManager.h" #import "TextSecureKitEnv.h" #import "YapDatabaseConnection+OWS.h" -#import "YapDatabaseReadTransaction+OWS.h" +#import "YapDatabaseTransaction+OWS.h" #import #import #import @@ -271,6 +271,23 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa return NO; } +- (void)setVerificationState:(OWSVerificationState)verificationState + identityKey:(NSData *)identityKey + recipientId:(NSString *)recipientId + isUserInitiatedChange:(BOOL)isUserInitiatedChange +{ + OWSAssert(identityKey.length == kStoredIdentityKeyLength); + OWSAssert(recipientId.length > 0); + + [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { + [self setVerificationState:verificationState + identityKey:identityKey + recipientId:recipientId + isUserInitiatedChange:isUserInitiatedChange + transaction:transaction]; + }]; +} + - (void)setVerificationState:(OWSVerificationState)verificationState identityKey:(NSData *)identityKey recipientId:(NSString *)recipientId @@ -283,10 +300,27 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa YapDatabaseReadWriteTransaction *transaction = protocolContext; + [self setVerificationState:verificationState + identityKey:identityKey + recipientId:recipientId + isUserInitiatedChange:isUserInitiatedChange + transaction:transaction]; +} + +- (void)setVerificationState:(OWSVerificationState)verificationState + identityKey:(NSData *)identityKey + recipientId:(NSString *)recipientId + isUserInitiatedChange:(BOOL)isUserInitiatedChange + transaction:(YapDatabaseReadWriteTransaction *)transaction +{ + OWSAssert(identityKey.length == kStoredIdentityKeyLength); + OWSAssert(recipientId.length > 0); + OWSAssert(transaction); + // TODO: Remove all @synchronized // Ensure a remote identity exists for this key. We may be learning about // it for the first time. - [self saveRemoteIdentity:identityKey recipientId:recipientId protocolContext:protocolContext]; + [self saveRemoteIdentity:identityKey recipientId:recipientId protocolContext:transaction]; OWSRecipientIdentity *recipientIdentity = [OWSRecipientIdentity fetchObjectWithUniqueID:recipientId transaction:transaction]; @@ -845,23 +879,23 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa #pragma mark - Debug #if DEBUG -- (void)clearIdentityState +- (void)clearIdentityState:(YapDatabaseReadWriteTransaction *)transaction { - [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - NSMutableArray *identityKeysToRemove = [NSMutableArray new]; - [transaction enumerateKeysInCollection:TSStorageManagerIdentityKeyStoreCollection - usingBlock:^(NSString *_Nonnull key, BOOL *_Nonnull stop) { - if ([key isEqualToString:TSStorageManagerIdentityKeyStoreIdentityKey]) { - // Don't delete our own key. - return; - } - [identityKeysToRemove addObject:key]; - }]; - for (NSString *key in identityKeysToRemove) { - [transaction removeObjectForKey:key inCollection:TSStorageManagerIdentityKeyStoreCollection]; - } - [transaction removeAllObjectsInCollection:TSStorageManagerTrustedKeysCollection]; - }]; + OWSAssert(transaction); + + NSMutableArray *identityKeysToRemove = [NSMutableArray new]; + [transaction enumerateKeysInCollection:TSStorageManagerIdentityKeyStoreCollection + usingBlock:^(NSString *_Nonnull key, BOOL *_Nonnull stop) { + if ([key isEqualToString:TSStorageManagerIdentityKeyStoreIdentityKey]) { + // Don't delete our own key. + return; + } + [identityKeysToRemove addObject:key]; + }]; + for (NSString *key in identityKeysToRemove) { + [transaction removeObjectForKey:key inCollection:TSStorageManagerIdentityKeyStoreCollection]; + } + [transaction removeAllObjectsInCollection:TSStorageManagerTrustedKeysCollection]; } - (NSString *)identityKeySnapshotFilePath @@ -878,20 +912,24 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa return [dirPath stringByAppendingPathComponent:@".trusted-key-snapshot"]; } -- (void)snapshotIdentityState +- (void)snapshotIdentityState:(YapDatabaseReadWriteTransaction *)transaction { - [self.dbConnection snapshotCollection:TSStorageManagerIdentityKeyStoreCollection - snapshotFilePath:self.identityKeySnapshotFilePath]; - [self.dbConnection snapshotCollection:TSStorageManagerTrustedKeysCollection - snapshotFilePath:self.trustedKeySnapshotFilePath]; + OWSAssert(transaction); + + [transaction snapshotCollection:TSStorageManagerIdentityKeyStoreCollection + snapshotFilePath:self.identityKeySnapshotFilePath]; + [transaction snapshotCollection:TSStorageManagerTrustedKeysCollection + snapshotFilePath:self.trustedKeySnapshotFilePath]; } -- (void)restoreIdentityState +- (void)restoreIdentityState:(YapDatabaseReadWriteTransaction *)transaction { - [self.dbConnection restoreSnapshotOfCollection:TSStorageManagerIdentityKeyStoreCollection - snapshotFilePath:self.identityKeySnapshotFilePath]; - [self.dbConnection restoreSnapshotOfCollection:TSStorageManagerTrustedKeysCollection - snapshotFilePath:self.trustedKeySnapshotFilePath]; + OWSAssert(transaction); + + [transaction restoreSnapshotOfCollection:TSStorageManagerIdentityKeyStoreCollection + snapshotFilePath:self.identityKeySnapshotFilePath]; + [transaction restoreSnapshotOfCollection:TSStorageManagerTrustedKeysCollection + snapshotFilePath:self.trustedKeySnapshotFilePath]; } #endif diff --git a/SignalServiceKit/src/Storage/AxolotlStore/TSStorageManager+SessionStore.h b/SignalServiceKit/src/Storage/AxolotlStore/TSStorageManager+SessionStore.h index f6847380e..bf92c4717 100644 --- a/SignalServiceKit/src/Storage/AxolotlStore/TSStorageManager+SessionStore.h +++ b/SignalServiceKit/src/Storage/AxolotlStore/TSStorageManager+SessionStore.h @@ -11,13 +11,15 @@ NS_ASSUME_NONNULL_BEGIN - (void)archiveAllSessionsForContact:(NSString *)contactIdentifier protocolContext:(nullable id)protocolContext; -#pragma mark - debug +#pragma mark - Debug + +- (void)resetSessionStore:(YapDatabaseReadWriteTransaction *)transaction; -- (void)resetSessionStore; #if DEBUG -- (void)snapshotSessionStore; -- (void)restoreSessionStore; +- (void)snapshotSessionStore:(YapDatabaseReadWriteTransaction *)transaction; +- (void)restoreSessionStore:(YapDatabaseReadWriteTransaction *)transaction; #endif + - (void)printAllSessions; @end diff --git a/SignalServiceKit/src/Storage/AxolotlStore/TSStorageManager+SessionStore.m b/SignalServiceKit/src/Storage/AxolotlStore/TSStorageManager+SessionStore.m index 30fea09f2..d244bf8c1 100644 --- a/SignalServiceKit/src/Storage/AxolotlStore/TSStorageManager+SessionStore.m +++ b/SignalServiceKit/src/Storage/AxolotlStore/TSStorageManager+SessionStore.m @@ -5,6 +5,7 @@ #import "OWSFileSystem.h" #import "TSStorageManager+SessionStore.h" #import "YapDatabaseConnection+OWS.h" +#import "YapDatabaseTransaction+OWS.h" #import #import @@ -195,12 +196,13 @@ NSString *const kSessionStoreDBConnectionKey = @"kSessionStoreDBConnectionKey"; #pragma mark - debug -- (void)resetSessionStore +- (void)resetSessionStore:(YapDatabaseReadWriteTransaction *)transaction { + OWSAssert(transaction); + DDLogWarn(@"%@ resetting session store", self.logTag); - [self.sessionStoreDBConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - [transaction removeAllObjectsInCollection:TSStorageManagerSessionStoreCollection]; - }]; + + [transaction removeAllObjectsInCollection:TSStorageManagerSessionStoreCollection]; } - (void)printAllSessions @@ -253,16 +255,19 @@ NSString *const kSessionStoreDBConnectionKey = @"kSessionStoreDBConnectionKey"; return [dirPath stringByAppendingPathComponent:@".session-snapshot"]; } -- (void)snapshotSessionStore +- (void)snapshotSessionStore:(YapDatabaseReadWriteTransaction *)transaction { - [self.sessionStoreDBConnection snapshotCollection:TSStorageManagerSessionStoreCollection - snapshotFilePath:self.snapshotFilePath]; + OWSAssert(transaction); + + [transaction snapshotCollection:TSStorageManagerSessionStoreCollection snapshotFilePath:self.snapshotFilePath]; } -- (void)restoreSessionStore +- (void)restoreSessionStore:(YapDatabaseReadWriteTransaction *)transaction { - [self.sessionStoreDBConnection restoreSnapshotOfCollection:TSStorageManagerSessionStoreCollection - snapshotFilePath:self.snapshotFilePath]; + OWSAssert(transaction); + + [transaction restoreSnapshotOfCollection:TSStorageManagerSessionStoreCollection + snapshotFilePath:self.snapshotFilePath]; } #endif diff --git a/SignalServiceKit/src/Storage/YapDatabaseConnection+OWS.h b/SignalServiceKit/src/Storage/YapDatabaseConnection+OWS.h index 584be964c..4df5f5046 100644 --- a/SignalServiceKit/src/Storage/YapDatabaseConnection+OWS.h +++ b/SignalServiceKit/src/Storage/YapDatabaseConnection+OWS.h @@ -38,13 +38,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)purgeCollection:(NSString *)collection; -#pragma mark - Debug - -#if DEBUG -- (void)snapshotCollection:(NSString *)collection snapshotFilePath:(NSString *)snapshotFilePath; -- (void)restoreSnapshotOfCollection:(NSString *)collection snapshotFilePath:(NSString *)snapshotFilePath; -#endif - @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Storage/YapDatabaseConnection+OWS.m b/SignalServiceKit/src/Storage/YapDatabaseConnection+OWS.m index f1d672736..44d11aa68 100644 --- a/SignalServiceKit/src/Storage/YapDatabaseConnection+OWS.m +++ b/SignalServiceKit/src/Storage/YapDatabaseConnection+OWS.m @@ -168,47 +168,6 @@ NS_ASSUME_NONNULL_BEGIN [self setObject:@(value.timeIntervalSince1970) forKey:key inCollection:collection]; } -#pragma mark - Debug - -#if DEBUG -- (void)snapshotCollection:(NSString *)collection snapshotFilePath:(NSString *)snapshotFilePath -{ - OWSAssert(collection.length > 0); - OWSAssert(snapshotFilePath.length > 0); - - NSMutableDictionary *snapshot = [NSMutableDictionary new]; - [self readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { - [transaction - enumerateKeysAndObjectsInCollection:collection - usingBlock:^(NSString *_Nonnull key, id _Nonnull value, BOOL *_Nonnull stop) { - snapshot[key] = value; - }]; - }]; - NSData *_Nullable data = [NSKeyedArchiver archivedDataWithRootObject:snapshot]; - OWSAssert(data); - BOOL success = [data writeToFile:snapshotFilePath atomically:YES]; - OWSAssert(success); -} - -- (void)restoreSnapshotOfCollection:(NSString *)collection snapshotFilePath:(NSString *)snapshotFilePath -{ - OWSAssert(collection.length > 0); - OWSAssert(snapshotFilePath.length > 0); - - NSData *_Nullable data = [NSData dataWithContentsOfFile:snapshotFilePath]; - OWSAssert(data); - NSMutableDictionary *_Nullable snapshot = [NSKeyedUnarchiver unarchiveObjectWithData:data]; - OWSAssert(snapshot); - - [self readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [transaction removeAllObjectsInCollection:collection]; - [snapshot enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull key, id _Nonnull value, BOOL *_Nonnull stop) { - [transaction setObject:value forKey:key inCollection:collection]; - }]; - }]; -} -#endif - @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Storage/YapDatabaseReadTransaction+OWS.h b/SignalServiceKit/src/Storage/YapDatabaseTransaction+OWS.h similarity index 79% rename from SignalServiceKit/src/Storage/YapDatabaseReadTransaction+OWS.h rename to SignalServiceKit/src/Storage/YapDatabaseTransaction+OWS.h index 6ceaa4941..db9581683 100644 --- a/SignalServiceKit/src/Storage/YapDatabaseReadTransaction+OWS.h +++ b/SignalServiceKit/src/Storage/YapDatabaseTransaction+OWS.h @@ -25,4 +25,17 @@ NS_ASSUME_NONNULL_BEGIN @end +#pragma mark - + +@interface YapDatabaseReadWriteTransaction (OWS) + +#pragma mark - Debug + +#if DEBUG +- (void)snapshotCollection:(NSString *)collection snapshotFilePath:(NSString *)snapshotFilePath; +- (void)restoreSnapshotOfCollection:(NSString *)collection snapshotFilePath:(NSString *)snapshotFilePath; +#endif + +@end + NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Storage/YapDatabaseReadTransaction+OWS.m b/SignalServiceKit/src/Storage/YapDatabaseTransaction+OWS.m similarity index 68% rename from SignalServiceKit/src/Storage/YapDatabaseReadTransaction+OWS.m rename to SignalServiceKit/src/Storage/YapDatabaseTransaction+OWS.m index 712a17832..63fdeeaaa 100644 --- a/SignalServiceKit/src/Storage/YapDatabaseReadTransaction+OWS.m +++ b/SignalServiceKit/src/Storage/YapDatabaseTransaction+OWS.m @@ -2,7 +2,7 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // -#import "YapDatabaseReadTransaction+OWS.h" +#import "YapDatabaseTransaction+OWS.h" #import #import #import @@ -109,4 +109,46 @@ NS_ASSUME_NONNULL_BEGIN @end +#pragma mark - + +@implementation YapDatabaseReadWriteTransaction (OWS) + +#pragma mark - Debug + +#if DEBUG +- (void)snapshotCollection:(NSString *)collection snapshotFilePath:(NSString *)snapshotFilePath +{ + OWSAssert(collection.length > 0); + OWSAssert(snapshotFilePath.length > 0); + + NSMutableDictionary *snapshot = [NSMutableDictionary new]; + [self enumerateKeysAndObjectsInCollection:collection + usingBlock:^(NSString *_Nonnull key, id _Nonnull value, BOOL *_Nonnull stop) { + snapshot[key] = value; + }]; + NSData *_Nullable data = [NSKeyedArchiver archivedDataWithRootObject:snapshot]; + OWSAssert(data); + BOOL success = [data writeToFile:snapshotFilePath atomically:YES]; + OWSAssert(success); +} + +- (void)restoreSnapshotOfCollection:(NSString *)collection snapshotFilePath:(NSString *)snapshotFilePath +{ + OWSAssert(collection.length > 0); + OWSAssert(snapshotFilePath.length > 0); + + NSData *_Nullable data = [NSData dataWithContentsOfFile:snapshotFilePath]; + OWSAssert(data); + NSMutableDictionary *_Nullable snapshot = [NSKeyedUnarchiver unarchiveObjectWithData:data]; + OWSAssert(snapshot); + + [self removeAllObjectsInCollection:collection]; + [snapshot enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull key, id _Nonnull value, BOOL *_Nonnull stop) { + [self setObject:value forKey:key inCollection:collection]; + }]; +} +#endif + +@end + NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Util/OWSBackgroundTask.m b/SignalServiceKit/src/Util/OWSBackgroundTask.m index fbf45dca2..f571aec31 100644 --- a/SignalServiceKit/src/Util/OWSBackgroundTask.m +++ b/SignalServiceKit/src/Util/OWSBackgroundTask.m @@ -77,55 +77,63 @@ - (void)startBackgroundTask { // beginBackgroundTaskWithExpirationHandler must be called on the main thread. - DispatchMainThreadSafe(^{ - __weak typeof(self) weakSelf = self; - self.backgroundTaskId = [CurrentAppContext() beginBackgroundTaskWithExpirationHandler:^{ - dispatch_async(dispatch_get_main_queue(), ^{ - OWSBackgroundTask *strongSelf = weakSelf; - if (!strongSelf) { - return; - } - - // Make a local copy of completionBlock to ensure that it is called - // exactly once. - BackgroundTaskCompletionBlock _Nullable completionBlock = nil; - - @synchronized(strongSelf) - { - if (strongSelf.backgroundTaskId == UIBackgroundTaskInvalid) { - return; - } - DDLogInfo(@"%@ %@ background task expired.", strongSelf.logTag, strongSelf.label); - strongSelf.backgroundTaskId = UIBackgroundTaskInvalid; - - completionBlock = strongSelf.completionBlock; - strongSelf.completionBlock = nil; - } - - if (completionBlock) { - completionBlock(BackgroundTaskState_Expired); - } - }); - }]; - - // If a background task could not be begun, call the completion block. - if (self.backgroundTaskId == UIBackgroundTaskInvalid) { - - DDLogInfo(@"%@ %@ background task could not be started.", self.logTag, self.label); + __weak typeof(self) weakSelf = self; + self.backgroundTaskId = [CurrentAppContext() beginBackgroundTaskWithExpirationHandler:^{ + // Supposedly [UIApplication beginBackgroundTaskWithExpirationHandler]'s handler + // will always be called on the main thread, but in practice we've observed + // otherwise. We use DispatchSyncMainThreadSafe() (note the sync) to ensure that + // this work is done on the main thread. + // + // See: https://developer.apple.com/documentation/uikit/uiapplication/1623031-beginbackgroundtaskwithexpiratio) + // + // Note the usage of OWSCAssert() to avoid capturing a reference to self. + OWSCAssert([NSThread isMainThread]); + + DispatchSyncMainThreadSafe(^{ + OWSBackgroundTask *strongSelf = weakSelf; + if (!strongSelf) { + return; + } // Make a local copy of completionBlock to ensure that it is called // exactly once. - BackgroundTaskCompletionBlock _Nullable completionBlock; - @synchronized(self) + BackgroundTaskCompletionBlock _Nullable completionBlock = nil; + + @synchronized(strongSelf) { - completionBlock = self.completionBlock; - self.completionBlock = nil; + if (strongSelf.backgroundTaskId == UIBackgroundTaskInvalid) { + return; + } + DDLogInfo(@"%@ %@ background task expired.", strongSelf.logTag, strongSelf.label); + strongSelf.backgroundTaskId = UIBackgroundTaskInvalid; + + completionBlock = strongSelf.completionBlock; + strongSelf.completionBlock = nil; } + if (completionBlock) { - completionBlock(BackgroundTaskState_CouldNotStart); + completionBlock(BackgroundTaskState_Expired); } + }); + }]; + + // If a background task could not be begun, call the completion block. + if (self.backgroundTaskId == UIBackgroundTaskInvalid) { + + DDLogInfo(@"%@ %@ background task could not be started.", self.logTag, self.label); + + // Make a local copy of completionBlock to ensure that it is called + // exactly once. + BackgroundTaskCompletionBlock _Nullable completionBlock; + @synchronized(self) + { + completionBlock = self.completionBlock; + self.completionBlock = nil; } - }); + if (completionBlock) { + completionBlock(BackgroundTaskState_CouldNotStart); + } + } } - (void)endBackgroundTask diff --git a/SignalServiceKit/src/Util/Threading.h b/SignalServiceKit/src/Util/Threading.h index 2173dd587..4aac9cec7 100644 --- a/SignalServiceKit/src/Util/Threading.h +++ b/SignalServiceKit/src/Util/Threading.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // NS_ASSUME_NONNULL_BEGIN @@ -7,8 +7,13 @@ NS_ASSUME_NONNULL_BEGIN typedef void (^SimpleBlock)(void); // The block is executed immediately if called from the -// main thread; otherwise it is disptached async to the +// main thread; otherwise it is dispatched async to the // main thread. void DispatchMainThreadSafe(SimpleBlock block); +// The block is executed immediately if called from the +// main thread; otherwise it is dispatched sync to the +// main thread. +void DispatchSyncMainThreadSafe(SimpleBlock block); + NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Util/Threading.m b/SignalServiceKit/src/Util/Threading.m index c37bc7429..72505e339 100644 --- a/SignalServiceKit/src/Util/Threading.m +++ b/SignalServiceKit/src/Util/Threading.m @@ -1,5 +1,5 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // #import "Threading.h" @@ -19,4 +19,17 @@ void DispatchMainThreadSafe(SimpleBlock block) } } +void DispatchSyncMainThreadSafe(SimpleBlock block) +{ + OWSCAssert(block); + + if ([NSThread isMainThread]) { + block(); + } else { + dispatch_sync(dispatch_get_main_queue(), ^{ + block(); + }); + } +} + NS_ASSUME_NONNULL_END