Skip to content

Commit abdd518

Browse files
authored
Use shared executors in App Distribution SDK (#4338)
1 parent 26f743d commit abdd518

File tree

7 files changed

+58
-48
lines changed

7 files changed

+58
-48
lines changed

firebase-appdistribution/firebase-appdistribution.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ android {
4444
dependencies {
4545
implementation 'org.jetbrains:annotations:15.0'
4646
implementation project(':firebase-appdistribution-api')
47+
implementation project(':firebase-annotations')
4748
implementation project(':firebase-components')
4849
implementation project(':firebase-installations-interop')
4950
implementation project(':firebase-common')

firebase-appdistribution/src/main/java/com/google/firebase/appdistribution/impl/AabUpdater.java

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import static com.google.firebase.appdistribution.impl.TaskUtils.runAsyncInTask;
2020
import static com.google.firebase.appdistribution.impl.TaskUtils.safeSetTaskException;
2121

22-
import android.annotation.SuppressLint;
2322
import android.app.Activity;
2423
import android.content.Intent;
2524
import android.net.Uri;
@@ -31,7 +30,6 @@
3130
import com.google.firebase.appdistribution.UpdateStatus;
3231
import java.io.IOException;
3332
import java.util.concurrent.Executor;
34-
import java.util.concurrent.Executors;
3533
import javax.net.ssl.HttpsURLConnection;
3634

3735
/** Class that handles updateApp functionality for AABs in {@link FirebaseAppDistribution}. */
@@ -40,7 +38,7 @@ class AabUpdater {
4038

4139
private final FirebaseAppDistributionLifecycleNotifier lifecycleNotifier;
4240
private final HttpsUrlConnectionFactory httpsUrlConnectionFactory;
43-
private final Executor executor;
41+
private final Executor blockingExecutor;
4442

4543
private final Object updateAabLock = new Object();
4644

@@ -53,23 +51,21 @@ class AabUpdater {
5351
@GuardedBy("updateAabLock")
5452
private boolean hasBeenSentToPlayForCurrentTask = false;
5553

56-
// TODO(b/258264924): Migrate to go/firebase-android-executors
57-
@SuppressLint("ThreadPoolCreation")
58-
AabUpdater() {
54+
AabUpdater(@NonNull Executor blockingExecutor) {
5955
this(
6056
FirebaseAppDistributionLifecycleNotifier.getInstance(),
6157
new HttpsUrlConnectionFactory(),
62-
Executors.newSingleThreadExecutor());
58+
blockingExecutor);
6359
}
6460

6561
AabUpdater(
6662
@NonNull FirebaseAppDistributionLifecycleNotifier lifecycleNotifier,
6763
@NonNull HttpsUrlConnectionFactory httpsUrlConnectionFactory,
68-
@NonNull Executor executor) {
64+
@NonNull Executor blockingExecutor) {
6965
this.lifecycleNotifier = lifecycleNotifier;
7066
this.httpsUrlConnectionFactory = httpsUrlConnectionFactory;
7167
lifecycleNotifier.addOnActivityStartedListener(this::onActivityStarted);
72-
this.executor = executor;
68+
this.blockingExecutor = blockingExecutor;
7369
}
7470

7571
@VisibleForTesting
@@ -97,13 +93,13 @@ UpdateTaskImpl updateAab(@NonNull AppDistributionReleaseInternal newRelease) {
9793
hasBeenSentToPlayForCurrentTask = false;
9894

9995
// On a background thread, fetch the redirect URL and open it in the Play app
100-
runAsyncInTask(executor, () -> fetchDownloadRedirectUrl(newRelease.getDownloadUrl()))
96+
runAsyncInTask(blockingExecutor, () -> fetchDownloadRedirectUrl(newRelease.getDownloadUrl()))
10197
.onSuccessTask(
102-
executor,
98+
blockingExecutor,
10399
redirectUrl ->
104100
lifecycleNotifier.consumeForegroundActivity(
105101
activity -> openRedirectUrlInPlay(redirectUrl, activity)))
106-
.addOnFailureListener(executor, this::setUpdateTaskCompletionError);
102+
.addOnFailureListener(blockingExecutor, this::setUpdateTaskCompletionError);
107103

108104
return cachedUpdateTask;
109105
}

firebase-appdistribution/src/main/java/com/google/firebase/appdistribution/impl/ApkUpdater.java

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import static com.google.firebase.appdistribution.impl.TaskUtils.safeSetTaskException;
2020
import static com.google.firebase.appdistribution.impl.TaskUtils.safeSetTaskResult;
2121

22-
import android.annotation.SuppressLint;
2322
import android.content.Context;
2423
import android.os.Build.VERSION;
2524
import android.os.Build.VERSION_CODES;
@@ -38,7 +37,6 @@
3837
import java.io.IOException;
3938
import java.io.InputStream;
4039
import java.util.concurrent.Executor;
41-
import java.util.concurrent.Executors;
4240
import java.util.jar.JarFile;
4341
import javax.net.ssl.HttpsURLConnection;
4442

@@ -51,7 +49,7 @@ class ApkUpdater {
5149
private static final String DEFAULT_APK_FILE_NAME = "downloaded_release.apk";
5250

5351
private TaskCompletionSource<File> downloadTaskCompletionSource;
54-
private final Executor taskExecutor; // Executor to run task listeners on a background thread
52+
private final Executor blockingExecutor; // Executor to run task listeners on a background thread
5553
private final Context context;
5654
private final ApkInstaller apkInstaller;
5755
private final FirebaseAppDistributionNotificationsManager appDistributionNotificationsManager;
@@ -63,11 +61,12 @@ class ApkUpdater {
6361

6462
private final Object updateTaskLock = new Object();
6563

66-
// TODO(b/258264924): Migrate to go/firebase-android-executors
67-
@SuppressLint("ThreadPoolCreation")
68-
public ApkUpdater(@NonNull FirebaseApp firebaseApp, @NonNull ApkInstaller apkInstaller) {
64+
public ApkUpdater(
65+
@NonNull FirebaseApp firebaseApp,
66+
@NonNull ApkInstaller apkInstaller,
67+
@NonNull Executor blockingExecutor) {
6968
this(
70-
Executors.newSingleThreadExecutor(),
69+
blockingExecutor,
7170
firebaseApp.getApplicationContext(),
7271
apkInstaller,
7372
new FirebaseAppDistributionNotificationsManager(firebaseApp.getApplicationContext()),
@@ -77,13 +76,13 @@ public ApkUpdater(@NonNull FirebaseApp firebaseApp, @NonNull ApkInstaller apkIns
7776

7877
@VisibleForTesting
7978
public ApkUpdater(
80-
@NonNull Executor taskExecutor,
79+
@NonNull Executor blockingExecutor,
8180
@NonNull Context context,
8281
@NonNull ApkInstaller apkInstaller,
8382
@NonNull FirebaseAppDistributionNotificationsManager appDistributionNotificationsManager,
8483
@NonNull HttpsUrlConnectionFactory httpsUrlConnectionFactory,
8584
@NonNull FirebaseAppDistributionLifecycleNotifier lifeCycleNotifier) {
86-
this.taskExecutor = taskExecutor;
85+
this.blockingExecutor = blockingExecutor;
8786
this.context = context;
8887
this.apkInstaller = apkInstaller;
8988
this.appDistributionNotificationsManager = appDistributionNotificationsManager;
@@ -102,9 +101,9 @@ UpdateTaskImpl updateApk(
102101
}
103102

104103
downloadApk(newRelease, showNotification)
105-
.addOnSuccessListener(taskExecutor, file -> installApk(file, showNotification))
104+
.addOnSuccessListener(blockingExecutor, file -> installApk(file, showNotification))
106105
.addOnFailureListener(
107-
taskExecutor,
106+
blockingExecutor,
108107
e -> {
109108
setUpdateTaskCompletionErrorWithDefault(
110109
e, "Failed to download APK", Status.DOWNLOAD_FAILURE);
@@ -120,14 +119,14 @@ private void installApk(File file, boolean showDownloadNotificationManager) {
120119
.applyToForegroundActivityTask(
121120
activity -> apkInstaller.installApk(file.getPath(), activity))
122121
.addOnSuccessListener(
123-
taskExecutor,
122+
blockingExecutor,
124123
unused -> {
125124
synchronized (updateTaskLock) {
126125
safeSetTaskResult(cachedUpdateTask);
127126
}
128127
})
129128
.addOnFailureListener(
130-
taskExecutor,
129+
blockingExecutor,
131130
e -> {
132131
postUpdateProgress(
133132
file.length(),
@@ -151,7 +150,7 @@ Task<File> downloadApk(
151150

152151
downloadTaskCompletionSource = new TaskCompletionSource<>();
153152

154-
taskExecutor.execute(
153+
blockingExecutor.execute(
155154
() -> {
156155
try {
157156
makeApkDownloadRequest(newRelease, showNotification);

firebase-appdistribution/src/main/java/com/google/firebase/appdistribution/impl/FirebaseAppDistributionRegistrar.java

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,19 @@
1919
import androidx.annotation.Keep;
2020
import androidx.annotation.NonNull;
2121
import com.google.firebase.FirebaseApp;
22+
import com.google.firebase.annotations.concurrent.Blocking;
2223
import com.google.firebase.appdistribution.FirebaseAppDistribution;
2324
import com.google.firebase.components.Component;
2425
import com.google.firebase.components.ComponentContainer;
2526
import com.google.firebase.components.ComponentRegistrar;
2627
import com.google.firebase.components.Dependency;
28+
import com.google.firebase.components.Qualified;
2729
import com.google.firebase.inject.Provider;
2830
import com.google.firebase.installations.FirebaseInstallationsApi;
2931
import com.google.firebase.platforminfo.LibraryVersionComponent;
3032
import java.util.Arrays;
3133
import java.util.List;
34+
import java.util.concurrent.Executor;
3235

3336
/**
3437
* Registers FirebaseAppDistribution.
@@ -39,31 +42,37 @@
3942
public class FirebaseAppDistributionRegistrar implements ComponentRegistrar {
4043
private static final String LIBRARY_NAME = "fire-appdistribution";
4144

42-
private static String TAG = "Registrar:";
45+
private static String TAG = "FirebaseAppDistributionRegistrar";
4346

4447
@Override
4548
public @NonNull List<Component<?>> getComponents() {
49+
Qualified<Executor> blockingExecutor = Qualified.qualified(Blocking.class, Executor.class);
4650
return Arrays.asList(
4751
Component.builder(FirebaseAppDistribution.class)
4852
.name(LIBRARY_NAME)
4953
.add(Dependency.required(FirebaseApp.class))
5054
.add(Dependency.requiredProvider(FirebaseInstallationsApi.class))
51-
.factory(this::buildFirebaseAppDistribution)
55+
.add(Dependency.required(blockingExecutor))
56+
.factory(c -> buildFirebaseAppDistribution(c, c.get(blockingExecutor)))
5257
// construct FirebaseAppDistribution instance on startup so we can register for
5358
// activity lifecycle callbacks before the API is called
5459
.alwaysEager()
5560
.build(),
5661
LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME));
5762
}
5863

59-
private FirebaseAppDistribution buildFirebaseAppDistribution(ComponentContainer container) {
64+
private FirebaseAppDistribution buildFirebaseAppDistribution(
65+
ComponentContainer container, Executor blockingExecutor) {
6066
FirebaseApp firebaseApp = container.get(FirebaseApp.class);
6167
Context context = firebaseApp.getApplicationContext();
6268
Provider<FirebaseInstallationsApi> firebaseInstallationsApiProvider =
6369
container.getProvider(FirebaseInstallationsApi.class);
6470
FirebaseAppDistributionTesterApiClient testerApiClient =
6571
new FirebaseAppDistributionTesterApiClient(
66-
firebaseApp, firebaseInstallationsApiProvider, new TesterApiHttpClient(firebaseApp));
72+
firebaseApp,
73+
firebaseInstallationsApiProvider,
74+
new TesterApiHttpClient(firebaseApp),
75+
blockingExecutor);
6776
SignInStorage signInStorage = new SignInStorage(context);
6877
FirebaseAppDistributionLifecycleNotifier lifecycleNotifier =
6978
FirebaseAppDistributionLifecycleNotifier.getInstance();
@@ -74,8 +83,8 @@ private FirebaseAppDistribution buildFirebaseAppDistribution(ComponentContainer
7483
new TesterSignInManager(firebaseApp, firebaseInstallationsApiProvider, signInStorage),
7584
new NewReleaseFetcher(
7685
firebaseApp.getApplicationContext(), testerApiClient, releaseIdentifier),
77-
new ApkUpdater(firebaseApp, new ApkInstaller()),
78-
new AabUpdater(),
86+
new ApkUpdater(firebaseApp, new ApkInstaller(), blockingExecutor),
87+
new AabUpdater(blockingExecutor),
7988
signInStorage,
8089
lifecycleNotifier);
8190

@@ -85,11 +94,11 @@ private FirebaseAppDistribution buildFirebaseAppDistribution(ComponentContainer
8594
} else {
8695
LogWrapper.getInstance()
8796
.e(
88-
TAG
89-
+ "Context "
90-
+ context
91-
+ " was not an Application, can't register for lifecycle callbacks. SDK might not"
92-
+ " function correctly.");
97+
TAG,
98+
String.format(
99+
"Context %s was not an Application, can't register for lifecycle callbacks. SDK"
100+
+ " might not function correctly.",
101+
context));
93102
}
94103

95104
return appDistribution;

firebase-appdistribution/src/main/java/com/google/firebase/appdistribution/impl/FirebaseAppDistributionTesterApiClient.java

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
import static com.google.firebase.appdistribution.impl.TaskUtils.runAsyncInTask;
1818

19-
import android.annotation.SuppressLint;
2019
import androidx.annotation.NonNull;
2120
import com.google.android.gms.tasks.Task;
2221
import com.google.android.gms.tasks.Tasks;
@@ -29,7 +28,6 @@
2928
import com.google.firebase.installations.InstallationTokenResult;
3029
import java.io.File;
3130
import java.util.concurrent.Executor;
32-
import java.util.concurrent.Executors;
3331
import org.json.JSONArray;
3432
import org.json.JSONException;
3533
import org.json.JSONObject;
@@ -64,18 +62,17 @@ private interface FidDependentJob<TResult> {
6462
private final FirebaseApp firebaseApp;
6563
private final Provider<FirebaseInstallationsApi> firebaseInstallationsApiProvider;
6664
private final TesterApiHttpClient testerApiHttpClient;
67-
68-
// TODO(b/258264924): Migrate to go/firebase-android-executors
69-
@SuppressLint("ThreadPoolCreation")
70-
private final Executor taskExecutor = Executors.newSingleThreadExecutor();
65+
private final Executor blockingExecutor;
7166

7267
FirebaseAppDistributionTesterApiClient(
7368
@NonNull FirebaseApp firebaseApp,
7469
@NonNull Provider<FirebaseInstallationsApi> firebaseInstallationsApiProvider,
75-
@NonNull TesterApiHttpClient testerApiHttpClient) {
70+
@NonNull TesterApiHttpClient testerApiHttpClient,
71+
@NonNull Executor blockingExecutor) {
7672
this.firebaseApp = firebaseApp;
7773
this.firebaseInstallationsApiProvider = firebaseInstallationsApiProvider;
7874
this.testerApiHttpClient = testerApiHttpClient;
75+
this.blockingExecutor = blockingExecutor;
7976
}
8077

8178
/**
@@ -265,9 +262,9 @@ private <TResult> Task<TResult> runWithFidAndToken(FidDependentJob<TResult> job)
265262
firebaseInstallationsApiProvider.get().getToken(/* forceRefresh= */ false);
266263

267264
return Tasks.whenAllSuccess(installationIdTask, installationAuthTokenTask)
268-
.continueWithTask(taskExecutor, TaskUtils::handleTaskFailure)
265+
.continueWithTask(blockingExecutor, TaskUtils::handleTaskFailure)
269266
.onSuccessTask(
270-
taskExecutor,
267+
blockingExecutor,
271268
resultsList -> {
272269
// Tasks.whenAllSuccess combines task results into a list
273270
if (resultsList.size() != 2) {
@@ -276,7 +273,7 @@ private <TResult> Task<TResult> runWithFidAndToken(FidDependentJob<TResult> job)
276273
}
277274
String fid = (String) resultsList.get(0);
278275
InstallationTokenResult tokenResult = (InstallationTokenResult) resultsList.get(1);
279-
return runAsyncInTask(taskExecutor, () -> job.run(fid, tokenResult.getToken()));
276+
return runAsyncInTask(blockingExecutor, () -> job.run(fid, tokenResult.getToken()));
280277
});
281278
}
282279
}

firebase-appdistribution/src/main/java/com/google/firebase/appdistribution/impl/LogWrapper.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ void e(@NonNull String msg, @NonNull Throwable tr) {
8080
Log.e(LOG_TAG, msg, tr);
8181
}
8282

83+
void e(@NonNull String additionalTag, @NonNull String msg) {
84+
Log.e(LOG_TAG, prependTag(additionalTag, msg));
85+
}
86+
8387
void e(@NonNull String additionalTag, @NonNull String msg, @NonNull Throwable tr) {
8488
Log.e(LOG_TAG, prependTag(additionalTag, msg), tr);
8589
}

firebase-appdistribution/src/test/java/com/google/firebase/appdistribution/impl/FirebaseAppDistributionTesterApiClientTest.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import com.google.firebase.installations.FirebaseInstallationsApi;
3636
import com.google.firebase.installations.InstallationTokenResult;
3737
import java.io.File;
38+
import java.util.concurrent.Executors;
3839
import org.json.JSONException;
3940
import org.json.JSONObject;
4041
import org.junit.Before;
@@ -102,7 +103,10 @@ public void setup() {
102103

103104
firebaseAppDistributionTesterApiClient =
104105
new FirebaseAppDistributionTesterApiClient(
105-
firebaseApp, mockFirebaseInstallationsProvider, mockTesterApiHttpClient);
106+
firebaseApp,
107+
mockFirebaseInstallationsProvider,
108+
mockTesterApiHttpClient,
109+
Executors.newSingleThreadExecutor());
106110
}
107111

108112
@Test

0 commit comments

Comments
 (0)