diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m index c6125a59c..9be9298ea 100644 --- a/Signal/src/AppDelegate.m +++ b/Signal/src/AppDelegate.m @@ -161,6 +161,11 @@ static NSString *const kURLHostVerifyPrefix = @"verify"; } notificationsProtocolBlock:^{ return SignalApp.sharedApp.notificationsManager; + } + migrationCompletion:^{ + OWSAssertIsOnMainThread(); + + [self versionMigrationsDidComplete]; }]; [UIUtil applySignalAppearence]; @@ -176,14 +181,6 @@ static NSString *const kURLHostVerifyPrefix = @"verify"; mainWindow.rootViewController = [self loadingRootViewController]; [mainWindow makeKeyAndVisible]; - // performUpdateCheck must be invoked after Environment has been initialized because - // upgrade process may depend on Environment. - [VersionMigrations performUpdateCheckWithCompletion:^{ - OWSAssertIsOnMainThread(); - - [self versionMigrationsDidComplete]; - }]; - // Accept push notification when app is not open NSDictionary *remoteNotif = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]; if (remoteNotif) { diff --git a/SignalMessaging/environment/AppSetup.h b/SignalMessaging/environment/AppSetup.h index a24695c44..4d71c4694 100644 --- a/SignalMessaging/environment/AppSetup.h +++ b/SignalMessaging/environment/AppSetup.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 @@ -14,7 +14,8 @@ typedef id _Nonnull (^NotificationsManagerBlock)(void); @interface AppSetup : NSObject + (void)setupEnvironment:(CallMessageHandlerBlock)callMessageHandlerBlock - notificationsProtocolBlock:(NotificationsManagerBlock)notificationsManagerBlock; + notificationsProtocolBlock:(NotificationsManagerBlock)notificationsManagerBlock + migrationCompletion:(dispatch_block_t)migrationCompletion; @end diff --git a/SignalMessaging/environment/AppSetup.m b/SignalMessaging/environment/AppSetup.m index 48f663d83..6b01b5893 100644 --- a/SignalMessaging/environment/AppSetup.m +++ b/SignalMessaging/environment/AppSetup.m @@ -20,9 +20,14 @@ NS_ASSUME_NONNULL_BEGIN + (void)setupEnvironment:(CallMessageHandlerBlock)callMessageHandlerBlock notificationsProtocolBlock:(NotificationsManagerBlock)notificationsManagerBlock + migrationCompletion:(dispatch_block_t)migrationCompletion { OWSAssert(callMessageHandlerBlock); OWSAssert(notificationsManagerBlock); + OWSAssert(migrationCompletion); + + __block OWSBackgroundTask *_Nullable backgroundTask = + [OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__]; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ @@ -46,7 +51,16 @@ NS_ASSUME_NONNULL_BEGIN [NSKeyedUnarchiver setClass:[OWSUserProfile class] forClassName:[OWSUserProfile collection]]; [NSKeyedUnarchiver setClass:[OWSDatabaseMigration class] forClassName:[OWSDatabaseMigration collection]]; - [OWSStorage setupStorage]; + [OWSStorage setupStorageWithMigrationBlock:^() { + // Don't start database migrations until storage is ready. + [VersionMigrations performUpdateCheckWithCompletion:^() { + OWSAssertIsOnMainThread(); + + migrationCompletion(); + + backgroundTask = nil; + }]; + }]; [[Environment current].contactsManager startObserving]; }); } diff --git a/SignalMessaging/environment/VersionMigrations.m b/SignalMessaging/environment/VersionMigrations.m index 2e4c4d4be..84194d623 100644 --- a/SignalMessaging/environment/VersionMigrations.m +++ b/SignalMessaging/environment/VersionMigrations.m @@ -33,6 +33,8 @@ NS_ASSUME_NONNULL_BEGIN + (void)performUpdateCheckWithCompletion:(VersionMigrationCompletion)completion { + DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); + // performUpdateCheck must be invoked after Environment has been initialized because // upgrade process may depend on Environment. OWSAssert([Environment current]); diff --git a/SignalMessaging/environment/migrations/OWSDatabaseMigration.m b/SignalMessaging/environment/migrations/OWSDatabaseMigration.m index 7ff231076..90c1e0e1f 100644 --- a/SignalMessaging/environment/migrations/OWSDatabaseMigration.m +++ b/SignalMessaging/environment/migrations/OWSDatabaseMigration.m @@ -58,16 +58,6 @@ NS_ASSUME_NONNULL_BEGIN OWSAssert(completion); OWSDatabaseConnection *dbConnection = (OWSDatabaseConnection *)self.primaryStorage.newDatabaseConnection; - // These migrations won't be run until storage registrations are enqueued, - // but this transaction might begin before all registrations are marked as - // complete, so disable this checking. - // - // TODO: Once we move "app readiness" into AppSetup, we should explicitly - // not start these migrations until storage is ready. We can then remove - // this statement which disables checking. -#ifdef DEBUG - dbConnection.canWriteBeforeStorageReady = YES; -#endif [dbConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { [self runUpWithTransaction:transaction]; @@ -88,18 +78,12 @@ NS_ASSUME_NONNULL_BEGIN return self.dbReadWriteConnection; } -// Database migrations need to occur _before_ storage is ready (by definition), -// so we need to use a connection with canWriteBeforeStorageReady set in -// debug builds. + (YapDatabaseConnection *)dbReadWriteConnection { static dispatch_once_t onceToken; static YapDatabaseConnection *sharedDBConnection; dispatch_once(&onceToken, ^{ sharedDBConnection = [OWSPrimaryStorage sharedManager].newDatabaseConnection; - - OWSAssert([sharedDBConnection isKindOfClass:[OWSDatabaseConnection class]]); - ((OWSDatabaseConnection *)sharedDBConnection).canWriteBeforeStorageReady = YES; }); return sharedDBConnection; diff --git a/SignalServiceKit/src/Storage/OWSStorage.h b/SignalServiceKit/src/Storage/OWSStorage.h index 12198be48..b4226f876 100644 --- a/SignalServiceKit/src/Storage/OWSStorage.h +++ b/SignalServiceKit/src/Storage/OWSStorage.h @@ -22,10 +22,6 @@ extern NSString *const StorageIsReadyNotification; @property (atomic, weak) id delegate; -#ifdef DEBUG -@property (atomic) BOOL canWriteBeforeStorageReady; -#endif - - (instancetype)init NS_UNAVAILABLE; - (instancetype)initWithDatabase:(YapDatabase *)database delegate:(id)delegate NS_DESIGNATED_INITIALIZER; @@ -48,6 +44,8 @@ extern NSString *const StorageIsReadyNotification; #pragma mark - +typedef void (^OWSStorageMigrationBlock)(void); + @interface OWSStorage : NSObject - (instancetype)init NS_UNAVAILABLE; @@ -60,7 +58,7 @@ extern NSString *const StorageIsReadyNotification; // This object can be used to filter database notifications. @property (nonatomic, readonly, nullable) id dbNotificationObject; -+ (void)setupStorage; ++ (void)setupStorageWithMigrationBlock:(OWSStorageMigrationBlock)migrationBlock; + (void)resetAllStorage; diff --git a/SignalServiceKit/src/Storage/OWSStorage.m b/SignalServiceKit/src/Storage/OWSStorage.m index 75e97c45e..e7eead41b 100644 --- a/SignalServiceKit/src/Storage/OWSStorage.m +++ b/SignalServiceKit/src/Storage/OWSStorage.m @@ -74,7 +74,7 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void); { id delegate = self.delegate; OWSAssert(delegate); - OWSAssert(delegate.areAllRegistrationsComplete || self.canWriteBeforeStorageReady); + OWSAssert(delegate.areAllRegistrationsComplete); OWSBackgroundTask *_Nullable backgroundTask = nil; if (CurrentAppContext().isMainApp) { @@ -101,7 +101,7 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void); { id delegate = self.delegate; OWSAssert(delegate); - OWSAssert(delegate.areAllRegistrationsComplete || self.canWriteBeforeStorageReady); + OWSAssert(delegate.areAllRegistrationsComplete); __block OWSBackgroundTask *_Nullable backgroundTask = nil; if (CurrentAppContext().isMainApp) { @@ -176,13 +176,6 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void); - (YapDatabaseConnection *)registrationConnection { YapDatabaseConnection *connection = [super registrationConnection]; - -#ifdef DEBUG - // Flag the registration connection as such. - OWSAssert([connection isKindOfClass:[OWSDatabaseConnection class]]); - ((OWSDatabaseConnection *)connection).canWriteBeforeStorageReady = YES; -#endif - return connection; } @@ -332,29 +325,24 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void); OWS_ABSTRACT_METHOD(); } -+ (NSArray *)allStorages ++ (void)setupStorageWithMigrationBlock:(OWSStorageMigrationBlock)migrationBlock { - return @[ - OWSPrimaryStorage.sharedManager, - ]; -} + OWSAssert(migrationBlock); -+ (void)setupStorage -{ __block OWSBackgroundTask *_Nullable backgroundTask = [OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__]; - for (OWSStorage *storage in self.allStorages) { - [storage runSyncRegistrations]; - } + [OWSPrimaryStorage.sharedManager runSyncRegistrations]; - for (OWSStorage *storage in self.allStorages) { - [storage runAsyncRegistrationsWithCompletion:^{ - if ([self postRegistrationCompleteNotificationIfPossible]) { - backgroundTask = nil; - } - }]; - } + [OWSPrimaryStorage.sharedManager runAsyncRegistrationsWithCompletion:^{ + OWSAssert(self.isStorageReady); + + [self postRegistrationCompleteNotification]; + + migrationBlock(); + + backgroundTask = nil; + }]; } - (YapDatabaseConnection *)registrationConnection @@ -363,11 +351,11 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void); } // Returns YES IFF all registrations are complete. -+ (BOOL)postRegistrationCompleteNotificationIfPossible ++ (void)postRegistrationCompleteNotification { - if (!self.isStorageReady) { - return NO; - } + OWSAssert(self.isStorageReady); + + DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ @@ -375,18 +363,11 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void); object:nil userInfo:nil]; }); - - return YES; } + (BOOL)isStorageReady { - for (OWSStorage *storage in self.allStorages) { - if (!storage.areAllRegistrationsComplete) { - return NO; - } - } - return YES; + return OWSPrimaryStorage.sharedManager.areAllRegistrationsComplete; } - (BOOL)tryToLoadDatabase diff --git a/SignalShareExtension/ShareViewController.swift b/SignalShareExtension/ShareViewController.swift index c952e4a23..a9fb08472 100644 --- a/SignalShareExtension/ShareViewController.swift +++ b/SignalShareExtension/ShareViewController.swift @@ -90,18 +90,18 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed // We shouldn't set up our environment until after we've consulted isReadyForAppExtensions. AppSetup.setupEnvironment({ return NoopCallMessageHandler() - }) { + }, + notificationsProtocolBlock: { return NoopNotificationsManager() - } + }, + migrationCompletion: { [weak self] in + SwiftAssertIsOnMainThread(#function) - // performUpdateCheck must be invoked after Environment has been initialized because - // upgrade process may depend on Environment. - VersionMigrations.performUpdateCheck(completion: { [weak self] in - SwiftAssertIsOnMainThread(#function) - - guard let strongSelf = self else { return } + guard let strongSelf = self else { return } - strongSelf.versionMigrationsDidComplete() + // performUpdateCheck must be invoked after Environment has been initialized because + // upgrade process may depend on Environment. + strongSelf.versionMigrationsDidComplete() }) // We don't need to use "screen protection" in the SAE.