diff --git a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java index de43af0da1..a82a366ce4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java +++ b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java @@ -145,10 +145,6 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr long startTime = System.currentTimeMillis(); - if (RemoteConfig.internalUser()) { - Tracer.getInstance().setMaxBufferSize(35_000); - } - super.onCreate(); AppStartup.getInstance().addBlocking("sqlcipher-init", () -> { @@ -183,6 +179,7 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr .addBlocking("remote-config", RemoteConfig::init) .addBlocking("ring-rtc", this::initializeRingRtc) .addBlocking("glide", () -> SignalGlideModule.setRegisterGlideComponents(new SignalGlideComponents())) + .addBlocking("tracer", this::initializeTracer) .addNonBlocking(() -> RegistrationUtil.maybeMarkRegistrationComplete()) .addNonBlocking(() -> Glide.get(this)) .addNonBlocking(this::cleanAvatarStorage) @@ -423,6 +420,12 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr } } + private void initializeTracer() { + if (RemoteConfig.internalUser()) { + Tracer.getInstance().setMaxBufferSize(35_000); + } + } + private void initializePeriodicTasks() { RotateSignedPreKeyListener.schedule(this); DirectoryRefreshListener.schedule(this); diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/RemoteConfig.kt b/app/src/main/java/org/thoughtcrime/securesms/util/RemoteConfig.kt index ea15e512ba..90edbf4007 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/RemoteConfig.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/RemoteConfig.kt @@ -1,5 +1,6 @@ package org.thoughtcrime.securesms.util +import androidx.annotation.GuardedBy import androidx.annotation.VisibleForTesting import androidx.annotation.WorkerThread import org.json.JSONException @@ -19,6 +20,8 @@ import org.thoughtcrime.securesms.util.RemoteConfig.remoteBoolean import org.thoughtcrime.securesms.util.RemoteConfig.remoteValue import java.io.IOException import java.util.TreeMap +import java.util.concurrent.locks.ReentrantLock +import kotlin.concurrent.withLock import kotlin.math.max import kotlin.math.min import kotlin.reflect.KProperty @@ -48,18 +51,27 @@ object RemoteConfig { @VisibleForTesting val configsByKey: MutableMap> = mutableMapOf() + @GuardedBy("initLock") + @Volatile + @VisibleForTesting + var initialized: Boolean = false + private val initLock: ReentrantLock = ReentrantLock() + @JvmStatic - @Synchronized fun init() { - val current = parseStoredConfig(SignalStore.remoteConfig.currentConfig) - val pending = parseStoredConfig(SignalStore.remoteConfig.pendingConfig) - val changes = computeChanges(current, pending) + initLock.withLock { + val current = parseStoredConfig(SignalStore.remoteConfig.currentConfig) + val pending = parseStoredConfig(SignalStore.remoteConfig.pendingConfig) + val changes = computeChanges(current, pending) - SignalStore.remoteConfig.currentConfig = mapToJson(pending) - REMOTE_VALUES.putAll(pending) - triggerFlagChangeListeners(changes) + SignalStore.remoteConfig.currentConfig = mapToJson(pending) + REMOTE_VALUES.putAll(pending) + triggerFlagChangeListeners(changes) - Log.i(TAG, "init() $REMOTE_VALUES") + Log.i(TAG, "init() $REMOTE_VALUES") + + initialized = true + } } @JvmStatic @@ -347,6 +359,15 @@ object RemoteConfig { val transformer: (Any?) -> T ) { operator fun getValue(thisRef: Any?, property: KProperty<*>): T { + if (!initialized) { + Log.w(TAG, "Tried to read $key before initialization. Initializing now.") + initLock.withLock { + if (!initialized) { + init() + } + } + } + return transformer(REMOTE_VALUES[key]) } } diff --git a/app/src/test/java/org/thoughtcrime/securesms/util/RemoteConfig_StaticValuesTest.kt b/app/src/test/java/org/thoughtcrime/securesms/util/RemoteConfig_StaticValuesTest.kt index 7b5bcfc844..7d436c5002 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/util/RemoteConfig_StaticValuesTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/util/RemoteConfig_StaticValuesTest.kt @@ -1,5 +1,6 @@ package org.thoughtcrime.securesms.util +import org.junit.Before import org.junit.Test import kotlin.reflect.KProperty1 import kotlin.reflect.KVisibility @@ -10,6 +11,11 @@ import kotlin.reflect.full.memberProperties */ class RemoteConfig_StaticValuesTest { + @Before + fun setup() { + RemoteConfig.initialized = true + } + /** * This test cycles the REMOTE_VALUES through a bunch of different inputs, then looks at all of the public getters and checks to see if they return different * values when the inputs change. If they don't, then it's likely that the getter is returning a static value, which was likely introduced during testing @@ -34,6 +40,7 @@ class RemoteConfig_StaticValuesTest { val configKeys = RemoteConfig.configsByKey.keys val ignoreList = setOf( + "initialized", "REMOTE_VALUES", "configsByKey", "debugMemoryValues",