From 477d753c4145498afb1186a8a0d960ebc912c512 Mon Sep 17 00:00:00 2001 From: turtledreams <62231246+turtledreams@users.noreply.github.com> Date: Thu, 23 Oct 2025 18:53:12 +0900 Subject: [PATCH] Lock for RC --- CHANGELOG.md | 1 + app/build.gradle | 3 + .../count/android/sdk/ModuleRemoteConfig.java | 480 +++++++++--------- 3 files changed, 235 insertions(+), 249 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e2204ec7..3e8fbd68a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ ## X.X.X +* Mitigated a potential issue where Remote Config calls could have block the main UI thread processes. * Added a new config flag `setUseSerialExecutor(boolean useSerial)` for selecting immediate request executor type. * Added a new config option `setWebviewDisplayOption(WebViewDisplayOption)` to control how Content and Feedback Widgets are displayed. * `IMMERSIVE` mode (default): Full-screen display (except cutouts). diff --git a/app/build.gradle b/app/build.gradle index ff7933f38..3e21dc9c0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -74,6 +74,9 @@ android { // sourceCompatibility JavaVersion.VERSION_1_8 // targetCompatibility JavaVersion.VERSION_1_8 // } + // kotlinOptions { + // jvmTarget = "1.8" + // } /* //for automatic symbol upload diff --git a/sdk/src/main/java/ly/count/android/sdk/ModuleRemoteConfig.java b/sdk/src/main/java/ly/count/android/sdk/ModuleRemoteConfig.java index 0e091ab12..2957c87f6 100644 --- a/sdk/src/main/java/ly/count/android/sdk/ModuleRemoteConfig.java +++ b/sdk/src/main/java/ly/count/android/sdk/ModuleRemoteConfig.java @@ -3,11 +3,12 @@ import android.text.TextUtils; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.locks.ReentrantReadWriteLock; import ly.count.android.sdk.internal.RemoteConfigHelper; import ly.count.android.sdk.internal.RemoteConfigValueStore; import org.json.JSONException; @@ -30,13 +31,15 @@ public class ModuleRemoteConfig extends ModuleBase { boolean remoteConfigValuesShouldBeCached = false; - List downloadCallbacks = new ArrayList<>(2); + CopyOnWriteArrayList downloadCallbacks = new CopyOnWriteArrayList<>(); public final static String variantObjectNameKey = "name"; @Nullable Map metricOverride = null; + private final ReentrantReadWriteLock remoteConfigStoreLock = new ReentrantReadWriteLock(); + ModuleRemoteConfig(Countly cly, final CountlyConfig config) { super(cly, config); L.v("[ModuleRemoteConfig] Initialising"); @@ -264,17 +267,22 @@ void testingEnrollIntoVariantInternal(@NonNull final String key, @NonNull final * @throws Exception it throws an exception so that it is escalated upwards */ void mergeCheckResponseIntoCurrentValues(boolean clearOldValues, @NonNull Map newRC) { - //todo iterate over all response values and print a summary of the returned keys + ideally a summary of their payload. + remoteConfigStoreLock.writeLock().lock(); + try { + //todo iterate over all response values and print a summary of the returned keys + ideally a summary of their payload. - //merge the new values into the current ones - RemoteConfigValueStore rcvs = loadConfig(); - rcvs.mergeValues(newRC, clearOldValues); + //merge the new values into the current ones + RemoteConfigValueStore rcvs = loadConfig(); + rcvs.mergeValues(newRC, clearOldValues); - L.d("[ModuleRemoteConfig] Finished remote config processing, starting saving"); + L.d("[ModuleRemoteConfig] Finished remote config processing, starting saving"); - saveConfig(rcvs); + saveConfig(rcvs); - L.d("[ModuleRemoteConfig] Finished remote config saving"); + L.d("[ModuleRemoteConfig] Finished remote config saving"); + } finally { + remoteConfigStoreLock.writeLock().unlock(); + } } /** @@ -299,22 +307,28 @@ boolean isResponseValid(@NonNull JSONObject responseJson) { } RCData getRCValue(@NonNull String key) { + remoteConfigStoreLock.readLock().lock(); try { RemoteConfigValueStore rcvs = loadConfig(); return rcvs.getValue(key); } catch (Exception ex) { L.e("[ModuleRemoteConfig] getValue, Call failed:[" + ex.toString() + "]"); return new RCData(null, true); + } finally { + remoteConfigStoreLock.readLock().unlock(); } } Object getRCValueLegacy(@NonNull String key) { + remoteConfigStoreLock.readLock().lock(); try { RemoteConfigValueStore rcvs = loadConfig(); return rcvs.getValueLegacy(key); } catch (Exception ex) { L.e("[ModuleRemoteConfig] getValueLegacy, Call failed:[" + ex.toString() + "]"); return null; + } finally { + remoteConfigStoreLock.readLock().unlock(); } } @@ -334,26 +348,37 @@ void saveConfig(@NonNull RemoteConfigValueStore rcvs) { } void clearValueStoreInternal() { - storageProvider.setRemoteConfigValues(""); + remoteConfigStoreLock.writeLock().lock(); + try { + storageProvider.setRemoteConfigValues(""); + } finally { + remoteConfigStoreLock.writeLock().unlock(); + } } @NonNull Map getAllRemoteConfigValuesInternalLegacy() { + remoteConfigStoreLock.readLock().lock(); try { RemoteConfigValueStore rcvs = loadConfig(); return rcvs.getAllValuesLegacy(); } catch (Exception ex) { Countly.sharedInstance().L.e("[ModuleRemoteConfig] getAllRemoteConfigValuesInternal, Call failed:[" + ex.toString() + "]"); return new HashMap<>(); + } finally { + remoteConfigStoreLock.readLock().unlock(); } } @NonNull Map getAllRemoteConfigValuesInternal() { + remoteConfigStoreLock.readLock().lock(); try { RemoteConfigValueStore rcvs = loadConfig(); return rcvs.getAllValues(); } catch (Exception ex) { Countly.sharedInstance().L.e("[ModuleRemoteConfig] getAllRemoteConfigValuesInternal, Call failed:[" + ex.toString() + "]"); return new HashMap<>(); + } finally { + remoteConfigStoreLock.readLock().unlock(); } } @@ -393,14 +418,21 @@ void clearAndDownloadAfterIdChange() { void CacheOrClearRCValuesIfNeeded() { L.v("[RemoteConfig] CacheOrClearRCValuesIfNeeded, cacheclearing values"); - RemoteConfigValueStore rc = loadConfig(); - rc.cacheClearValues(); - saveConfig(rc); + remoteConfigStoreLock.writeLock().lock(); + try { + RemoteConfigValueStore rc = loadConfig(); + rc.cacheClearValues(); + saveConfig(rc); + } finally { + remoteConfigStoreLock.writeLock().unlock(); + } } void NotifyDownloadCallbacks(RCDownloadCallback devProvidedCallback, RequestResult requestResult, String message, boolean fullUpdate, Map downloadedValues) { for (RCDownloadCallback callback : downloadCallbacks) { - callback.callback(requestResult, message, fullUpdate, downloadedValues); + if (callback != null) { + callback.callback(requestResult, message, fullUpdate, downloadedValues); + } } if (devProvidedCallback != null) { @@ -468,11 +500,9 @@ public class RemoteConfig { * @deprecated Use "clearAll" */ public void clearStoredValues() { - synchronized (_cly) { - L.i("[RemoteConfig] clearStoredValues"); + L.i("[RemoteConfig] clearStoredValues"); - clearValueStoreInternal(); - } + clearValueStoreInternal(); } /** @@ -480,11 +510,9 @@ public void clearStoredValues() { * @deprecated You should use "getValues" */ public Map getAllValues() { - synchronized (_cly) { - L.i("[RemoteConfig] getAllValues"); + L.i("[RemoteConfig] getAllValues"); - return getAllRemoteConfigValuesInternalLegacy(); - } + return getAllRemoteConfigValuesInternalLegacy(); } /** @@ -495,11 +523,9 @@ public Map getAllValues() { * @deprecated You should use "getValue" */ public Object getValueForKey(String key) { - synchronized (_cly) { - L.i("[RemoteConfig] remoteConfigValueForKey, " + key); + L.i("[RemoteConfig] remoteConfigValueForKey, " + key); - return getRCValueLegacy(key); - } + return getRCValueLegacy(key); } /** @@ -510,27 +536,25 @@ public Object getValueForKey(String key) { * @deprecated You should use "downloadOmittingKeys" */ public void updateExceptKeys(String[] keysToExclude, RemoteConfigCallback callback) { - synchronized (_cly) { - L.i("[RemoteConfig] updateExceptKeys"); + L.i("[RemoteConfig] updateExceptKeys"); - if (!consentProvider.getConsent(Countly.CountlyFeatureNames.remoteConfig)) { - if (callback != null) { - callback.callback("No consent given"); - } - return; - } - if (keysToExclude == null) { - L.w("[RemoteConfig] updateExceptKeys passed 'keys to ignore' array is null"); + if (!consentProvider.getConsent(Countly.CountlyFeatureNames.remoteConfig)) { + if (callback != null) { + callback.callback("No consent given"); } + return; + } + if (keysToExclude == null) { + L.w("[RemoteConfig] updateExceptKeys passed 'keys to ignore' array is null"); + } - RCDownloadCallback innerCall = (downloadResult, error, fullValueUpdate, downloadedValues) -> { - if (callback != null) { - callback.callback(error); - } - }; + RCDownloadCallback innerCall = (downloadResult, error, fullValueUpdate, downloadedValues) -> { + if (callback != null) { + callback.callback(error); + } + }; - updateRemoteConfigValues(null, keysToExclude, true, innerCall); - } + updateRemoteConfigValues(null, keysToExclude, true, innerCall); } /** @@ -541,26 +565,24 @@ public void updateExceptKeys(String[] keysToExclude, RemoteConfigCallback callba * @deprecated You should use "downloadSpecificKeys" */ public void updateForKeysOnly(String[] keysToInclude, RemoteConfigCallback callback) { - synchronized (_cly) { - L.i("[RemoteConfig] updateForKeysOnly"); - if (!consentProvider.getConsent(Countly.CountlyFeatureNames.remoteConfig)) { - if (callback != null) { - callback.callback("No consent given"); - } - return; - } - if (keysToInclude == null) { - L.w("[RemoteConfig] updateForKeysOnly passed 'keys to include' array is null"); + L.i("[RemoteConfig] updateForKeysOnly"); + if (!consentProvider.getConsent(Countly.CountlyFeatureNames.remoteConfig)) { + if (callback != null) { + callback.callback("No consent given"); } + return; + } + if (keysToInclude == null) { + L.w("[RemoteConfig] updateForKeysOnly passed 'keys to include' array is null"); + } - RCDownloadCallback innerCall = (downloadResult, error, fullValueUpdate, downloadedValues) -> { - if (callback != null) { - callback.callback(error); - } - }; + RCDownloadCallback innerCall = (downloadResult, error, fullValueUpdate, downloadedValues) -> { + if (callback != null) { + callback.callback(error); + } + }; - updateRemoteConfigValues(keysToInclude, null, true, innerCall); - } + updateRemoteConfigValues(keysToInclude, null, true, innerCall); } /** @@ -570,24 +592,22 @@ public void updateForKeysOnly(String[] keysToInclude, RemoteConfigCallback callb * @deprecated You should use "downloadAllKeys" */ public void update(RemoteConfigCallback callback) { - synchronized (_cly) { - L.i("[RemoteConfig] update"); + L.i("[RemoteConfig] update"); - if (!consentProvider.getConsent(Countly.CountlyFeatureNames.remoteConfig)) { - if (callback != null) { - callback.callback("No consent given"); - } - return; + if (!consentProvider.getConsent(Countly.CountlyFeatureNames.remoteConfig)) { + if (callback != null) { + callback.callback("No consent given"); } + return; + } - RCDownloadCallback innerCall = (downloadResult, error, fullValueUpdate, downloadedValues) -> { - if (callback != null) { - callback.callback(error); - } - }; + RCDownloadCallback innerCall = (downloadResult, error, fullValueUpdate, downloadedValues) -> { + if (callback != null) { + callback.callback(error); + } + }; - updateRemoteConfigValues(null, null, true, innerCall); - } + updateRemoteConfigValues(null, null, true, innerCall); } /** @@ -598,26 +618,24 @@ public void update(RemoteConfigCallback callback) { * @param callback This is called when the operation concludes */ public void downloadOmittingKeys(@Nullable String[] keysToOmit, @Nullable RCDownloadCallback callback) { - synchronized (_cly) { - L.i("[RemoteConfig] downloadOmittingKeys"); + L.i("[RemoteConfig] downloadOmittingKeys"); - if (!consentProvider.getConsent(Countly.CountlyFeatureNames.remoteConfig)) { - if (callback != null) { - callback.callback(RequestResult.Error, null, false, null); - } - return; - } - if (keysToOmit == null) { - L.w("[RemoteConfig] downloadOmittingKeys passed 'keys to ignore' array is null"); - } - - if (callback == null) { - callback = (downloadResult, error, fullValueUpdate, downloadedValues) -> { - }; + if (!consentProvider.getConsent(Countly.CountlyFeatureNames.remoteConfig)) { + if (callback != null) { + callback.callback(RequestResult.Error, null, false, null); } + return; + } + if (keysToOmit == null) { + L.w("[RemoteConfig] downloadOmittingKeys passed 'keys to ignore' array is null"); + } - updateRemoteConfigValues(null, keysToOmit, false, callback); + if (callback == null) { + callback = (downloadResult, error, fullValueUpdate, downloadedValues) -> { + }; } + + updateRemoteConfigValues(null, keysToOmit, false, callback); } /** @@ -628,25 +646,23 @@ public void downloadOmittingKeys(@Nullable String[] keysToOmit, @Nullable RCDown * @param callback This is called when the operation concludes */ public void downloadSpecificKeys(@Nullable String[] keysToInclude, @Nullable RCDownloadCallback callback) { - synchronized (_cly) { - L.i("[RemoteConfig] downloadSpecificKeys"); - if (!consentProvider.getConsent(Countly.CountlyFeatureNames.remoteConfig)) { - if (callback != null) { - callback.callback(RequestResult.Error, null, false, null); - } - return; - } - if (keysToInclude == null) { - L.w("[RemoteConfig] downloadSpecificKeys passed 'keys to include' array is null"); - } - - if (callback == null) { - callback = (downloadResult, error, fullValueUpdate, downloadedValues) -> { - }; + L.i("[RemoteConfig] downloadSpecificKeys"); + if (!consentProvider.getConsent(Countly.CountlyFeatureNames.remoteConfig)) { + if (callback != null) { + callback.callback(RequestResult.Error, null, false, null); } + return; + } + if (keysToInclude == null) { + L.w("[RemoteConfig] downloadSpecificKeys passed 'keys to include' array is null"); + } - updateRemoteConfigValues(keysToInclude, null, false, callback); + if (callback == null) { + callback = (downloadResult, error, fullValueUpdate, downloadedValues) -> { + }; } + + updateRemoteConfigValues(keysToInclude, null, false, callback); } /** @@ -655,23 +671,21 @@ public void downloadSpecificKeys(@Nullable String[] keysToInclude, @Nullable RCD * @param callback This is called when the operation concludes */ public void downloadAllKeys(@Nullable RCDownloadCallback callback) { - synchronized (_cly) { - L.i("[RemoteConfig] downloadAllKeys"); - - if (!consentProvider.getConsent(Countly.CountlyFeatureNames.remoteConfig)) { - if (callback != null) { - callback.callback(RequestResult.Error, null, true, null); - } - return; - } + L.i("[RemoteConfig] downloadAllKeys"); - if (callback == null) { - callback = (downloadResult, error, fullValueUpdate, downloadedValues) -> { - }; + if (!consentProvider.getConsent(Countly.CountlyFeatureNames.remoteConfig)) { + if (callback != null) { + callback.callback(RequestResult.Error, null, true, null); } + return; + } - updateRemoteConfigValues(null, null, false, callback); + if (callback == null) { + callback = (downloadResult, error, fullValueUpdate, downloadedValues) -> { + }; } + + updateRemoteConfigValues(null, null, false, callback); } /** @@ -680,11 +694,9 @@ public void downloadAllKeys(@Nullable RCDownloadCallback callback) { * @return The available RC values */ public @NonNull Map getValues() { - synchronized (_cly) { - L.i("[RemoteConfig] getValues"); + L.i("[RemoteConfig] getValues"); - return getAllRemoteConfigValuesInternal(); - } + return getAllRemoteConfigValuesInternal(); } /** @@ -693,29 +705,24 @@ public void downloadAllKeys(@Nullable RCDownloadCallback callback) { * @return The available RC values */ public @NonNull Map getAllValuesAndEnroll() { - synchronized (_cly) { - L.i("[RemoteConfig] getAllValuesAndEnroll"); - Map values = getAllRemoteConfigValuesInternal(); + L.i("[RemoteConfig] getAllValuesAndEnroll"); + Map values = getAllRemoteConfigValuesInternal(); - if (values.isEmpty()) { - L.i("[RemoteConfig] getAllValuesAndEnroll, No value to enroll"); - } else { - // assuming the values is not empty enroll for the keys - Set setOfKeys = values.keySet(); - String[] arrayOfKeys = new String[setOfKeys.size()]; - - // set to array - int i = 0; - for (String key : setOfKeys) { - arrayOfKeys[i++] = key; - } + if (values.isEmpty()) { + L.i("[RemoteConfig] getAllValuesAndEnroll, No value to enroll"); + } else { + Set setOfKeys = values.keySet(); + String[] arrayOfKeys = new String[setOfKeys.size()]; - // enroll - enrollIntoABTestsForKeys(arrayOfKeys); + int i = 0; + for (String key : setOfKeys) { + arrayOfKeys[i++] = key; } - return values; + enrollIntoABTestsForKeys(arrayOfKeys); } + + return values; } /** @@ -725,16 +732,14 @@ public void downloadAllKeys(@Nullable RCDownloadCallback callback) { * @return The returned value. If no value existed for the key then the inner object (value) will be returned as "null" */ public @NonNull RCData getValue(final @Nullable String key) { - synchronized (_cly) { - L.i("[RemoteConfig] getValue, key:[" + key + "]"); - - if (key == null || key.equals("")) { - L.i("[RemoteConfig] getValue, A valid key should be provided to get its value."); - return new RCData(null, true); - } + L.i("[RemoteConfig] getValue, key:[" + key + "]"); - return getRCValue(key); + if (key == null || key.equals("")) { + L.i("[RemoteConfig] getValue, A valid key should be provided to get its value."); + return new RCData(null, true); } + + return getRCValue(key); } /** @@ -744,26 +749,23 @@ public void downloadAllKeys(@Nullable RCDownloadCallback callback) { * @return The returned value. If no value existed for the key then the inner object will be returned as "null" */ public @NonNull RCData getValueAndEnroll(@Nullable String key) { - synchronized (_cly) { - L.i("[RemoteConfig] getValueAndEnroll, key:[" + key + "]"); + L.i("[RemoteConfig] getValueAndEnroll, key:[" + key + "]"); - if (key == null || key.equals("")) { - L.i("[RemoteConfig] getValueAndEnroll, A valid key should be provided to get its value."); - return new RCData(null, true); - } - - RCData data = getRCValue(key); + if (key == null || key.equals("")) { + L.i("[RemoteConfig] getValueAndEnroll, A valid key should be provided to get its value."); + return new RCData(null, true); + } - if (data.value == null) { - L.i("[RemoteConfig] getValueAndEnroll, No value to enroll"); - } else { - // assuming value is not null enroll to key - String[] arrayOfKeys = { key }; - enrollIntoABTestsForKeys(arrayOfKeys); - } + RCData data = getRCValue(key); - return data; + if (data.value == null) { + L.i("[RemoteConfig] getValueAndEnroll, No value to enroll"); + } else { + String[] arrayOfKeys = { key }; + enrollIntoABTestsForKeys(arrayOfKeys); } + + return data; } /** @@ -772,20 +774,18 @@ public void downloadAllKeys(@Nullable RCDownloadCallback callback) { * @param keys - String array of keys (parameters) */ public void enrollIntoABTestsForKeys(@Nullable String[] keys) { - synchronized (_cly) { - L.i("[RemoteConfig] enrollIntoABTestsForKeys"); - - if (keys == null || keys.length == 0) { - L.w("[RemoteConfig] enrollIntoABTestsForKeys, A key should be provided to enroll the user."); - return; - } + L.i("[RemoteConfig] enrollIntoABTestsForKeys"); - if (!consentProvider.getConsent(Countly.CountlyFeatureNames.remoteConfig)) { - return; - } + if (keys == null || keys.length == 0) { + L.w("[RemoteConfig] enrollIntoABTestsForKeys, A key should be provided to enroll the user."); + return; + } - enrollIntoABTestsForKeysInternal(keys); + if (!consentProvider.getConsent(Countly.CountlyFeatureNames.remoteConfig)) { + return; } + + enrollIntoABTestsForKeysInternal(keys); } /** @@ -794,19 +794,17 @@ public void enrollIntoABTestsForKeys(@Nullable String[] keys) { * @param keys - String array of keys (parameters) */ public void exitABTestsForKeys(@Nullable String[] keys) { - synchronized (_cly) { - L.i("[RemoteConfig] exitABTestsForKeys"); + L.i("[RemoteConfig] exitABTestsForKeys"); - if (keys == null) { - keys = new String[0]; - } - - if (!consentProvider.getConsent(Countly.CountlyFeatureNames.remoteConfig)) { - return; - } + if (keys == null) { + keys = new String[0]; + } - exitABTestsForKeysInternal(keys); + if (!consentProvider.getConsent(Countly.CountlyFeatureNames.remoteConfig)) { + return; } + + exitABTestsForKeysInternal(keys); } /** @@ -815,8 +813,8 @@ public void exitABTestsForKeys(@Nullable String[] keys) { * @param callback The callback that should be added */ public void registerDownloadCallback(@Nullable RCDownloadCallback callback) { - synchronized (_cly) { - L.i("[RemoteConfig] registerDownloadCallback"); + L.i("[RemoteConfig] registerDownloadCallback"); + if (callback != null) { downloadCallbacks.add(callback); } } @@ -827,20 +825,16 @@ public void registerDownloadCallback(@Nullable RCDownloadCallback callback) { * @param callback The callback that should be removed */ public void removeDownloadCallback(@Nullable RCDownloadCallback callback) { - synchronized (_cly) { - L.i("[RemoteConfig] removeDownloadCallback"); - downloadCallbacks.remove(callback); - } + L.i("[RemoteConfig] removeDownloadCallback"); + downloadCallbacks.remove(callback); } /** * Clear all stored remote config values. */ public void clearAll() { - synchronized (_cly) { - L.i("[RemoteConfig] clearAll"); - clearStoredValues(); - } + L.i("[RemoteConfig] clearAll"); + clearStoredValues(); } /** @@ -851,11 +845,9 @@ public void clearAll() { * @return Return the information of all available variants */ public @NonNull Map testingGetAllVariants() { - synchronized (_cly) { - L.i("[RemoteConfig] testingGetAllVariants"); + L.i("[RemoteConfig] testingGetAllVariants"); - return testingGetAllVariantsInternal(); - } + return testingGetAllVariantsInternal(); } /** @@ -866,11 +858,9 @@ public void clearAll() { * @return Return the information of all available variants */ public @NonNull Map testingGetAllExperimentInfo() { - synchronized (_cly) { - L.i("[RemoteConfig] testingGetAllExperimentInfo"); + L.i("[RemoteConfig] testingGetAllExperimentInfo"); - return experimentContainer; - } + return experimentContainer; } /** @@ -882,16 +872,14 @@ public void clearAll() { * @return If returns the stored variants for the given key. Returns "null" if there are no variants for that key. */ public @Nullable String[] testingGetVariantsForKey(@Nullable String key) { - synchronized (_cly) { - L.i("[RemoteConfig] testingGetVariantsForKey"); + L.i("[RemoteConfig] testingGetVariantsForKey"); - if (key == null) { - L.i("[RemoteConfig] testingGetVariantsForKey, provided variant key can not be null"); - return null; - } - - return testingGetVariantsForKeyInternal(key); + if (key == null) { + L.i("[RemoteConfig] testingGetVariantsForKey, provided variant key can not be null"); + return null; } + + return testingGetVariantsForKeyInternal(key); } /** @@ -902,20 +890,18 @@ public void clearAll() { * @param completionCallback this callback will be called when the network request finished */ public void testingDownloadVariantInformation(@Nullable RCVariantCallback completionCallback) { - synchronized (_cly) { - L.i("[RemoteConfig] testingFetchVariantInformation"); + L.i("[RemoteConfig] testingFetchVariantInformation"); - if (!consentProvider.getConsent(Countly.CountlyFeatureNames.remoteConfig)) { - return; - } - - if (completionCallback == null) { - completionCallback = (result, error) -> { - }; - } + if (!consentProvider.getConsent(Countly.CountlyFeatureNames.remoteConfig)) { + return; + } - testingFetchVariantInformationInternal(completionCallback, false); + if (completionCallback == null) { + completionCallback = (result, error) -> { + }; } + + testingFetchVariantInformationInternal(completionCallback, false); } /** @@ -926,20 +912,18 @@ public void testingDownloadVariantInformation(@Nullable RCVariantCallback comple * @param completionCallback this callback will be called when the network request finished */ public void testingDownloadExperimentInformation(@Nullable RCVariantCallback completionCallback) { - synchronized (_cly) { - L.i("[RemoteConfig] testingDownloadExperimentInformation"); + L.i("[RemoteConfig] testingDownloadExperimentInformation"); - if (!consentProvider.getConsent(Countly.CountlyFeatureNames.remoteConfig)) { - return; - } - - if (completionCallback == null) { - completionCallback = (result, error) -> { - }; - } + if (!consentProvider.getConsent(Countly.CountlyFeatureNames.remoteConfig)) { + return; + } - testingFetchVariantInformationInternal(completionCallback, true); + if (completionCallback == null) { + completionCallback = (result, error) -> { + }; } + + testingFetchVariantInformationInternal(completionCallback, true); } /** @@ -952,25 +936,23 @@ public void testingDownloadExperimentInformation(@Nullable RCVariantCallback com * @param completionCallback */ public void testingEnrollIntoVariant(@Nullable String keyName, String variantName, @Nullable RCVariantCallback completionCallback) { - synchronized (_cly) { - L.i("[RemoteConfig] testingEnrollIntoVariant"); + L.i("[RemoteConfig] testingEnrollIntoVariant"); - if (!consentProvider.getConsent(Countly.CountlyFeatureNames.remoteConfig)) { - return; - } - - if (keyName == null || variantName == null) { - L.w("[RemoteConfig] testEnrollIntoVariant, passed key or variant is null. Aborting."); - return; - } + if (!consentProvider.getConsent(Countly.CountlyFeatureNames.remoteConfig)) { + return; + } - if (completionCallback == null) { - completionCallback = (result, error) -> { - }; - } + if (keyName == null || variantName == null) { + L.w("[RemoteConfig] testEnrollIntoVariant, passed key or variant is null. Aborting."); + return; + } - testingEnrollIntoVariantInternal(keyName, variantName, completionCallback); + if (completionCallback == null) { + completionCallback = (result, error) -> { + }; } + + testingEnrollIntoVariantInternal(keyName, variantName, completionCallback); } } }