diff --git a/Podfile b/Podfile index c403ba87a..6e57ae933 100644 --- a/Podfile +++ b/Podfile @@ -3,7 +3,7 @@ source 'https://github.com/CocoaPods/Specs.git' target 'Signal' do pod 'SocketRocket', :git => 'https://github.com/facebook/SocketRocket.git' - pod 'SignalServiceKit', git: 'https://github.com/WhisperSystems/SignalServiceKit.git', branch: 'mkirk/async-db-setup' + pod 'SignalServiceKit', git: 'https://github.com/WhisperSystems/SignalServiceKit.git' #pod 'SignalServiceKit', path: '../SignalServiceKit' pod 'OpenSSL', '~> 1.0.208' pod 'PastelogKit', '~> 1.3' diff --git a/Podfile.lock b/Podfile.lock index 4e79de0b8..afbd3b502 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -119,19 +119,18 @@ DEPENDENCIES: - OpenSSL (~> 1.0.208) - PastelogKit (~> 1.3) - SCWaveformView (~> 1.0) - - SignalServiceKit (from `https://github.com/WhisperSystems/SignalServiceKit.git`, branch `mkirk/async-db-setup`) + - SignalServiceKit (from `https://github.com/WhisperSystems/SignalServiceKit.git`) - SocketRocket (from `https://github.com/facebook/SocketRocket.git`) EXTERNAL SOURCES: SignalServiceKit: - :branch: mkirk/async-db-setup :git: https://github.com/WhisperSystems/SignalServiceKit.git SocketRocket: :git: https://github.com/facebook/SocketRocket.git CHECKOUT OPTIONS: SignalServiceKit: - :commit: d06455fe2b3af5c072be3437a55d78eb6a5d540f + :commit: cf035a597d73d68bd15993dbac4ada576573d96e :git: https://github.com/WhisperSystems/SignalServiceKit.git SocketRocket: :commit: 8096fef47d582bff8ae3758c9ae7af1d55ea53d6 @@ -162,6 +161,6 @@ SPEC CHECKSUMS: UnionFind: c33be5adb12983981d6e827ea94fc7f9e370f52d YapDatabase: b1e43555a34a5298e23a045be96817a5ef0da58f -PODFILE CHECKSUM: e5ab6db291fd21f96ab3767fbf468988b9c916c7 +PODFILE CHECKSUM: 5dccee4c1c1ba5d4bf9575a81eeede82d1e89e8b COCOAPODS: 1.0.1 diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 63f188635..816ac2fb6 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -17,6 +17,9 @@ 453D28BB1D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m in Sources */ = {isa = PBXBuildFile; fileRef = 453D28B91D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m */; }; 45666F561D9B2827008FE134 /* OWSScrubbingLogFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 45666F551D9B2827008FE134 /* OWSScrubbingLogFormatter.m */; }; 45666F581D9B2880008FE134 /* OWSScrubbingLogFormatterTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 45666F571D9B2880008FE134 /* OWSScrubbingLogFormatterTest.m */; }; + 45666F761D9BFE00008FE134 /* OWS100RemoveTSRecipientsMigration.m in Sources */ = {isa = PBXBuildFile; fileRef = 45666F751D9BFE00008FE134 /* OWS100RemoveTSRecipientsMigration.m */; }; + 45666F7B1D9C0533008FE134 /* OWSDatabaseMigration.m in Sources */ = {isa = PBXBuildFile; fileRef = 45666F7A1D9C0533008FE134 /* OWSDatabaseMigration.m */; }; + 45666F7E1D9C0814008FE134 /* OWSDatabaseMigrationRunner.m in Sources */ = {isa = PBXBuildFile; fileRef = 45666F7D1D9C0814008FE134 /* OWSDatabaseMigrationRunner.m */; }; 45843D1F1D2236B30013E85A /* OWSContactsSearcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 45843D1E1D2236B30013E85A /* OWSContactsSearcher.m */; }; 45843D201D2236B30013E85A /* OWSContactsSearcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 45843D1E1D2236B30013E85A /* OWSContactsSearcher.m */; }; 45843D221D223BA10013E85A /* OWSContactsSearcherTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 45843D211D223BA10013E85A /* OWSContactsSearcherTest.m */; }; @@ -529,6 +532,12 @@ 45666F541D9B2827008FE134 /* OWSScrubbingLogFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSScrubbingLogFormatter.h; sourceTree = ""; }; 45666F551D9B2827008FE134 /* OWSScrubbingLogFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSScrubbingLogFormatter.m; sourceTree = ""; }; 45666F571D9B2880008FE134 /* OWSScrubbingLogFormatterTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSScrubbingLogFormatterTest.m; sourceTree = ""; }; + 45666F741D9BFE00008FE134 /* OWS100RemoveTSRecipientsMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWS100RemoveTSRecipientsMigration.h; path = Migrations/OWS100RemoveTSRecipientsMigration.h; sourceTree = ""; }; + 45666F751D9BFE00008FE134 /* OWS100RemoveTSRecipientsMigration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWS100RemoveTSRecipientsMigration.m; path = Migrations/OWS100RemoveTSRecipientsMigration.m; sourceTree = ""; }; + 45666F791D9C0533008FE134 /* OWSDatabaseMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSDatabaseMigration.h; path = Migrations/OWSDatabaseMigration.h; sourceTree = ""; }; + 45666F7A1D9C0533008FE134 /* OWSDatabaseMigration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSDatabaseMigration.m; path = Migrations/OWSDatabaseMigration.m; sourceTree = ""; }; + 45666F7C1D9C0814008FE134 /* OWSDatabaseMigrationRunner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSDatabaseMigrationRunner.h; path = Migrations/OWSDatabaseMigrationRunner.h; sourceTree = ""; }; + 45666F7D1D9C0814008FE134 /* OWSDatabaseMigrationRunner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSDatabaseMigrationRunner.m; path = Migrations/OWSDatabaseMigrationRunner.m; sourceTree = ""; }; 45843D1D1D2236B30013E85A /* OWSContactsSearcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContactsSearcher.h; sourceTree = ""; }; 45843D1E1D2236B30013E85A /* OWSContactsSearcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactsSearcher.m; sourceTree = ""; }; 45843D211D223BA10013E85A /* OWSContactsSearcherTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactsSearcherTest.m; sourceTree = ""; }; @@ -1140,6 +1149,19 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 45666F731D9BFDB9008FE134 /* Migrations */ = { + isa = PBXGroup; + children = ( + 45666F741D9BFE00008FE134 /* OWS100RemoveTSRecipientsMigration.h */, + 45666F751D9BFE00008FE134 /* OWS100RemoveTSRecipientsMigration.m */, + 45666F791D9C0533008FE134 /* OWSDatabaseMigration.h */, + 45666F7A1D9C0533008FE134 /* OWSDatabaseMigration.m */, + 45666F7C1D9C0814008FE134 /* OWSDatabaseMigrationRunner.h */, + 45666F7D1D9C0814008FE134 /* OWSDatabaseMigrationRunner.m */, + ); + name = Migrations; + sourceTree = ""; + }; 457F3AC01D14A0F700C51351 /* Models */ = { isa = PBXGroup; children = ( @@ -1285,6 +1307,7 @@ 76EB041118170B33006006FC /* environment */ = { isa = PBXGroup; children = ( + 45666F731D9BFDB9008FE134 /* Migrations */, B6258B311C29E2E60014138E /* NotificationsManager.h */, B6258B321C29E2E60014138E /* NotificationsManager.m */, 76EB041218170B33006006FC /* Environment.h */, @@ -2808,6 +2831,7 @@ 76EB05F418170B33006006FC /* CallConnectResult.m in Sources */, FCFD256F1A151BCB00F4C644 /* NewGroupViewController.m in Sources */, 76EB059E18170B33006006FC /* HttpSocket.m in Sources */, + 45666F761D9BFE00008FE134 /* OWS100RemoveTSRecipientsMigration.m in Sources */, E197B60E18BBEC1A00F073E5 /* CallAudioManager.m in Sources */, FCC81A981A44558300DFEC7D /* UIDevice+TSHardwareVersion.m in Sources */, 76EB054018170B33006006FC /* AppDelegate.m in Sources */, @@ -2828,6 +2852,7 @@ 76EB05F818170B33006006FC /* CallConnectUtil_Initiator.m in Sources */, B62F5E101C2980B4000D370C /* NSData+ows_StripToken.m in Sources */, B6B2269A1BE4C59200860F4D /* APNavigationController.m in Sources */, + 45666F7E1D9C0814008FE134 /* OWSDatabaseMigrationRunner.m in Sources */, B63761E319E1F487005735D1 /* AFHTTPSessionManager+SignalMethods.m in Sources */, 76EB05CC18170B33006006FC /* ShortAuthenticationStringGenerator.m in Sources */, E16E5BEF18AAC40200B7C403 /* EC25KeyAgreementProtocol.m in Sources */, @@ -2836,6 +2861,7 @@ 76EB058818170B33006006FC /* PropertyListPreferences.m in Sources */, 76EB05B218170B33006006FC /* DH3KKeyAgreementProtocol.m in Sources */, B63761EC19E1FBE8005735D1 /* HttpRequest.m in Sources */, + 45666F7B1D9C0533008FE134 /* OWSDatabaseMigration.m in Sources */, 76EB060818170B33006006FC /* ResponderSessionDescriptor.m in Sources */, B90418E6183E9DD40038554A /* DateUtil.m in Sources */, 76EB05C618170B33006006FC /* HelloAckPacket.m in Sources */, diff --git a/Signal/Signal-Info.plist b/Signal/Signal-Info.plist index 0de6523aa..e0137d3f3 100644 --- a/Signal/Signal-Info.plist +++ b/Signal/Signal-Info.plist @@ -38,7 +38,7 @@ CFBundleVersion - 2.5.3.0 + 2.5.3.3 ITSAppUsesNonExemptEncryption LOGS_EMAIL diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m index 05d0f23d6..be47ddfd5 100644 --- a/Signal/src/AppDelegate.m +++ b/Signal/src/AppDelegate.m @@ -99,7 +99,8 @@ static NSString *const kURLHostVerifyPrefix = @"verify"; [self prepareScreenProtection]; - if ([TSAccountManager isRegistered]) { + // Avoid blocking app launch by putting all possible DB access in async thread. + [TSAccountManager runIfRegistered:^{ if (application.applicationState == UIApplicationStateInactive) { [TSSocketManager becomeActiveFromForeground]; } else if (application.applicationState == UIApplicationStateBackground) { @@ -110,10 +111,9 @@ static NSString *const kURLHostVerifyPrefix = @"verify"; [[PushManager sharedManager] validateUserNotificationSettings]; [TSPreKeyManager refreshPreKeys]; - } + }]; [AppStoreRating setupRatingLibrary]; - return YES; } @@ -185,12 +185,12 @@ static NSString *const kURLHostVerifyPrefix = @"verify"; return; } - if ([TSAccountManager isRegistered]) { + [TSAccountManager runIfRegistered:^{ // We're double checking that the app is active, to be sure since we can't verify in production env due to code // signing. [TSSocketManager becomeActiveFromForeground]; [[Environment getCurrent].contactsManager verifyABPermission]; - } + }]; [self removeScreenProtection]; } diff --git a/Signal/src/environment/Migrations/OWS100RemoveTSRecipientsMigration.h b/Signal/src/environment/Migrations/OWS100RemoveTSRecipientsMigration.h new file mode 100644 index 000000000..e87edd63b --- /dev/null +++ b/Signal/src/environment/Migrations/OWS100RemoveTSRecipientsMigration.h @@ -0,0 +1,12 @@ +// Created by Michael Kirk on 9/28/16. +// Copyright © 2016 Open Whisper Systems. All rights reserved. + +#import "OWSDatabaseMigration.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface OWS100RemoveTSRecipientsMigration : OWSDatabaseMigration + +@end + +NS_ASSUME_NONNULL_END diff --git a/Signal/src/environment/Migrations/OWS100RemoveTSRecipientsMigration.m b/Signal/src/environment/Migrations/OWS100RemoveTSRecipientsMigration.m new file mode 100644 index 000000000..b92b33f2c --- /dev/null +++ b/Signal/src/environment/Migrations/OWS100RemoveTSRecipientsMigration.m @@ -0,0 +1,28 @@ +// Created by Michael Kirk on 9/28/16. +// Copyright © 2016 Open Whisper Systems. All rights reserved. + +#import "OWS100RemoveTSRecipientsMigration.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +// Increment a similar constant for every future DBMigration +static NSString *const OWS100RemoveTSRecipientsMigrationId = @"100"; + +@implementation OWS100RemoveTSRecipientsMigration + ++ (NSString *)migrationId +{ + return OWS100RemoveTSRecipientsMigrationId; +} + +- (void)runUpWithTransaction:(YapDatabaseReadWriteTransaction *)transaction +{ + NSUInteger legacyRecipientCount = [transaction numberOfKeysInCollection:@"TSRecipient"]; + DDLogWarn(@"Removing %lu objects from TSRecipient collection", (unsigned long)legacyRecipientCount); + [transaction removeAllObjectsInCollection:@"TSRecipient"]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Signal/src/environment/Migrations/OWSDatabaseMigration.h b/Signal/src/environment/Migrations/OWSDatabaseMigration.h new file mode 100644 index 000000000..58bc174ff --- /dev/null +++ b/Signal/src/environment/Migrations/OWSDatabaseMigration.h @@ -0,0 +1,32 @@ +// Created by Michael Kirk on 9/28/16. +// Copyright © 2016 Open Whisper Systems. All rights reserved. + +#include + +NS_ASSUME_NONNULL_BEGIN + +@class TSStorageManager; + +@interface OWSDatabaseMigration : TSYapDatabaseObject + +- (instancetype)initWithStorageManager:(TSStorageManager *)storageManager; + +@property (nonatomic, readonly) TSStorageManager *storageManager; + +/** + * Run an asynchronous migration. Prefer this to the blocking variant whenever possible as the migration runner will + * block launching, and potentially crash apps e.g. if a view is being populated. + */ +- (void)runUp; + +/** + * Run a synchronous migration. + * TODO: there's currently no tooling in the migration runner to run BlockingMigrations, as we don't have any yet. + * Try to avoid this whenever possible as the migration runner will block launching, and potentially crash apps + * e.g. if a view is being populated. + */ +- (void)runUpWithBlockingMigration; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Signal/src/environment/Migrations/OWSDatabaseMigration.m b/Signal/src/environment/Migrations/OWSDatabaseMigration.m new file mode 100644 index 000000000..244528c6b --- /dev/null +++ b/Signal/src/environment/Migrations/OWSDatabaseMigration.m @@ -0,0 +1,81 @@ +// Created by Michael Kirk on 9/28/16. +// Copyright © 2016 Open Whisper Systems. All rights reserved. + +#import "OWSDatabaseMigration.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +@implementation OWSDatabaseMigration + +- (instancetype)initWithStorageManager:(TSStorageManager *)storageManager +{ + self = [super initWithUniqueId:[self.class migrationId]]; + if (!self) { + return self; + } + + _storageManager = storageManager; + + return self; +} + ++ (MTLPropertyStorage)storageBehaviorForPropertyWithKey:(NSString *)propertyKey +{ + if ([propertyKey isEqualToString:@"storageManager"]) { + return MTLPropertyStorageNone; + } else { + return [super storageBehaviorForPropertyWithKey:propertyKey]; + } +} + ++ (NSString *)migrationId +{ + @throw [NSException + exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"Must override %@ in subclass", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + ++ (NSString *)collection +{ + // We want all subclasses in the same collection + return @"OWSDatabaseMigration"; +} + +- (void)runUpWithTransaction:(YapDatabaseReadWriteTransaction *)transaction +{ + @throw [NSException + exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"Must override %@ in subclass", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + +- (void)runUp +{ + [self.storageManager.newDatabaseConnection + asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { + [self runUpWithTransaction:transaction]; + } + completionBlock:^{ + DDLogInfo(@"Completed migration %@", self.uniqueId); + [self save]; + }]; +} + +/** + * Try to avoid using this. + */ +- (void)runUpWithBlockingMigration +{ + [self.storageManager.newDatabaseConnection + readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { + [self runUpWithTransaction:transaction]; + }]; + DDLogInfo(@"Completed migration %@", self.uniqueId); + [self save]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Signal/src/environment/Migrations/OWSDatabaseMigrationRunner.h b/Signal/src/environment/Migrations/OWSDatabaseMigrationRunner.h new file mode 100644 index 000000000..1997a2a73 --- /dev/null +++ b/Signal/src/environment/Migrations/OWSDatabaseMigrationRunner.h @@ -0,0 +1,26 @@ +// Created by Michael Kirk on 9/28/16. +// Copyright © 2016 Open Whisper Systems. All rights reserved. + +NS_ASSUME_NONNULL_BEGIN + +@class TSStorageManager; + +@interface OWSDatabaseMigrationRunner : NSObject + +- (instancetype)initWithStorageManager:(TSStorageManager *)storageManager; + +@property (nonatomic, readonly) TSStorageManager *storageManager; + +/** + * Run any outstanding version migrations. + */ +- (void)runAllOutstanding; + +/** + * On new installations, no need to migrate anything. + */ +- (void)assumeAllExistingMigrationsRun; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Signal/src/environment/Migrations/OWSDatabaseMigrationRunner.m b/Signal/src/environment/Migrations/OWSDatabaseMigrationRunner.m new file mode 100644 index 000000000..9b055339d --- /dev/null +++ b/Signal/src/environment/Migrations/OWSDatabaseMigrationRunner.m @@ -0,0 +1,62 @@ +// Created by Michael Kirk on 9/28/16. +// Copyright © 2016 Open Whisper Systems. All rights reserved. + +#import "OWSDatabaseMigrationRunner.h" +#import "OWS100RemoveTSRecipientsMigration.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation OWSDatabaseMigrationRunner + +- (instancetype)initWithStorageManager:(TSStorageManager *)storageManager +{ + self = [super init]; + if (!self) { + return self; + } + + _storageManager = storageManager; + + return self; +} + +- (NSArray *)allMigrations +{ + return @[ [[OWS100RemoveTSRecipientsMigration alloc] initWithStorageManager:self.storageManager] ]; +} + +- (void)assumeAllExistingMigrationsRun +{ + for (OWSDatabaseMigration *migration in self.allMigrations) { + DDLogInfo(@"%@ Skipping migration on new install: %@", self.tag, migration); + [migration save]; + } +} + +- (void)runAllOutstanding +{ + for (OWSDatabaseMigration *migration in self.allMigrations) { + if ([OWSDatabaseMigration fetchObjectWithUniqueID:migration.uniqueId]) { + DDLogDebug(@"%@ Skipping previously run migration: %@", self.tag, migration); + } else { + DDLogWarn(@"%@ Running migration: %@", self.tag, migration); + [migration runUp]; + } + } +} + +#pragma mark - Logging + ++ (NSString *)tag +{ + return [NSString stringWithFormat:@"[%@]", self.class]; +} + +- (NSString *)tag +{ + return self.class.tag; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Signal/src/environment/VersionMigrations.m b/Signal/src/environment/VersionMigrations.m index 7c5c3ba11..32b179f77 100644 --- a/Signal/src/environment/VersionMigrations.m +++ b/Signal/src/environment/VersionMigrations.m @@ -10,6 +10,7 @@ #import "Environment.h" #import "LockInteractionController.h" +#import "OWSDatabaseMigrationRunner.h" #import "PreferencesUtil.h" #import "PushManager.h" #import "RecentCallManager.h" @@ -25,6 +26,7 @@ + (void)storeString:(NSString *)string forKey:(NSString *)key; + (void)storeData:(NSData *)data forKey:(NSString *)key; + @end @implementation VersionMigrations @@ -36,6 +38,9 @@ NSString *previousVersion = Environment.preferences.lastRanVersion; if (!previousVersion) { DDLogInfo(@"No previous version found. Probably first launch since install - nothing to migrate."); + OWSDatabaseMigrationRunner *runner = + [[OWSDatabaseMigrationRunner alloc] initWithStorageManager:[TSStorageManager sharedManager]]; + [runner assumeAllExistingMigrationsRun]; [Environment.preferences setAndGetCurrentVersion]; return; } @@ -75,14 +80,7 @@ }); } - if ([self isVersion:previousVersion atLeast:@"2.0.0" andLessThan:@"2.5.2"] && [TSAccountManager isRegistered]) { - [[TSStorageManager sharedManager].dbConnection - readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - NSUInteger legacyRecipientCount = [transaction numberOfKeysInCollection:@"TSRecipient"]; - DDLogWarn(@"Removing %lu objects from TSRecipient collection", (unsigned long)legacyRecipientCount); - [transaction removeAllObjectsInCollection:@"TSRecipient"]; - }]; - } + [[[OWSDatabaseMigrationRunner alloc] initWithStorageManager:[TSStorageManager sharedManager]] runAllOutstanding]; [Environment.preferences setAndGetCurrentVersion]; }