- 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
410 lines
20 KiB
Java
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) {
|
|
}
|
|
}
|
|
}
|
|
}
|