Files
rr3-apk/decompiled-community/sources/com/google/firebase/remoteconfig/internal/ConfigRealtimeHttpClient.java
Daniel Elliott c080f0d97f Add Discord community version (64-bit only)
- Added realracing3-community.apk (71.57 MB)
- Removed 32-bit support (armeabi-v7a)
- Only includes arm64-v8a libraries
- Decompiled source code included
- Added README-community.md with analysis
2026-02-18 15:48:36 -08:00

410 lines
20 KiB
Java

package com.google.firebase.remoteconfig.internal;
import android.content.Context;
import android.content.pm.PackageManager;
import android.util.Log;
import com.google.android.gms.common.util.AndroidUtilsLight;
import com.google.android.gms.common.util.Clock;
import com.google.android.gms.common.util.DefaultClock;
import com.google.android.gms.common.util.Hex;
import com.google.android.gms.tasks.Continuation;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.Tasks;
import com.google.firebase.FirebaseApp;
import com.google.firebase.installations.FirebaseInstallationsApi;
import com.google.firebase.installations.InstallationTokenResult;
import com.google.firebase.remoteconfig.ConfigUpdate;
import com.google.firebase.remoteconfig.ConfigUpdateListener;
import com.google.firebase.remoteconfig.FirebaseRemoteConfigClientException;
import com.google.firebase.remoteconfig.FirebaseRemoteConfigException;
import com.google.firebase.remoteconfig.FirebaseRemoteConfigServerException;
import com.ironsource.nb;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.json.JSONObject;
/* loaded from: classes3.dex */
public class ConfigRealtimeHttpClient {
public static final int[] BACKOFF_TIME_DURATIONS_IN_MINUTES = {2, 4, 8, 16, 32, 64, 128, 256};
public static final Pattern GMP_APP_ID_PATTERN = Pattern.compile("^[^:]+:([0-9]+):(android|ios|web):([0-9a-f]+)");
public ConfigCacheClient activatedCache;
public final ConfigFetchHandler configFetchHandler;
public final Context context;
public final FirebaseApp firebaseApp;
public final FirebaseInstallationsApi firebaseInstallations;
public int httpRetriesRemaining;
public final Set listeners;
public final ConfigMetadataClient metadataClient;
public final String namespace;
public final ScheduledExecutorService scheduledExecutorService;
public final int ORIGINAL_RETRIES = 8;
public boolean isHttpConnectionRunning = false;
public final Random random = new Random();
public final Clock clock = DefaultClock.getInstance();
public boolean isRealtimeDisabled = false;
public boolean isInBackground = false;
public final boolean isStatusCodeRetryable(int i) {
return i == 408 || i == 429 || i == 502 || i == 503 || i == 504;
}
public void setRealtimeBackgroundState(boolean z) {
this.isInBackground = z;
}
public ConfigRealtimeHttpClient(FirebaseApp firebaseApp, FirebaseInstallationsApi firebaseInstallationsApi, ConfigFetchHandler configFetchHandler, ConfigCacheClient configCacheClient, Context context, String str, Set set, ConfigMetadataClient configMetadataClient, ScheduledExecutorService scheduledExecutorService) {
this.listeners = set;
this.scheduledExecutorService = scheduledExecutorService;
this.httpRetriesRemaining = Math.max(8 - configMetadataClient.getRealtimeBackoffMetadata().getNumFailedStreams(), 1);
this.firebaseApp = firebaseApp;
this.configFetchHandler = configFetchHandler;
this.firebaseInstallations = firebaseInstallationsApi;
this.activatedCache = configCacheClient;
this.context = context;
this.namespace = str;
this.metadataClient = configMetadataClient;
}
public static String extractProjectNumberFromAppId(String str) {
Matcher matcher = GMP_APP_ID_PATTERN.matcher(str);
if (matcher.matches()) {
return matcher.group(1);
}
return null;
}
public final String getFingerprintHashForPackage() {
try {
Context context = this.context;
byte[] packageCertificateHashBytes = AndroidUtilsLight.getPackageCertificateHashBytes(context, context.getPackageName());
if (packageCertificateHashBytes == null) {
Log.e("FirebaseRemoteConfig", "Could not get fingerprint hash for package: " + this.context.getPackageName());
return null;
}
return Hex.bytesToStringUppercase(packageCertificateHashBytes, false);
} catch (PackageManager.NameNotFoundException unused) {
StringBuilder sb = new StringBuilder();
sb.append("No such package: ");
sb.append(this.context.getPackageName());
return null;
}
}
public final void setCommonRequestHeaders(HttpURLConnection httpURLConnection, String str) {
httpURLConnection.setRequestProperty("X-Goog-Firebase-Installations-Auth", str);
httpURLConnection.setRequestProperty("X-Goog-Api-Key", this.firebaseApp.getOptions().getApiKey());
httpURLConnection.setRequestProperty("X-Android-Package", this.context.getPackageName());
httpURLConnection.setRequestProperty("X-Android-Cert", getFingerprintHashForPackage());
httpURLConnection.setRequestProperty("X-Google-GFE-Can-Retry", "yes");
httpURLConnection.setRequestProperty("X-Accept-Response-Streaming", "true");
httpURLConnection.setRequestProperty("Content-Type", nb.L);
httpURLConnection.setRequestProperty("Accept", nb.L);
}
public final JSONObject createRequestBody(String str) {
HashMap hashMap = new HashMap();
hashMap.put("project", extractProjectNumberFromAppId(this.firebaseApp.getOptions().getApplicationId()));
hashMap.put("namespace", this.namespace);
hashMap.put("lastKnownVersionNumber", Long.toString(this.configFetchHandler.getTemplateVersionNumber()));
hashMap.put("appId", this.firebaseApp.getOptions().getApplicationId());
hashMap.put("sdkVersion", "22.0.0");
hashMap.put("appInstanceId", str);
return new JSONObject(hashMap);
}
public void setRequestParams(HttpURLConnection httpURLConnection, String str, String str2) {
httpURLConnection.setRequestMethod("POST");
setCommonRequestHeaders(httpURLConnection, str2);
byte[] bytes = createRequestBody(str).toString().getBytes(nb.N);
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(httpURLConnection.getOutputStream());
bufferedOutputStream.write(bytes);
bufferedOutputStream.flush();
bufferedOutputStream.close();
}
public final synchronized void propagateErrors(FirebaseRemoteConfigException firebaseRemoteConfigException) {
Iterator it = this.listeners.iterator();
while (it.hasNext()) {
((ConfigUpdateListener) it.next()).onError(firebaseRemoteConfigException);
}
}
public final void updateBackoffMetadataWithLastFailedStreamConnectionTime(Date date) {
int numFailedStreams = this.metadataClient.getRealtimeBackoffMetadata().getNumFailedStreams() + 1;
this.metadataClient.setRealtimeBackoffMetadata(numFailedStreams, new Date(date.getTime() + getRandomizedBackoffDurationInMillis(numFailedStreams)));
}
public final long getRandomizedBackoffDurationInMillis(int i) {
int length = BACKOFF_TIME_DURATIONS_IN_MINUTES.length;
if (i >= length) {
i = length;
}
return (TimeUnit.MINUTES.toMillis(r0[i - 1]) / 2) + this.random.nextInt((int) r0);
}
public final synchronized void enableBackoff() {
this.isRealtimeDisabled = true;
}
public final synchronized boolean canMakeHttpStreamConnection() {
boolean z;
if (!this.listeners.isEmpty() && !this.isHttpConnectionRunning && !this.isRealtimeDisabled) {
z = this.isInBackground ? false : true;
}
return z;
}
public final String getRealtimeURL(String str) {
return String.format("https://firebaseremoteconfigrealtime.googleapis.com/v1/projects/%s/namespaces/%s:streamFetchInvalidations", extractProjectNumberFromAppId(this.firebaseApp.getOptions().getApplicationId()), str);
}
public final URL getUrl() {
try {
return new URL(getRealtimeURL(this.namespace));
} catch (MalformedURLException unused) {
Log.e("FirebaseRemoteConfig", "URL is malformed");
return null;
}
}
public Task createRealtimeConnection() {
final Task token = this.firebaseInstallations.getToken(false);
final Task id = this.firebaseInstallations.getId();
return Tasks.whenAllComplete((Task<?>[]) new Task[]{token, id}).continueWithTask(this.scheduledExecutorService, new Continuation() { // from class: com.google.firebase.remoteconfig.internal.ConfigRealtimeHttpClient$$ExternalSyntheticLambda1
@Override // com.google.android.gms.tasks.Continuation
public final Object then(Task task) {
Task lambda$createRealtimeConnection$0;
lambda$createRealtimeConnection$0 = ConfigRealtimeHttpClient.this.lambda$createRealtimeConnection$0(token, id, task);
return lambda$createRealtimeConnection$0;
}
});
}
public final /* synthetic */ Task lambda$createRealtimeConnection$0(Task task, Task task2, Task task3) {
if (!task.isSuccessful()) {
return Tasks.forException(new FirebaseRemoteConfigClientException("Firebase Installations failed to get installation auth token for config update listener connection.", task.getException()));
}
if (!task2.isSuccessful()) {
return Tasks.forException(new FirebaseRemoteConfigClientException("Firebase Installations failed to get installation ID for config update listener connection.", task2.getException()));
}
try {
HttpURLConnection httpURLConnection = (HttpURLConnection) getUrl().openConnection();
setRequestParams(httpURLConnection, (String) task2.getResult(), ((InstallationTokenResult) task.getResult()).getToken());
return Tasks.forResult(httpURLConnection);
} catch (IOException e) {
return Tasks.forException(new FirebaseRemoteConfigClientException("Failed to open HTTP stream connection", e));
}
}
public void startHttpConnection() {
makeRealtimeHttpConnection(0L);
}
public synchronized void retryHttpConnectionWhenBackoffEnds() {
makeRealtimeHttpConnection(Math.max(0L, this.metadataClient.getRealtimeBackoffMetadata().getBackoffEndTime().getTime() - new Date(this.clock.currentTimeMillis()).getTime()));
}
public final synchronized void makeRealtimeHttpConnection(long j) {
try {
if (canMakeHttpStreamConnection()) {
int i = this.httpRetriesRemaining;
if (i > 0) {
this.httpRetriesRemaining = i - 1;
this.scheduledExecutorService.schedule(new Runnable() { // from class: com.google.firebase.remoteconfig.internal.ConfigRealtimeHttpClient.1
@Override // java.lang.Runnable
public void run() {
ConfigRealtimeHttpClient.this.beginRealtimeHttpStream();
}
}, j, TimeUnit.MILLISECONDS);
} else if (!this.isInBackground) {
propagateErrors(new FirebaseRemoteConfigClientException("Unable to connect to the server. Check your connection and try again.", FirebaseRemoteConfigException.Code.CONFIG_UPDATE_STREAM_ERROR));
}
}
} catch (Throwable th) {
throw th;
}
}
public final synchronized void resetRetryCount() {
this.httpRetriesRemaining = 8;
}
public final synchronized void setIsHttpConnectionRunning(boolean z) {
this.isHttpConnectionRunning = z;
}
public synchronized ConfigAutoFetch startAutoFetch(HttpURLConnection httpURLConnection) {
return new ConfigAutoFetch(httpURLConnection, this.configFetchHandler, this.activatedCache, this.listeners, new ConfigUpdateListener() { // from class: com.google.firebase.remoteconfig.internal.ConfigRealtimeHttpClient.2
@Override // com.google.firebase.remoteconfig.ConfigUpdateListener
public void onUpdate(ConfigUpdate configUpdate) {
}
@Override // com.google.firebase.remoteconfig.ConfigUpdateListener
public void onError(FirebaseRemoteConfigException firebaseRemoteConfigException) {
ConfigRealtimeHttpClient.this.enableBackoff();
ConfigRealtimeHttpClient.this.propagateErrors(firebaseRemoteConfigException);
}
}, this.scheduledExecutorService);
}
public final String parseForbiddenErrorResponseMessage(InputStream inputStream) {
StringBuilder sb = new StringBuilder();
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
while (true) {
String readLine = bufferedReader.readLine();
if (readLine == null) {
break;
}
sb.append(readLine);
}
} catch (IOException unused) {
if (sb.length() == 0) {
return "Unable to connect to the server, access is forbidden. HTTP status code: 403";
}
}
return sb.toString();
}
public void beginRealtimeHttpStream() {
if (canMakeHttpStreamConnection()) {
if (new Date(this.clock.currentTimeMillis()).before(this.metadataClient.getRealtimeBackoffMetadata().getBackoffEndTime())) {
retryHttpConnectionWhenBackoffEnds();
} else {
final Task createRealtimeConnection = createRealtimeConnection();
Tasks.whenAllComplete((Task<?>[]) new Task[]{createRealtimeConnection}).continueWith(this.scheduledExecutorService, new Continuation() { // from class: com.google.firebase.remoteconfig.internal.ConfigRealtimeHttpClient$$ExternalSyntheticLambda0
@Override // com.google.android.gms.tasks.Continuation
public final Object then(Task task) {
Task lambda$beginRealtimeHttpStream$1;
lambda$beginRealtimeHttpStream$1 = ConfigRealtimeHttpClient.this.lambda$beginRealtimeHttpStream$1(createRealtimeConnection, task);
return lambda$beginRealtimeHttpStream$1;
}
});
}
}
}
public final /* synthetic */ Task lambda$beginRealtimeHttpStream$1(Task task, Task task2) {
Integer num;
Throwable th;
HttpURLConnection httpURLConnection;
FirebaseRemoteConfigServerException firebaseRemoteConfigServerException;
boolean isStatusCodeRetryable;
boolean z = true;
try {
} catch (IOException unused) {
httpURLConnection = null;
num = null;
} catch (Throwable th2) {
num = null;
th = th2;
httpURLConnection = null;
}
if (!task.isSuccessful()) {
throw new IOException(task.getException());
}
setIsHttpConnectionRunning(true);
httpURLConnection = (HttpURLConnection) task.getResult();
try {
num = Integer.valueOf(httpURLConnection.getResponseCode());
try {
if (num.intValue() == 200) {
resetRetryCount();
this.metadataClient.resetRealtimeBackoff();
startAutoFetch(httpURLConnection).listenForNotifications();
}
closeRealtimeHttpStream(httpURLConnection);
setIsHttpConnectionRunning(false);
isStatusCodeRetryable = isStatusCodeRetryable(num.intValue());
if (isStatusCodeRetryable) {
updateBackoffMetadataWithLastFailedStreamConnectionTime(new Date(this.clock.currentTimeMillis()));
}
} catch (IOException unused2) {
closeRealtimeHttpStream(httpURLConnection);
setIsHttpConnectionRunning(false);
if (num != null && !isStatusCodeRetryable(num.intValue())) {
z = false;
}
if (z) {
updateBackoffMetadataWithLastFailedStreamConnectionTime(new Date(this.clock.currentTimeMillis()));
}
if (!z && num.intValue() != 200) {
String format = String.format("Unable to connect to the server. Try again in a few minutes. HTTP status code: %d", num);
if (num.intValue() == 403) {
format = parseForbiddenErrorResponseMessage(httpURLConnection.getErrorStream());
}
firebaseRemoteConfigServerException = new FirebaseRemoteConfigServerException(num.intValue(), format, FirebaseRemoteConfigException.Code.CONFIG_UPDATE_STREAM_ERROR);
propagateErrors(firebaseRemoteConfigServerException);
return Tasks.forResult(null);
}
retryHttpConnectionWhenBackoffEnds();
return Tasks.forResult(null);
} catch (Throwable th3) {
th = th3;
closeRealtimeHttpStream(httpURLConnection);
setIsHttpConnectionRunning(false);
if (num != null && !isStatusCodeRetryable(num.intValue())) {
z = false;
}
if (z) {
updateBackoffMetadataWithLastFailedStreamConnectionTime(new Date(this.clock.currentTimeMillis()));
}
if (z || num.intValue() == 200) {
retryHttpConnectionWhenBackoffEnds();
} else {
String format2 = String.format("Unable to connect to the server. Try again in a few minutes. HTTP status code: %d", num);
if (num.intValue() == 403) {
format2 = parseForbiddenErrorResponseMessage(httpURLConnection.getErrorStream());
}
propagateErrors(new FirebaseRemoteConfigServerException(num.intValue(), format2, FirebaseRemoteConfigException.Code.CONFIG_UPDATE_STREAM_ERROR));
}
throw th;
}
} catch (IOException unused3) {
num = null;
} catch (Throwable th4) {
num = null;
th = th4;
}
if (!isStatusCodeRetryable && num.intValue() != 200) {
String format3 = String.format("Unable to connect to the server. Try again in a few minutes. HTTP status code: %d", num);
if (num.intValue() == 403) {
format3 = parseForbiddenErrorResponseMessage(httpURLConnection.getErrorStream());
}
firebaseRemoteConfigServerException = new FirebaseRemoteConfigServerException(num.intValue(), format3, FirebaseRemoteConfigException.Code.CONFIG_UPDATE_STREAM_ERROR);
propagateErrors(firebaseRemoteConfigServerException);
return Tasks.forResult(null);
}
retryHttpConnectionWhenBackoffEnds();
return Tasks.forResult(null);
}
public void closeRealtimeHttpStream(HttpURLConnection httpURLConnection) {
if (httpURLConnection != null) {
httpURLConnection.disconnect();
try {
httpURLConnection.getInputStream().close();
if (httpURLConnection.getErrorStream() != null) {
httpURLConnection.getErrorStream().close();
}
} catch (IOException unused) {
}
}
}
}