Allow RemoteConfig to be lazily initialized.

This commit is contained in:
Greyson Parrelli
2024-07-09 16:52:00 -04:00
parent 04e75c18dd
commit 91eeda6c6e
3 changed files with 43 additions and 12 deletions

View File

@@ -145,10 +145,6 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
if (RemoteConfig.internalUser()) {
Tracer.getInstance().setMaxBufferSize(35_000);
}
super.onCreate(); super.onCreate();
AppStartup.getInstance().addBlocking("sqlcipher-init", () -> { AppStartup.getInstance().addBlocking("sqlcipher-init", () -> {
@@ -183,6 +179,7 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr
.addBlocking("remote-config", RemoteConfig::init) .addBlocking("remote-config", RemoteConfig::init)
.addBlocking("ring-rtc", this::initializeRingRtc) .addBlocking("ring-rtc", this::initializeRingRtc)
.addBlocking("glide", () -> SignalGlideModule.setRegisterGlideComponents(new SignalGlideComponents())) .addBlocking("glide", () -> SignalGlideModule.setRegisterGlideComponents(new SignalGlideComponents()))
.addBlocking("tracer", this::initializeTracer)
.addNonBlocking(() -> RegistrationUtil.maybeMarkRegistrationComplete()) .addNonBlocking(() -> RegistrationUtil.maybeMarkRegistrationComplete())
.addNonBlocking(() -> Glide.get(this)) .addNonBlocking(() -> Glide.get(this))
.addNonBlocking(this::cleanAvatarStorage) .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() { private void initializePeriodicTasks() {
RotateSignedPreKeyListener.schedule(this); RotateSignedPreKeyListener.schedule(this);
DirectoryRefreshListener.schedule(this); DirectoryRefreshListener.schedule(this);

View File

@@ -1,5 +1,6 @@
package org.thoughtcrime.securesms.util package org.thoughtcrime.securesms.util
import androidx.annotation.GuardedBy
import androidx.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting
import androidx.annotation.WorkerThread import androidx.annotation.WorkerThread
import org.json.JSONException import org.json.JSONException
@@ -19,6 +20,8 @@ import org.thoughtcrime.securesms.util.RemoteConfig.remoteBoolean
import org.thoughtcrime.securesms.util.RemoteConfig.remoteValue import org.thoughtcrime.securesms.util.RemoteConfig.remoteValue
import java.io.IOException import java.io.IOException
import java.util.TreeMap import java.util.TreeMap
import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
@@ -48,18 +51,27 @@ object RemoteConfig {
@VisibleForTesting @VisibleForTesting
val configsByKey: MutableMap<String, Config<*>> = mutableMapOf() val configsByKey: MutableMap<String, Config<*>> = mutableMapOf()
@GuardedBy("initLock")
@Volatile
@VisibleForTesting
var initialized: Boolean = false
private val initLock: ReentrantLock = ReentrantLock()
@JvmStatic @JvmStatic
@Synchronized
fun init() { fun init() {
val current = parseStoredConfig(SignalStore.remoteConfig.currentConfig) initLock.withLock {
val pending = parseStoredConfig(SignalStore.remoteConfig.pendingConfig) val current = parseStoredConfig(SignalStore.remoteConfig.currentConfig)
val changes = computeChanges(current, pending) val pending = parseStoredConfig(SignalStore.remoteConfig.pendingConfig)
val changes = computeChanges(current, pending)
SignalStore.remoteConfig.currentConfig = mapToJson(pending) SignalStore.remoteConfig.currentConfig = mapToJson(pending)
REMOTE_VALUES.putAll(pending) REMOTE_VALUES.putAll(pending)
triggerFlagChangeListeners(changes) triggerFlagChangeListeners(changes)
Log.i(TAG, "init() $REMOTE_VALUES") Log.i(TAG, "init() $REMOTE_VALUES")
initialized = true
}
} }
@JvmStatic @JvmStatic
@@ -347,6 +359,15 @@ object RemoteConfig {
val transformer: (Any?) -> T val transformer: (Any?) -> T
) { ) {
operator fun getValue(thisRef: Any?, property: KProperty<*>): 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]) return transformer(REMOTE_VALUES[key])
} }
} }

View File

@@ -1,5 +1,6 @@
package org.thoughtcrime.securesms.util package org.thoughtcrime.securesms.util
import org.junit.Before
import org.junit.Test import org.junit.Test
import kotlin.reflect.KProperty1 import kotlin.reflect.KProperty1
import kotlin.reflect.KVisibility import kotlin.reflect.KVisibility
@@ -10,6 +11,11 @@ import kotlin.reflect.full.memberProperties
*/ */
class RemoteConfig_StaticValuesTest { 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 * 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 * 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 configKeys = RemoteConfig.configsByKey.keys
val ignoreList = setOf( val ignoreList = setOf(
"initialized",
"REMOTE_VALUES", "REMOTE_VALUES",
"configsByKey", "configsByKey",
"debugMemoryValues", "debugMemoryValues",