@@ -85,6 +85,9 @@ public class ConfigFetchHandler {
85
85
*/
86
86
@ VisibleForTesting static final String FIRST_OPEN_TIME_KEY = "_fot" ;
87
87
88
+ /** Custom Http header key to identify the fetch type. */
89
+ private static final String X_FIREBASE_RC_FETCH_TYPE = "X-Firebase-RC-Fetch-Type" ;
90
+
88
91
private final FirebaseInstallationsApi firebaseInstallations ;
89
92
private final Provider <AnalyticsConnector > analyticsConnector ;
90
93
@@ -156,13 +159,66 @@ public Task<FetchResponse> fetch() {
156
159
* updates, the {@link FetchResponse}'s configs will be {@code null}.
157
160
*/
158
161
public Task <FetchResponse > fetch (long minimumFetchIntervalInSeconds ) {
162
+
163
+ // Make a copy to prevent any concurrency issues between Fetches.
164
+ Map <String , String > copyOfCustomHttpHeaders = new HashMap <>(customHttpHeaders );
165
+ copyOfCustomHttpHeaders .put (X_FIREBASE_RC_FETCH_TYPE , FetchType .BASE .getValue () + "/" + 1 );
166
+
159
167
return fetchedConfigsCache
160
168
.get ()
161
169
.continueWithTask (
162
170
executor ,
163
171
(cachedFetchConfigsTask ) ->
164
172
fetchIfCacheExpiredAndNotThrottled (
165
- cachedFetchConfigsTask , minimumFetchIntervalInSeconds ));
173
+ cachedFetchConfigsTask ,
174
+ minimumFetchIntervalInSeconds ,
175
+ copyOfCustomHttpHeaders ));
176
+ }
177
+
178
+ /**
179
+ * Starts fetching configs from the Firebase Remote Config server.
180
+ *
181
+ * <p>Guarantees consistency between memory and disk; fetched configs are saved to memory only
182
+ * after they have been written to disk.
183
+ *
184
+ * <p>Fetches even if the read of the fetch cache fails (assumes there are no cached fetched
185
+ * configs in that case).
186
+ *
187
+ * <p>If the fetch request could not be created or there was error connecting to the server, the
188
+ * returned Task throws a {@link FirebaseRemoteConfigClientException}.
189
+ *
190
+ * <p>If the server responds with an error, the returned Task throws a {@link
191
+ * FirebaseRemoteConfigServerException}.
192
+ *
193
+ * <p>If any of the following is true, then the returned Task throws a {@link
194
+ * FirebaseRemoteConfigFetchThrottledException}:
195
+ *
196
+ * <ul>
197
+ * <li>The backoff duration from a previous throttled exception has not expired,
198
+ * <li>The backend responded with a throttled error, or
199
+ * <li>The backend responded with unavailable errors for the last two fetch requests.
200
+ * </ul>
201
+ *
202
+ * @param {@link FetchType} and fetchAttemptNumber help detail what started the fetch call.
203
+ * @return A {@link Task} representing an immediate fetch call that returns a {@link
204
+ * FetchResponse} with the configs fetched from the backend. If the backend was not called or
205
+ * the backend had no updates, the {@link FetchResponse}'s configs will be {@code null}.
206
+ */
207
+ public Task <FetchResponse > fetchNowWithTypeAndAttemptNumber (
208
+ FetchType fetchType , int fetchAttemptNumber ) {
209
+
210
+ // Make a copy to prevent any concurrency issues between Fetches.
211
+ Map <String , String > copyOfCustomHttpHeaders = new HashMap <>(customHttpHeaders );
212
+ copyOfCustomHttpHeaders .put (
213
+ X_FIREBASE_RC_FETCH_TYPE , fetchType .getValue () + "/" + fetchAttemptNumber );
214
+
215
+ return fetchedConfigsCache
216
+ .get ()
217
+ .continueWithTask (
218
+ executor ,
219
+ (cachedFetchConfigsTask ) ->
220
+ fetchIfCacheExpiredAndNotThrottled (
221
+ cachedFetchConfigsTask , 0 , copyOfCustomHttpHeaders ));
166
222
}
167
223
168
224
/**
@@ -173,7 +229,9 @@ public Task<FetchResponse> fetch(long minimumFetchIntervalInSeconds) {
173
229
* fetch time and {@link BackoffMetadata} in {@link ConfigMetadataClient}.
174
230
*/
175
231
private Task <FetchResponse > fetchIfCacheExpiredAndNotThrottled (
176
- Task <ConfigContainer > cachedFetchConfigsTask , long minimumFetchIntervalInSeconds ) {
232
+ Task <ConfigContainer > cachedFetchConfigsTask ,
233
+ long minimumFetchIntervalInSeconds ,
234
+ Map <String , String > customFetchHeaders ) {
177
235
Date currentTime = new Date (clock .currentTimeMillis ());
178
236
if (cachedFetchConfigsTask .isSuccessful ()
179
237
&& areCachedFetchConfigsValid (minimumFetchIntervalInSeconds , currentTime )) {
@@ -218,7 +276,7 @@ && areCachedFetchConfigsValid(minimumFetchIntervalInSeconds, currentTime)) {
218
276
String installationId = installationIdTask .getResult ();
219
277
String installationToken = installationAuthTokenTask .getResult ().getToken ();
220
278
return fetchFromBackendAndCacheResponse (
221
- installationId , installationToken , currentTime );
279
+ installationId , installationToken , currentTime , customFetchHeaders );
222
280
});
223
281
}
224
282
@@ -278,9 +336,13 @@ private String createThrottledMessage(long throttledDurationInMillis) {
278
336
* {@code fetchedConfigsCache}.
279
337
*/
280
338
private Task <FetchResponse > fetchFromBackendAndCacheResponse (
281
- String installationId , String installationToken , Date fetchTime ) {
339
+ String installationId ,
340
+ String installationToken ,
341
+ Date fetchTime ,
342
+ Map <String , String > customFetchHeaders ) {
282
343
try {
283
- FetchResponse fetchResponse = fetchFromBackend (installationId , installationToken , fetchTime );
344
+ FetchResponse fetchResponse =
345
+ fetchFromBackend (installationId , installationToken , fetchTime , customFetchHeaders );
284
346
if (fetchResponse .getStatus () != Status .BACKEND_UPDATES_FETCHED ) {
285
347
return Tasks .forResult (fetchResponse );
286
348
}
@@ -303,7 +365,10 @@ private Task<FetchResponse> fetchFromBackendAndCacheResponse(
303
365
*/
304
366
@ WorkerThread
305
367
private FetchResponse fetchFromBackend (
306
- String installationId , String installationToken , Date currentTime )
368
+ String installationId ,
369
+ String installationToken ,
370
+ Date currentTime ,
371
+ Map <String , String > customFetchHeaders )
307
372
throws FirebaseRemoteConfigException {
308
373
try {
309
374
HttpURLConnection urlConnection = frcBackendApiClient .createHttpURLConnection ();
@@ -315,7 +380,7 @@ private FetchResponse fetchFromBackend(
315
380
installationToken ,
316
381
getUserProperties (),
317
382
frcMetadata .getLastFetchETag (),
318
- customHttpHeaders ,
383
+ customFetchHeaders ,
319
384
getFirstOpenTime (),
320
385
currentTime );
321
386
@@ -626,4 +691,19 @@ public ConfigContainer getFetchedConfigs() {
626
691
int LOCAL_STORAGE_USED = 2 ;
627
692
}
628
693
}
694
+
695
+ public enum FetchType {
696
+ BASE ("Base" ),
697
+ REALTIME ("Realtime" );
698
+
699
+ private final String value ;
700
+
701
+ FetchType (String value ) {
702
+ this .value = value ;
703
+ }
704
+
705
+ String getValue () {
706
+ return value ;
707
+ }
708
+ }
629
709
}
0 commit comments