From f256617636d354a52ddc547895b370c4d4d674cd Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Wed, 28 Sep 2016 12:07:22 -0400 Subject: [PATCH 1/2] If we can't find a class definition, don't explode, just log. If we have a serialized object in our data store that wasn't properly removed, we can be faced with an exception when enumerating objects in the database, e.g. when we add a new Yap Index. // FREEBIE --- src/Storage/TSStorageManager.m | 38 +++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/src/Storage/TSStorageManager.m b/src/Storage/TSStorageManager.m index f9b39857a..f05611261 100644 --- a/src/Storage/TSStorageManager.m +++ b/src/Storage/TSStorageManager.m @@ -32,19 +32,39 @@ static NSString *keychainDBPassAccount = @"TSDatabasePass"; @end -@implementation TSRecipient +@interface OWSUnknownObject : NSObject + +@end + +/** + * A default object to returned when we can't deserialize an object from YapDB. This can prevent crashes when + * old objects linger after their definition file is removed. The danger is that, the objects can lay in wait + * until the next time a DB extension is added and we necessarily enumerate the entire DB. + */ +@implementation OWSUnknownObject - (instancetype)initWithCoder:(NSCoder *)aDecoder { - DDLogWarn(@"Ignoring decoding signal recipient with coder."); - - self = [super init]; return nil; } - (void)encodeWithCoder:(NSCoder *)aCoder { - DDLogWarn(@"Ignoring encoding signal recipient with coder."); + +} + +@end + +@interface OWSUnarchiverDelegate : NSObject + +@end + +@implementation OWSUnarchiverDelegate + +- (nullable Class)unarchiver:(NSKeyedUnarchiver *)unarchiver cannotDecodeObjectOfClassName:(NSString *)name originalClasses:(NSArray *)classNames +{ + DDLogError(@"[OWSUnarchiverDelegate] Ignoring unknown class name: %@. Was the class definition deleted?", name); + return [OWSUnknownObject class]; } @end @@ -86,13 +106,17 @@ static NSString *keychainDBPassAccount = @"TSDatabasePass"; **/ + (YapDatabaseDeserializer)logOnFailureDeserializer { + OWSUnarchiverDelegate *unarchiverDelegate = [OWSUnarchiverDelegate new]; + return ^id(NSString __unused *collection, NSString __unused *key, NSData *data) { if (!data || data.length <= 0) { return nil; } @try { - return [NSKeyedUnarchiver unarchiveObjectWithData:data]; + NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; + unarchiver.delegate = unarchiverDelegate; + return [unarchiver decodeObjectForKey:@"root"]; } @catch (NSException *exception) { // Sync log in case we bail. DDLogError(@"%@ Unarchiving key:%@ from collection:%@ and data %@ failed with error: %@", @@ -103,8 +127,6 @@ static NSString *keychainDBPassAccount = @"TSDatabasePass"; exception.reason); DDLogError(@"%@ Raising exception.", self.tag); @throw exception; - // DDLogWarn(@"%@ Ignoring exception.", self.tag); - // return nil; } }; } From ff9729f421176ed888a9365ce54b18ebfe0b1694 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Wed, 28 Sep 2016 12:09:37 -0400 Subject: [PATCH 2/2] Avoid blocking app launch // FREEBIE --- src/Account/TSAccountManager.h | 2 +- src/Account/TSAccountManager.m | 5 ++++ src/Storage/TSStorageManager+keyingMaterial.h | 2 +- src/Storage/TSStorageManager+keyingMaterial.m | 23 +++++++++++++++++++ 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/Account/TSAccountManager.h b/src/Account/TSAccountManager.h index ff7e6fade..4d5c192eb 100644 --- a/src/Account/TSAccountManager.h +++ b/src/Account/TSAccountManager.h @@ -21,8 +21,8 @@ typedef void (^failedBlock)(NSError *error); * * @return registered or not */ - + (BOOL)isRegistered; ++ (void)runIfRegistered:(void (^)())block; /** * Returns registered number diff --git a/src/Account/TSAccountManager.m b/src/Account/TSAccountManager.m index 28432c0f0..3b265940a 100644 --- a/src/Account/TSAccountManager.m +++ b/src/Account/TSAccountManager.m @@ -40,6 +40,11 @@ return [TSStorageManager localNumber] ? YES : NO; } ++ (void)runIfRegistered:(void (^)())block +{ + [[TSStorageManager sharedManager] runIfHasLocalNumber:block]; +} + + (void)didRegister { TSAccountManager *sharedManager = [self sharedInstance]; __strong NSString *phoneNumber = sharedManager.phoneNumberAwaitingVerification; diff --git a/src/Storage/TSStorageManager+keyingMaterial.h b/src/Storage/TSStorageManager+keyingMaterial.h index 822de6904..3a988662e 100644 --- a/src/Storage/TSStorageManager+keyingMaterial.h +++ b/src/Storage/TSStorageManager+keyingMaterial.h @@ -33,8 +33,8 @@ * * @return E164 string of the registered phone number */ - + (NSString *)localNumber; +- (void)runIfHasLocalNumber:(void (^)())block; + (void)storeServerToken:(NSString *)authToken signalingKey:(NSString *)signalingKey; diff --git a/src/Storage/TSStorageManager+keyingMaterial.m b/src/Storage/TSStorageManager+keyingMaterial.m index ab9436c83..0a8431400 100644 --- a/src/Storage/TSStorageManager+keyingMaterial.m +++ b/src/Storage/TSStorageManager+keyingMaterial.m @@ -14,6 +14,17 @@ return [[self sharedManager] stringForKey:TSStorageRegisteredNumberKey inCollection:TSStorageUserAccountCollection]; } +- (void)runIfHasLocalNumber:(void (^)())block +{ + [self.newDatabaseConnection asyncReadWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { + if ([transaction objectForKey:TSStorageRegisteredNumberKey inCollection:TSStorageUserAccountCollection]) { + block(); + } else { + DDLogDebug(@"%@ Skipping block since no local number is registered", self.tag); + } + }]; +} + + (NSString *)signalingKey { return [[self sharedManager] stringForKey:TSStorageServerSignalingKey inCollection:TSStorageUserAccountCollection]; } @@ -44,4 +55,16 @@ }]; } +#pragma mark - Logging + ++ (NSString *)tag +{ + return [NSString stringWithFormat:@"[%@]", self.class]; +} + +- (NSString *)tag +{ + return self.class.tag; +} + @end