diff --git a/Monal/Classes/HelperTools.m b/Monal/Classes/HelperTools.m index 783deaaea..e47e193ba 100644 --- a/Monal/Classes/HelperTools.m +++ b/Monal/Classes/HelperTools.m @@ -75,14 +75,23 @@ @interface MLDelayableTimer() -(void) invalidate; @end +//make method visible +@interface DDLog() +-(void) queueLogMessage:(DDLogMessage*) logMessage asynchronously:(BOOL) asyncFlag; +@end + +@interface DDLog (AllowQueueFreeze) +-(void) swizzled_queueLogMessage:(DDLogMessage*) logMessage asynchronously:(BOOL) asyncFlag; +@end + static char* _crashBundleName = "UnifiedReport"; static NSString* _processID; static DDFileLogger* _fileLogger = nil; static char _origLogfilePath[1024] = ""; static char _logfilePath[1024] = ""; static NSObject* _isAppExtensionLock = nil; -static NSObject* _suspensionHandlingLock = nil; -static BOOL _suspensionHandlingIsSuspended = NO; +static NSObject* _suspensionHandling_lock = nil; +static BOOL _suspensionHandling_isSuspended = NO; static NSMutableDictionary* _versionInfoCache; static MLStreamRedirect* _stdoutRedirector = nil; static MLStreamRedirect* _stderrRedirector = nil; @@ -293,12 +302,36 @@ -(id) initWithObj:(id) obj } @end +@implementation DDLog (AllowQueueFreeze) + +-(void) swizzled_queueLogMessage:(DDLogMessage*) logMessage asynchronously:(BOOL) asyncFlag +{ + //don't do sync logging for any message (usually ERROR), while the global logging queue is suspended + @synchronized(_suspensionHandling_lock) { + return [self swizzled_queueLogMessage:logMessage asynchronously:_suspensionHandling_isSuspended ? YES : asyncFlag]; + } +} + +//see https://stackoverflow.com/a/13326633 and https://fek.io/blog/method-swizzling-in-obj-c-and-swift/ ++(void) load +{ + if(self == DDLog.self) + { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + swizzle([self class], @selector(queueLogMessage:asynchronously:), @selector(swizzled_queueLogMessage:asynchronously:)); + }); + } +} + +@end + @implementation HelperTools +(void) initialize { - _suspensionHandlingLock = [NSObject new]; - _suspensionHandlingIsSuspended = NO; + _suspensionHandling_lock = [NSObject new]; + _suspensionHandling_isSuspended = NO; _isAppExtensionLock = [NSObject new]; _versionInfoCache = [NSMutableDictionary new]; @@ -1880,27 +1913,31 @@ +(void) flushLogsWithTimeout:(double) timeout +(void) signalSuspension { - @synchronized(_suspensionHandlingLock) { - if(!_suspensionHandlingIsSuspended) + @synchronized(_suspensionHandling_lock) { + if(!_suspensionHandling_isSuspended) { DDLogVerbose(@"Suspending logger queue..."); [HelperTools flushLogsWithTimeout:0.100]; dispatch_suspend([DDLog loggingQueue]); - _suspensionHandlingIsSuspended = YES; + _suspensionHandling_isSuspended = YES; + + DDLogVerbose(@"Posting kMonalFrozen notification now..."); + [[NSNotificationCenter defaultCenter] postNotificationName:kMonalFrozen object:nil]; } } - DDLogVerbose(@"Posting kMonalIsFreezed notification now..."); - [[NSNotificationCenter defaultCenter] postNotificationName:kMonalIsFreezed object:nil]; } +(void) signalResumption { - @synchronized(_suspensionHandlingLock) { - if(_suspensionHandlingIsSuspended) + @synchronized(_suspensionHandling_lock) { + if(_suspensionHandling_isSuspended) { DDLogVerbose(@"Resuming logger queue..."); dispatch_resume([DDLog loggingQueue]); - _suspensionHandlingIsSuspended = NO; + _suspensionHandling_isSuspended = NO; + + DDLogVerbose(@"Posting kMonalUnfrozen notification now..."); + [[NSNotificationCenter defaultCenter] postNotificationName:kMonalUnfrozen object:nil]; } } } diff --git a/Monal/Classes/MLOMEMO.m b/Monal/Classes/MLOMEMO.m index cf127794b..ceea2705f 100644 --- a/Monal/Classes/MLOMEMO.m +++ b/Monal/Classes/MLOMEMO.m @@ -26,7 +26,7 @@ NS_ASSUME_NONNULL_BEGIN -static const size_t MIN_OMEMO_KEYS = 25; +static const size_t MIN_OMEMO_KEYS = 90; static const size_t MAX_OMEMO_KEYS = 100; static const int KEY_SIZE = 16; @@ -750,8 +750,9 @@ -(void) processOMEMOKeys:(MLXMLNode*) item forJid:(NSString*) jid andRid:(NSNumb { // select random preKey and try to import it const uint32_t preKeyIdxToTest = arc4random_uniform((uint32_t)preKeyIds.count); - // load preKey NSNumber* preKeyId = preKeyIds[preKeyIdxToTest]; + [preKeyIds removeObjectAtIndex:preKeyIdxToTest]; + processedKeys++; if(preKeyId == nil) continue;; NSData* key = [bundle findFirst:@"prekeys/preKeyPublic#|base64", preKeyId]; @@ -790,7 +791,7 @@ -(void) processOMEMOKeys:(MLXMLNode*) item forJid:(NSString*) jid andRid:(NSNumb [self notifyKnownDevicesUpdated:jid]; return; - } while(++processedKeys < preKeyIds.count); + } while(preKeyIds.count > 0); DDLogError(@"Could not import a single prekey from bundle for rid %@ (tried %lu keys)", rid, processedKeys); //TODO: should we blacklist this device id? @synchronized(self.state.queuedSessionRepairs) { diff --git a/Monal/Classes/MonalAppDelegate.m b/Monal/Classes/MonalAppDelegate.m index 4c8c1c0f7..28d7896e3 100644 --- a/Monal/Classes/MonalAppDelegate.m +++ b/Monal/Classes/MonalAppDelegate.m @@ -1595,9 +1595,6 @@ -(void) handleBackgroundProcessingTask:(BGTask*) task }]; }; - //resume logging and other core tasks - [HelperTools signalResumption]; - //only proceed with our BGTASK if the NotificationServiceExtension is not running [MLProcessLock lock]; [[IPC sharedInstance] sendMessage:@"Monal.disconnectAll" withData:nil to:@"NotificationServiceExtension"]; @@ -1702,9 +1699,6 @@ -(void) handleBackgroundRefreshingTask:(BGTask*) task }]; }; - //resume logging and other core tasks - [HelperTools signalResumption]; - //only proceed with our BGTASK if the NotificationServiceExtension is not running [MLProcessLock lock]; [[IPC sharedInstance] sendMessage:@"Monal.disconnectAll" withData:nil to:@"NotificationServiceExtension"]; @@ -1748,6 +1742,9 @@ -(void) handleBackgroundRefreshingTask:(BGTask*) task -(void) configureBackgroundTasks { [[BGTaskScheduler sharedScheduler] registerForTaskWithIdentifier:kBackgroundProcessingTask usingQueue:dispatch_get_main_queue() launchHandler:^(BGTask *task) { + //resume logging and other core tasks + [HelperTools signalResumption]; + DDLogDebug(@"RUNNING BGPROCESSING LAUNCH HANDLER"); DDLogInfo(@"BG time available: %f", [UIApplication sharedApplication].backgroundTimeRemaining); if(![HelperTools isInBackground]) @@ -1768,6 +1765,9 @@ -(void) configureBackgroundTasks }]; [[BGTaskScheduler sharedScheduler] registerForTaskWithIdentifier:kBackgroundRefreshingTask usingQueue:dispatch_get_main_queue() launchHandler:^(BGTask *task) { + //resume logging and other core tasks + [HelperTools signalResumption]; + DDLogDebug(@"RUNNING BGREFRESHING LAUNCH HANDLER"); DDLogInfo(@"BG time available: %f", [UIApplication sharedApplication].backgroundTimeRemaining); if(![HelperTools isInBackground]) diff --git a/Monal/NotificationService/NotificationService.m b/Monal/NotificationService/NotificationService.m index c25f3052c..6cfa12dd5 100644 --- a/Monal/NotificationService/NotificationService.m +++ b/Monal/NotificationService/NotificationService.m @@ -516,7 +516,7 @@ -(void) didReceiveNotificationRequest:(UNNotificationRequest*) request withConte } } - #ifdef DEBUG +#ifdef DEBUG if(warnUnclean) { UNMutableNotificationContent* errorContent = [UNMutableNotificationContent new]; @@ -530,7 +530,7 @@ -(void) didReceiveNotificationRequest:(UNNotificationRequest*) request withConte else warnUnclean = NO; //try again on error } - #endif +#endif //proxy to push singleton DDLogDebug(@"proxying to incomingPush"); @@ -547,7 +547,7 @@ -(void) serviceExtensionTimeWillExpire DDLogError(@"notification handler expired, that should never happen!"); /* - #ifdef DEBUG +#ifdef DEBUG UNMutableNotificationContent* errorContent = [UNMutableNotificationContent new]; errorContent.title = @"Unexpected appex expiration"; errorContent.body = @"This should never happen, please contact the developers and provide a logfile!"; @@ -556,7 +556,7 @@ -(void) serviceExtensionTimeWillExpire NSError* error = [HelperTools postUserNotificationRequest:errorRequest]; if(error) DDLogError(@"Error posting local appex expiration error notification: %@", error); - #endif +#endif //It seems the iOS induced deadlock unlocks itself after this expiration handler got called and even new pushes //can come in while this handler is still running