Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion firebase-perf/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Unreleased

* [fixed] Made a change that should help address an ANR on app launch. [#4831]

# 22.0.0
* [changed] **Breaking Change**: Updated minSdkVersion to API level 23 or higher.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@
import androidx.annotation.Keep;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.google.firebase.FirebaseApp;
import com.google.firebase.StartupTime;
import com.google.firebase.inject.Provider;
import com.google.firebase.perf.logging.AndroidLogger;
import com.google.firebase.perf.util.Optional;
Expand Down Expand Up @@ -54,15 +52,14 @@ public class RemoteConfigManager {
private static final long TIME_AFTER_WHICH_A_FETCH_IS_CONSIDERED_STALE_MS =
TimeUnit.HOURS.toMillis(12);
private static final long FETCH_NEVER_HAPPENED_TIMESTAMP_MS = 0;
private static final long MIN_APP_START_CONFIG_FETCH_DELAY_MS = 5000;
private static final int RANDOM_APP_START_CONFIG_FETCH_DELAY_MS = 25000;
private static final long MIN_CONFIG_FETCH_DELAY_MS = 5000;
private static final int RANDOM_CONFIG_FETCH_DELAY_MS = 25000;
private final long rcmInitTimestamp = getCurrentSystemTimeMillis();

private final DeviceCacheManager cache;
private final ConcurrentHashMap<String, FirebaseRemoteConfigValue> allRcConfigMap;
private final Executor executor;
private final long appStartTimeInMs;
private final long appStartConfigFetchDelayInMs;

private final long remoteConfigFetchDelayInMs;
private long firebaseRemoteConfigLastFetchTimestampMs = FETCH_NEVER_HAPPENED_TIMESTAMP_MS;

@Nullable private Provider<RemoteConfigComponent> firebaseRemoteConfigProvider;
Expand All @@ -80,44 +77,23 @@ private RemoteConfigManager() {
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>()),
/* firebaseRemoteConfig= */ null, // set once FirebaseRemoteConfig is initialized
MIN_APP_START_CONFIG_FETCH_DELAY_MS
+ new Random().nextInt(RANDOM_APP_START_CONFIG_FETCH_DELAY_MS),
getInitialStartupMillis());
}

@VisibleForTesting
@SuppressWarnings("FirebaseUseExplicitDependencies")
static long getInitialStartupMillis() {
StartupTime startupTime = null;
try {
startupTime = FirebaseApp.getInstance().get(StartupTime.class);
} catch (IllegalStateException ex) {
// This can happen if you start a trace before Firebase is init
logger.debug("Unable to get StartupTime instance.");
}
if (startupTime != null) {
return startupTime.getEpochMillis();
} else {
return System.currentTimeMillis();
}
MIN_CONFIG_FETCH_DELAY_MS + new Random().nextInt(RANDOM_CONFIG_FETCH_DELAY_MS));
}

@VisibleForTesting
RemoteConfigManager(
DeviceCacheManager cache,
Executor executor,
FirebaseRemoteConfig firebaseRemoteConfig,
long appStartConfigFetchDelayInMs,
long appStartTimeInMs) {
long remoteConfigFetchDelayInMs) {
this.cache = cache;
this.executor = executor;
this.firebaseRemoteConfig = firebaseRemoteConfig;
this.allRcConfigMap =
firebaseRemoteConfig == null
? new ConcurrentHashMap<>()
: new ConcurrentHashMap<>(firebaseRemoteConfig.getAll());
this.appStartTimeInMs = appStartTimeInMs;
this.appStartConfigFetchDelayInMs = appStartConfigFetchDelayInMs;
this.remoteConfigFetchDelayInMs = remoteConfigFetchDelayInMs;
}

/** Gets the singleton instance. */
Expand Down Expand Up @@ -329,7 +305,7 @@ public boolean isLastFetchFailed() {
*
* <ol>
* <li>Firebase Remote Config is available,
* <li>Time-since-app-start has passed a randomized delay-time (b/187985523), and
* <li>Time has passed a randomized delay-time (b/187985523), and
* <li>At least 12 hours have passed since the previous fetch.
* </ol>
*/
Expand Down Expand Up @@ -408,17 +384,17 @@ public boolean isFirebaseRemoteConfigAvailable() {
/** Returns true if a RC fetch should be made, false otherwise. */
private boolean shouldFetchAndActivateRemoteConfigValues() {
long currentTimeInMs = getCurrentSystemTimeMillis();
return hasAppStartConfigFetchDelayElapsed(currentTimeInMs)
return hasRemoteConfigFetchDelayElapsed(currentTimeInMs)
&& hasLastFetchBecomeStale(currentTimeInMs);
}

/**
* Delay fetch by some random time since app start. This is to prevent b/187985523.
* Delay fetch by some random time. This is to prevent b/187985523.
*
* @return true if the random delay has elapsed, false otherwise
*/
private boolean hasAppStartConfigFetchDelayElapsed(long currentTimeInMs) {
return (currentTimeInMs - appStartTimeInMs) >= appStartConfigFetchDelayInMs;
private boolean hasRemoteConfigFetchDelayElapsed(long currentTimeInMs) {
return (currentTimeInMs - rcmInitTimestamp) >= remoteConfigFetchDelayInMs;
}

// We want to fetch once when the app starts and every 12 hours after that.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -835,20 +835,20 @@ public void isLastFetchFailed_frcIsNonNullAndStatusOtherThanFailedOrThrottled_re
}

@Test
public void triggerRemoteConfigFetchIfNecessary_doesNotFetchBeforeAppStartRandomDelay() {
long appStartConfigFetchDelay = 5000;
public void triggerRemoteConfigFetchIfNecessary_doesNotFetchBeforeRandomDelay() {
long remoteConfigFetchDelay = 5000;
RemoteConfigManager remoteConfigManagerPartialMock =
spy(
setupTestRemoteConfigManager(
createFakeTaskThatDoesNothing(),
true,
createDefaultRcConfigMap(),
appStartConfigFetchDelay));
remoteConfigFetchDelay));

// Simulate time fast forward to some time before fetch time is up
long appStartTimeInMs = System.currentTimeMillis();
long approxRcmInitTimestampMs = System.currentTimeMillis();
when(remoteConfigManagerPartialMock.getCurrentSystemTimeMillis())
.thenReturn(appStartTimeInMs + appStartConfigFetchDelay - 2000);
.thenReturn(approxRcmInitTimestampMs + remoteConfigFetchDelay - 2000);

simulateFirebaseRemoteConfigLastFetchStatus(
FirebaseRemoteConfig.LAST_FETCH_STATUS_NO_FETCH_YET);
Expand All @@ -861,20 +861,20 @@ public void triggerRemoteConfigFetchIfNecessary_doesNotFetchBeforeAppStartRandom
}

@Test
public void triggerRemoteConfigFetchIfNecessary_fetchesAfterAppStartRandomDelay() {
long appStartConfigFetchDelay = 5000;
public void triggerRemoteConfigFetchIfNecessary_fetchesAfterRandomDelay() {
long remoteConfigFetchDelay = 5000;
RemoteConfigManager remoteConfigManagerPartialMock =
spy(
setupTestRemoteConfigManager(
createFakeTaskThatDoesNothing(),
true,
createDefaultRcConfigMap(),
appStartConfigFetchDelay));
remoteConfigFetchDelay));

// Simulate time fast forward to 2s after fetch delay time is up
long appStartTimeInMs = System.currentTimeMillis();
long approxRcmInitTimestampInMs = System.currentTimeMillis();
when(remoteConfigManagerPartialMock.getCurrentSystemTimeMillis())
.thenReturn(appStartTimeInMs + appStartConfigFetchDelay + 2000);
.thenReturn(approxRcmInitTimestampInMs + remoteConfigFetchDelay + 2000);

simulateFirebaseRemoteConfigLastFetchStatus(
FirebaseRemoteConfig.LAST_FETCH_STATUS_NO_FETCH_YET);
Expand Down Expand Up @@ -918,24 +918,16 @@ private RemoteConfigManager setupTestRemoteConfigManager(
Task<Boolean> fakeTask,
boolean initializeFrc,
Map<String, FirebaseRemoteConfigValue> configs,
long appStartConfigFetchDelayInMs) {
long remoteConfigFetchDelayInMs) {
simulateFirebaseRemoteConfigLastFetchStatus(FirebaseRemoteConfig.LAST_FETCH_STATUS_SUCCESS);
when(mockFirebaseRemoteConfig.fetchAndActivate()).thenReturn(fakeTask);
when(mockFirebaseRemoteConfig.getAll()).thenReturn(configs);
if (initializeFrc) {
return new RemoteConfigManager(
cacheManager,
fakeExecutor,
mockFirebaseRemoteConfig,
appStartConfigFetchDelayInMs,
RemoteConfigManager.getInitialStartupMillis());
cacheManager, fakeExecutor, mockFirebaseRemoteConfig, remoteConfigFetchDelayInMs);
} else {
return new RemoteConfigManager(
cacheManager,
fakeExecutor,
/* firebaseRemoteConfig= */ null,
appStartConfigFetchDelayInMs,
RemoteConfigManager.getInitialStartupMillis());
cacheManager, fakeExecutor, /* firebaseRemoteConfig= */ null, remoteConfigFetchDelayInMs);
}
}

Expand Down