diff --git a/Signal/Signal-Info.plist b/Signal/Signal-Info.plist index 24db74da2..82882c8cb 100644 --- a/Signal/Signal-Info.plist +++ b/Signal/Signal-Info.plist @@ -38,7 +38,7 @@ CFBundleVersion - 2.29.0.6 + 2.29.0.9 ITSAppUsesNonExemptEncryption LOGS_EMAIL diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 1431fe65d..18e387b51 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -441,6 +441,8 @@ typedef enum : NSUInteger { { OWSAssert(thread); + DDLogInfo(@"%@ configureForThread.", self.logTag); + _thread = thread; self.actionOnOpen = action; self.focusMessageIdOnOpen = focusMessageId; @@ -455,29 +457,11 @@ typedef enum : NSUInteger { [self ensureDynamicInteractions]; [[OWSPrimaryStorage sharedManager] updateUIDatabaseConnectionToLatest]; - if (thread.uniqueId.length > 0) { - self.messageMappings = [[YapDatabaseViewMappings alloc] initWithGroups:@[ thread.uniqueId ] - view:TSMessageDatabaseViewExtensionName]; - } else { - OWSFail(@"uniqueId unexpectedly empty for thread: %@", thread); - self.messageMappings = - [[YapDatabaseViewMappings alloc] initWithGroups:@[] view:TSMessageDatabaseViewExtensionName]; - return; + [self createNewMessageMappings]; + if (![self reloadViewItems]) { + OWSFail(@"%@ failed to reload view items in configureForThread.", self.logTag); } - // Cells' appearance can depend on adjacent cells in both directions. - [self.messageMappings setCellDrawingDependencyOffsets:[NSSet setWithArray:@[ - @(-1), - @(+1), - ]] - forGroup:self.thread.uniqueId]; - - // We need to impose the range restrictions on the mappings immediately to avoid - // doing a great deal of unnecessary work and causing a perf hotspot. - [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - [self.messageMappings updateWithTransaction:transaction]; - }]; - [self updateMessageMappingRangeOptions]; [self updateShouldObserveDBModifications]; self.reloadTimer = [NSTimer weakScheduledTimerWithTimeInterval:1.f @@ -814,7 +798,9 @@ typedef enum : NSUInteger { // Avoid layout corrupt issues and out-of-date message subtitles. self.lastReloadDate = [NSDate new]; self.collapseCutoffDate = [NSDate new]; - [self reloadViewItems]; + if (![self reloadViewItems]) { + OWSFail(@"%@ failed to reload view items in resetContentAndLayout.", self.logTag); + } [self.collectionView.collectionViewLayout invalidateLayout]; [self.collectionView reloadData]; } @@ -1771,7 +1757,6 @@ typedef enum : NSUInteger { [self.messageMappings setRangeOptions:rangeOptions forGroup:self.thread.uniqueId]; [self updateShowLoadMoreHeader]; self.collapseCutoffDate = [NSDate new]; - [self reloadViewItems]; } #pragma mark Bubble User Actions @@ -3378,14 +3363,21 @@ typedef enum : NSUInteger { // These errors seems to be very rare; they can only be reproduced // using the more extreme actions in the debug UI. OWSFail(@"%@ hasMalformedRowChange", self.logTag); - [self resetContentAndLayout]; + [self resetMappings]; [self updateLastVisibleTimestamp]; [self scrollToBottomAnimated:NO]; return; } NSUInteger oldViewItemCount = self.viewItems.count; - [self reloadViewItems]; + if (![self reloadViewItems]) { + // These errors are rare. + OWSFail(@"%@ could not reload view items; hard resetting message mappings.", self.logTag); + [self resetMappings]; + [self updateLastVisibleTimestamp]; + [self scrollToBottomAnimated:NO]; + return; + } BOOL wasAtBottom = [self isScrolledToBottom]; // We want sending messages to feel snappy. So, if the only @@ -4800,6 +4792,32 @@ typedef enum : NSUInteger { self.previousLastTimestamp = nil; } +- (void)createNewMessageMappings +{ + if (self.thread.uniqueId.length > 0) { + self.messageMappings = [[YapDatabaseViewMappings alloc] initWithGroups:@[ self.thread.uniqueId ] + view:TSMessageDatabaseViewExtensionName]; + } else { + OWSFail(@"uniqueId unexpectedly empty for thread: %@", self.thread); + self.messageMappings = + [[YapDatabaseViewMappings alloc] initWithGroups:@[] view:TSMessageDatabaseViewExtensionName]; + } + + // Cells' appearance can depend on adjacent cells in both directions. + [self.messageMappings setCellDrawingDependencyOffsets:[NSSet setWithArray:@[ + @(-1), + @(+1), + ]] + forGroup:self.thread.uniqueId]; + + // We need to impose the range restrictions on the mappings immediately to avoid + // doing a great deal of unnecessary work and causing a perf hotspot. + [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { + [self.messageMappings updateWithTransaction:transaction]; + }]; + [self updateMessageMappingRangeOptions]; +} + - (void)resetMappings { // If we're entering "active" mode (e.g. view is visible and app is in foreground), @@ -4814,7 +4832,6 @@ typedef enum : NSUInteger { [self updateMessageMappingRangeOptions]; } self.collapseCutoffDate = [NSDate new]; - [self reloadViewItems]; [self resetContentAndLayout]; [self ensureDynamicInteractions]; @@ -4849,7 +4866,9 @@ typedef enum : NSUInteger { // This is a key method. It builds or rebuilds the list of // cell view models. -- (void)reloadViewItems +// +// Returns NO on error. +- (BOOL)reloadViewItems { NSMutableArray *viewItems = [NSMutableArray new]; NSMutableDictionary *viewItemCache = [NSMutableDictionary new]; @@ -4857,6 +4876,7 @@ typedef enum : NSUInteger { NSUInteger count = [self.messageMappings numberOfItemsInSection:0]; BOOL isGroupThread = self.isGroupConversation; + __block BOOL hasError = NO; [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { YapDatabaseViewTransaction *viewTransaction = [transaction ext:TSMessageDatabaseViewExtensionName]; OWSAssert(viewTransaction); @@ -4869,6 +4889,7 @@ typedef enum : NSUInteger { (unsigned long)row, (unsigned long)count); // TODO: Add analytics. + hasError = YES; continue; } if (!interaction.uniqueId) { @@ -4878,6 +4899,7 @@ typedef enum : NSUInteger { (unsigned long)count, interaction); // TODO: Add analytics. + hasError = YES; continue; } @@ -4894,6 +4916,14 @@ typedef enum : NSUInteger { } }]; + // Flag to ensure that we only increment once per launch. + static BOOL hasIncrementedDatabaseView = NO; + if (hasError && !hasIncrementedDatabaseView) { + DDLogWarn(@"%@ incrementing version of: %@", self.logTag, TSMessageDatabaseViewExtensionName); + [OWSPrimaryStorage incrementVersionOfDatabaseExtension:TSMessageDatabaseViewExtensionName]; + hasIncrementedDatabaseView = YES; + } + // Update the "break" properties (shouldShowDate and unreadIndicator) of the view items. BOOL shouldShowDateOnNextViewItem = YES; uint64_t previousViewItemTimestamp = 0; @@ -5122,6 +5152,8 @@ typedef enum : NSUInteger { self.viewItems = viewItems; self.viewItemCache = viewItemCache; + + return !hasError; } // Whenever an interaction is modified, we need to reload it from the DB diff --git a/SignalServiceKit/src/Storage/OWSPrimaryStorage.m b/SignalServiceKit/src/Storage/OWSPrimaryStorage.m index 2a9d27050..3e8c049b4 100644 --- a/SignalServiceKit/src/Storage/OWSPrimaryStorage.m +++ b/SignalServiceKit/src/Storage/OWSPrimaryStorage.m @@ -132,6 +132,7 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage) - (void)updateUIDatabaseConnectionToLatest { + OWSAssertIsOnMainThread(); // Notify observers we're about to update the database connection [[NSNotificationCenter defaultCenter] postNotificationName:OWSUIDatabaseConnectionWillUpdateNotification object:self.dbNotificationObject]; diff --git a/SignalServiceKit/src/Storage/OWSStorage.m b/SignalServiceKit/src/Storage/OWSStorage.m index d4d898dd0..0795e52b1 100644 --- a/SignalServiceKit/src/Storage/OWSStorage.m +++ b/SignalServiceKit/src/Storage/OWSStorage.m @@ -513,7 +513,7 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ + (void)incrementVersionOfDatabaseExtension:(NSString *)extensionName { - DDLogError(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); + DDLogError(@"%@ %s %@", self.logTag, __PRETTY_FUNCTION__, extensionName); NSUserDefaults *appUserDefaults = [NSUserDefaults appUserDefaults]; OWSAssert(appUserDefaults); diff --git a/SignalShareExtension/Info.plist b/SignalShareExtension/Info.plist index 7a769362c..3cf77a9e6 100644 --- a/SignalShareExtension/Info.plist +++ b/SignalShareExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 2.29.0 CFBundleVersion - 2.29.0.6 + 2.29.0.9 ITSAppUsesNonExemptEncryption NSAppTransportSecurity