diff --git a/FirebaseRemoteConfig/CHANGELOG.md b/FirebaseRemoteConfig/CHANGELOG.md index 91ba0e80f24..495dbaeb55e 100644 --- a/FirebaseRemoteConfig/CHANGELOG.md +++ b/FirebaseRemoteConfig/CHANGELOG.md @@ -1,3 +1,9 @@ +# Unreleased +- [fixed] Fixed a bug where Remote Config does not work after a restore + of a previous backup of the device. (#14459) +- [fixed] Fixed a data race condition on the global database status flag + by synchronizing all read and write operations. (#14715) + # 12.3.0 - [fixed] Add missing GoogleUtilities dependency to fix SwiftPM builds when building dynamically linked libraries. (#15276) diff --git a/FirebaseRemoteConfig/Sources/FIRRemoteConfig.m b/FirebaseRemoteConfig/Sources/FIRRemoteConfig.m index 258eb362fe7..bfc55cdf877 100644 --- a/FirebaseRemoteConfig/Sources/FIRRemoteConfig.m +++ b/FirebaseRemoteConfig/Sources/FIRRemoteConfig.m @@ -160,6 +160,10 @@ - (instancetype)initWithAppName:(NSString *)appName // Initialize RCConfigContent if not already. _configContent = configContent; + + // We must ensure the DBManager's asynchronous setup (which sets gIsNewDatabase) + // completes before RCNConfigSettings tries to read that state for the resetUserDefaults logic. + [_DBManager waitForDatabaseOperationQueue]; _settings = [[RCNConfigSettings alloc] initWithDatabaseManager:_DBManager namespace:_FIRNamespace firebaseAppName:appName diff --git a/FirebaseRemoteConfig/Sources/RCNConfigDBManager.h b/FirebaseRemoteConfig/Sources/RCNConfigDBManager.h index e22b40d3779..d881381186b 100644 --- a/FirebaseRemoteConfig/Sources/RCNConfigDBManager.h +++ b/FirebaseRemoteConfig/Sources/RCNConfigDBManager.h @@ -130,4 +130,8 @@ typedef void (^RCNDBLoadCompletion)(BOOL success, /// Returns true if this a new install of the Config database. - (BOOL)isNewDatabase; + +/// Blocks the calling thread until all pending database operations on the internal serial queue are +/// completed. Used to enforce initialization order. +- (void)waitForDatabaseOperationQueue; @end diff --git a/FirebaseRemoteConfig/Sources/RCNConfigDBManager.m b/FirebaseRemoteConfig/Sources/RCNConfigDBManager.m index 161f678b8d6..c1fd403a246 100644 --- a/FirebaseRemoteConfig/Sources/RCNConfigDBManager.m +++ b/FirebaseRemoteConfig/Sources/RCNConfigDBManager.m @@ -38,6 +38,9 @@ /// The storage sub-directory that the Remote Config database resides in. static NSString *const RCNRemoteConfigStorageSubDirectory = @"Google/RemoteConfig"; +/// Introduce a dedicated serial queue for gIsNewDatabase access. +static dispatch_queue_t gIsNewDatabaseQueue; + /// Remote Config database path for deprecated V0 version. static NSString *RemoteConfigPathForOldDatabaseV0(void) { NSArray *dirPaths = @@ -82,7 +85,9 @@ static BOOL RemoteConfigCreateFilePathIfNotExist(NSString *filePath) { } NSFileManager *fileManager = [NSFileManager defaultManager]; if (![fileManager fileExistsAtPath:filePath]) { - gIsNewDatabase = YES; + dispatch_sync(gIsNewDatabaseQueue, ^{ + gIsNewDatabase = YES; + }); NSError *error; [fileManager createDirectoryAtPath:[filePath stringByDeletingLastPathComponent] withIntermediateDirectories:YES @@ -119,6 +124,8 @@ + (instancetype)sharedInstance { static dispatch_once_t onceToken; static RCNConfigDBManager *sharedInstance; dispatch_once(&onceToken, ^{ + gIsNewDatabaseQueue = dispatch_queue_create("com.google.FirebaseRemoteConfig.gIsNewDatabase", + DISPATCH_QUEUE_SERIAL); sharedInstance = [[RCNConfigDBManager alloc] init]; }); return sharedInstance; @@ -1219,7 +1226,19 @@ - (BOOL)logErrorWithSQL:(const char *)SQL } - (BOOL)isNewDatabase { - return gIsNewDatabase; + __block BOOL isNew; + dispatch_sync(gIsNewDatabaseQueue, ^{ + isNew = gIsNewDatabase; + }); + return isNew; +} + +- (void)waitForDatabaseOperationQueue { + // This dispatch_sync call ensures that all blocks queued before it on _databaseOperationQueue + // (including the createOrOpenDatabase setup block) execute and complete before this method + // returns. + dispatch_sync(_databaseOperationQueue, ^{ + }); } @end