Skip to content

Commit 02dd166

Browse files
authored
Migrate firebase-inappmessaging SDK to go/firebase-android-executors. (#4440)
Migrate firebase-inappmessaging SDK to go/firebase-android-executors.
1 parent fee7097 commit 02dd166

File tree

12 files changed

+104
-67
lines changed

12 files changed

+104
-67
lines changed

firebase-inappmessaging/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Unreleased
2+
* [changed] Migrate firebase-inappmessaging SDK to use common executor pool.
23

34
# 20.2.0
45
* [fixed] Fixed a bug that prevented marking more than one message as

firebase-inappmessaging/firebase-inappmessaging.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ dependencies {
143143
testImplementation "io.grpc:grpc-testing:$grpcVersion"
144144
testImplementation 'com.google.guava:guava:30.1-android'
145145
testImplementation 'androidx.test:core:1.2.0'
146+
testImplementation project(":integ-testing")
146147

147148
androidTestImplementation project(':integ-testing')
148149
androidTestImplementation 'androidx.test.ext:junit:1.1.1'

firebase-inappmessaging/src/androidTest/java/com/google/firebase/inappmessaging/FirebaseInAppMessagingFlowableTest.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import com.google.firebase.FirebaseApp;
5353
import com.google.firebase.FirebaseOptions;
5454
import com.google.firebase.analytics.connector.AnalyticsConnector;
55+
import com.google.firebase.concurrent.TestOnlyExecutors;
5556
import com.google.firebase.events.Subscriber;
5657
import com.google.firebase.inappmessaging.CommonTypesProto.Event;
5758
import com.google.firebase.inappmessaging.CommonTypesProto.Priority;
@@ -65,6 +66,7 @@
6566
import com.google.firebase.inappmessaging.internal.TestDeviceHelper;
6667
import com.google.firebase.inappmessaging.internal.injection.modules.AppMeasurementModule;
6768
import com.google.firebase.inappmessaging.internal.injection.modules.ApplicationModule;
69+
import com.google.firebase.inappmessaging.internal.injection.modules.ExecutorsModule;
6870
import com.google.firebase.inappmessaging.internal.injection.modules.GrpcClientModule;
6971
import com.google.firebase.inappmessaging.internal.injection.modules.ProgrammaticContextualTriggerFlowableModule;
7072
import com.google.firebase.inappmessaging.model.BannerMessage;
@@ -270,7 +272,9 @@ public void setUp() {
270272
.testSystemClockModule(new TestSystemClockModule(NOW))
271273
.programmaticContextualTriggerFlowableModule(
272274
new ProgrammaticContextualTriggerFlowableModule(
273-
new ProgramaticContextualTriggers()));
275+
new ProgramaticContextualTriggers()))
276+
.executorsModule(
277+
new ExecutorsModule(TestOnlyExecutors.background(), TestOnlyExecutors.blocking()));
274278

275279
TestUniversalComponent universalComponent = universalComponentBuilder.build();
276280

@@ -315,6 +319,8 @@ public void onAppOpen_whenAnalyticsAbsent_notifiesSubscriber() {
315319
TestUniversalComponent analyticsLessUniversalComponent =
316320
universalComponentBuilder
317321
.appMeasurementModule(new AppMeasurementModule(handler -> {}, firebaseEventSubscriber))
322+
.executorsModule(
323+
new ExecutorsModule(TestOnlyExecutors.background(), TestOnlyExecutors.blocking()))
318324
.build();
319325
TestAppComponent appComponent =
320326
appComponentBuilder.universalComponent(analyticsLessUniversalComponent).build();

firebase-inappmessaging/src/androidTest/java/com/google/firebase/inappmessaging/TestUniversalComponent.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import com.google.firebase.inappmessaging.internal.injection.modules.AnalyticsEventsModule;
1919
import com.google.firebase.inappmessaging.internal.injection.modules.AppMeasurementModule;
2020
import com.google.firebase.inappmessaging.internal.injection.modules.ApplicationModule;
21+
import com.google.firebase.inappmessaging.internal.injection.modules.ExecutorsModule;
2122
import com.google.firebase.inappmessaging.internal.injection.modules.ProgrammaticContextualTriggerFlowableModule;
2223
import com.google.firebase.inappmessaging.internal.injection.modules.ProtoStorageClientModule;
2324
import com.google.firebase.inappmessaging.internal.injection.modules.RateLimitModule;
@@ -41,5 +42,6 @@
4142
ProtoStorageClientModule.class,
4243
RateLimitModule.class,
4344
AppMeasurementModule.class,
45+
ExecutorsModule.class,
4446
})
4547
public interface TestUniversalComponent extends UniversalComponent {}

firebase-inappmessaging/src/main/java/com/google/firebase/inappmessaging/FirebaseInAppMessagingRegistrar.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,13 @@
2222
import com.google.firebase.abt.FirebaseABTesting;
2323
import com.google.firebase.abt.component.AbtComponent;
2424
import com.google.firebase.analytics.connector.AnalyticsConnector;
25+
import com.google.firebase.annotations.concurrent.Background;
26+
import com.google.firebase.annotations.concurrent.Blocking;
2527
import com.google.firebase.components.Component;
2628
import com.google.firebase.components.ComponentContainer;
2729
import com.google.firebase.components.ComponentRegistrar;
2830
import com.google.firebase.components.Dependency;
31+
import com.google.firebase.components.Qualified;
2932
import com.google.firebase.events.Subscriber;
3033
import com.google.firebase.inappmessaging.internal.AbtIntegrationHelper;
3134
import com.google.firebase.inappmessaging.internal.ProgramaticContextualTriggers;
@@ -37,13 +40,15 @@
3740
import com.google.firebase.inappmessaging.internal.injection.modules.ApiClientModule;
3841
import com.google.firebase.inappmessaging.internal.injection.modules.AppMeasurementModule;
3942
import com.google.firebase.inappmessaging.internal.injection.modules.ApplicationModule;
43+
import com.google.firebase.inappmessaging.internal.injection.modules.ExecutorsModule;
4044
import com.google.firebase.inappmessaging.internal.injection.modules.GrpcClientModule;
4145
import com.google.firebase.inappmessaging.internal.injection.modules.ProgrammaticContextualTriggerFlowableModule;
4246
import com.google.firebase.inject.Deferred;
4347
import com.google.firebase.installations.FirebaseInstallationsApi;
4448
import com.google.firebase.platforminfo.LibraryVersionComponent;
4549
import java.util.Arrays;
4650
import java.util.List;
51+
import java.util.concurrent.Executor;
4752

4853
/**
4954
* Registers {@link FirebaseInAppMessaging}.
@@ -53,6 +58,10 @@
5358
@Keep
5459
public class FirebaseInAppMessagingRegistrar implements ComponentRegistrar {
5560
private static final String LIBRARY_NAME = "fire-fiam";
61+
private Qualified<Executor> backgroundExecutor =
62+
Qualified.qualified(Background.class, Executor.class);
63+
private Qualified<Executor> blockingExecutor =
64+
Qualified.qualified(Blocking.class, Executor.class);
5665

5766
@Override
5867
@Keep
@@ -67,6 +76,8 @@ public List<Component<?>> getComponents() {
6776
.add(Dependency.deferred(AnalyticsConnector.class))
6877
.add(Dependency.required(TransportFactory.class))
6978
.add(Dependency.required(Subscriber.class))
79+
.add(Dependency.required(backgroundExecutor))
80+
.add(Dependency.required(blockingExecutor))
7081
.factory(this::providesFirebaseInAppMessaging)
7182
.eagerInDefaultApp()
7283
.build(),
@@ -91,6 +102,9 @@ private FirebaseInAppMessaging providesFirebaseInAppMessaging(ComponentContainer
91102
.programmaticContextualTriggerFlowableModule(
92103
new ProgrammaticContextualTriggerFlowableModule(
93104
new ProgramaticContextualTriggers()))
105+
.executorsModule(
106+
new ExecutorsModule(
107+
container.get(backgroundExecutor), container.get(blockingExecutor)))
94108
.build();
95109

96110
AppComponent instance =

firebase-inappmessaging/src/main/java/com/google/firebase/inappmessaging/internal/AbtIntegrationHelper.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,30 +14,26 @@
1414

1515
package com.google.firebase.inappmessaging.internal;
1616

17-
import android.annotation.SuppressLint;
1817
import androidx.annotation.VisibleForTesting;
1918
import com.google.firebase.abt.AbtException;
2019
import com.google.firebase.abt.AbtExperimentInfo;
2120
import com.google.firebase.abt.FirebaseABTesting;
21+
import com.google.firebase.annotations.concurrent.Blocking;
2222
import com.google.firebase.inappmessaging.ExperimentPayloadProto;
2323
import com.google.firebase.inappmessaging.internal.injection.scopes.FirebaseAppScope;
2424
import com.google.internal.firebase.inappmessaging.v1.CampaignProto;
2525
import com.google.internal.firebase.inappmessaging.v1.sdkserving.FetchEligibleCampaignsResponse;
2626
import java.util.ArrayList;
2727
import java.util.Date;
2828
import java.util.concurrent.Executor;
29-
import java.util.concurrent.Executors;
3029
import javax.inject.Inject;
3130

3231
/** @hide */
3332
@FirebaseAppScope
3433
public class AbtIntegrationHelper {
3534
private final FirebaseABTesting abTesting;
3635

37-
// TODO(b/258280977): Migrate to go/firebase-android-executors
38-
@SuppressLint("ThreadPoolCreation")
39-
@VisibleForTesting
40-
Executor executor = Executors.newSingleThreadExecutor();
36+
@Inject @Blocking @VisibleForTesting Executor executor;
4137

4238
@Inject
4339
public AbtIntegrationHelper(FirebaseABTesting abTesting) {

firebase-inappmessaging/src/main/java/com/google/firebase/inappmessaging/internal/DeveloperListenerManager.java

Lines changed: 8 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@
1414

1515
package com.google.firebase.inappmessaging.internal;
1616

17-
import android.annotation.SuppressLint;
18-
import androidx.annotation.NonNull;
17+
import com.google.firebase.annotations.concurrent.Background;
1918
import com.google.firebase.inappmessaging.FirebaseInAppMessagingClickListener;
2019
import com.google.firebase.inappmessaging.FirebaseInAppMessagingDismissListener;
2120
import com.google.firebase.inappmessaging.FirebaseInAppMessagingDisplayCallbacks;
@@ -25,13 +24,7 @@
2524
import com.google.firebase.inappmessaging.model.InAppMessage;
2625
import java.util.HashMap;
2726
import java.util.Map;
28-
import java.util.concurrent.BlockingQueue;
2927
import java.util.concurrent.Executor;
30-
import java.util.concurrent.LinkedBlockingQueue;
31-
import java.util.concurrent.ThreadFactory;
32-
import java.util.concurrent.ThreadPoolExecutor;
33-
import java.util.concurrent.TimeUnit;
34-
import java.util.concurrent.atomic.AtomicInteger;
3528

3629
/**
3730
* A class used to manage and schedule events to registered (ie: developer-defined) or expensive
@@ -42,11 +35,7 @@
4235
@SuppressWarnings("JavaDoc")
4336
public class DeveloperListenerManager {
4437

45-
// We limit to 1 so there is minimial impact to device performance
46-
private static final int POOL_SIZE = 1;
47-
// Keep alive to minimize chance of having to restart a thread to handle both impression and click
48-
private static final int KEEP_ALIVE_TIME_SECONDS = 15;
49-
public static DeveloperListenerManager instance = new DeveloperListenerManager();
38+
private final Executor backgroundExecutor;
5039
private Map<FirebaseInAppMessagingClickListener, ClicksExecutorAndListener>
5140
registeredClickListeners = new HashMap<>();
5241
private Map<FirebaseInAppMessagingDismissListener, DismissExecutorAndListener>
@@ -56,28 +45,15 @@ public class DeveloperListenerManager {
5645
private Map<FirebaseInAppMessagingImpressionListener, ImpressionExecutorAndListener>
5746
registeredImpressionListeners = new HashMap<>();
5847

59-
private static BlockingQueue<Runnable> mCallbackQueue = new LinkedBlockingQueue<>();
60-
61-
// TODO(b/258280977): Migrate to go/firebase-android-executors
62-
@SuppressLint("ThreadPoolCreation")
63-
private static final ThreadPoolExecutor CALLBACK_QUEUE_EXECUTOR =
64-
new ThreadPoolExecutor(
65-
POOL_SIZE,
66-
POOL_SIZE,
67-
KEEP_ALIVE_TIME_SECONDS,
68-
TimeUnit.SECONDS,
69-
mCallbackQueue,
70-
new FIAMThreadFactory("EventListeners-"));
71-
72-
static {
73-
CALLBACK_QUEUE_EXECUTOR.allowCoreThreadTimeOut(true);
48+
public DeveloperListenerManager(@Background Executor backgroundExecutor) {
49+
this.backgroundExecutor = backgroundExecutor;
7450
}
7551

7652
// Used internally by MetricsLoggerClient
7753
public void impressionDetected(InAppMessage inAppMessage) {
7854
for (ImpressionExecutorAndListener listener : registeredImpressionListeners.values()) {
7955
listener
80-
.withExecutor(CALLBACK_QUEUE_EXECUTOR)
56+
.withExecutor(backgroundExecutor)
8157
.execute(() -> listener.getListener().impressionDetected(inAppMessage));
8258
}
8359
}
@@ -87,23 +63,23 @@ public void displayErrorEncountered(
8763
FirebaseInAppMessagingDisplayCallbacks.InAppMessagingErrorReason errorReason) {
8864
for (ErrorsExecutorAndListener listener : registeredErrorListeners.values()) {
8965
listener
90-
.withExecutor(CALLBACK_QUEUE_EXECUTOR)
66+
.withExecutor(backgroundExecutor)
9167
.execute(() -> listener.getListener().displayErrorEncountered(inAppMessage, errorReason));
9268
}
9369
}
9470

9571
public void messageClicked(InAppMessage inAppMessage, Action action) {
9672
for (ClicksExecutorAndListener listener : registeredClickListeners.values()) {
9773
listener
98-
.withExecutor(CALLBACK_QUEUE_EXECUTOR)
74+
.withExecutor(backgroundExecutor)
9975
.execute(() -> listener.getListener().messageClicked(inAppMessage, action));
10076
}
10177
}
10278

10379
public void messageDismissed(InAppMessage inAppMessage) {
10480
for (DismissExecutorAndListener listener : registeredDismissListeners.values()) {
10581
listener
106-
.withExecutor(CALLBACK_QUEUE_EXECUTOR)
82+
.withExecutor(backgroundExecutor)
10783
.execute(() -> listener.getListener().messageDismissed(inAppMessage));
10884
}
10985
}
@@ -175,29 +151,6 @@ public void removeAllListeners() {
175151
registeredErrorListeners.clear();
176152
}
177153

178-
/** The thread factory for Storage threads. */
179-
static class FIAMThreadFactory implements ThreadFactory {
180-
private final AtomicInteger threadNumber = new AtomicInteger(1);
181-
private final String mNameSuffix;
182-
183-
FIAMThreadFactory(@NonNull String suffix) {
184-
mNameSuffix = suffix;
185-
}
186-
187-
@SuppressWarnings("ThreadPriorityCheck")
188-
@Override
189-
// TODO(b/258280977): Migrate to go/firebase-android-executors
190-
@SuppressLint("ThreadPoolCreation")
191-
public Thread newThread(@NonNull Runnable r) {
192-
Thread t = new Thread(r, "FIAM-" + mNameSuffix + threadNumber.getAndIncrement());
193-
t.setDaemon(false);
194-
t.setPriority(
195-
android.os.Process.THREAD_PRIORITY_BACKGROUND
196-
+ android.os.Process.THREAD_PRIORITY_MORE_FAVORABLE);
197-
return t;
198-
}
199-
}
200-
201154
private abstract static class ExecutorAndListener<T> {
202155

203156
private final Executor executor;

firebase-inappmessaging/src/main/java/com/google/firebase/inappmessaging/internal/injection/components/UniversalComponent.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import com.google.firebase.inappmessaging.internal.injection.modules.AnalyticsEventsModule;
2929
import com.google.firebase.inappmessaging.internal.injection.modules.AppMeasurementModule;
3030
import com.google.firebase.inappmessaging.internal.injection.modules.ApplicationModule;
31+
import com.google.firebase.inappmessaging.internal.injection.modules.ExecutorsModule;
3132
import com.google.firebase.inappmessaging.internal.injection.modules.ForegroundFlowableModule;
3233
import com.google.firebase.inappmessaging.internal.injection.modules.GrpcChannelModule;
3334
import com.google.firebase.inappmessaging.internal.injection.modules.ProgrammaticContextualTriggerFlowableModule;
@@ -64,7 +65,8 @@
6465
ProtoStorageClientModule.class,
6566
SystemClockModule.class,
6667
RateLimitModule.class,
67-
AppMeasurementModule.class
68+
AppMeasurementModule.class,
69+
ExecutorsModule.class
6870
})
6971
public interface UniversalComponent {
7072
ProviderInstaller probiderInstaller();

firebase-inappmessaging/src/main/java/com/google/firebase/inappmessaging/internal/injection/modules/ApplicationModule.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
package com.google.firebase.inappmessaging.internal.injection.modules;
1616

1717
import android.app.Application;
18+
import com.google.firebase.annotations.concurrent.Background;
1819
import com.google.firebase.inappmessaging.internal.DeveloperListenerManager;
1920
import dagger.Module;
2021
import dagger.Provides;
22+
import java.util.concurrent.Executor;
2123
import javax.inject.Singleton;
2224

2325
/**
@@ -41,7 +43,8 @@ public Application providesApplication() {
4143

4244
@Provides
4345
@Singleton
44-
public DeveloperListenerManager developerListenerManager() {
45-
return new DeveloperListenerManager();
46+
public DeveloperListenerManager developerListenerManager(
47+
@Background Executor backgroundExecutor) {
48+
return new DeveloperListenerManager(backgroundExecutor);
4649
}
4750
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright 2018 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.firebase.inappmessaging.internal.injection.modules;
16+
17+
import androidx.annotation.NonNull;
18+
import com.google.firebase.annotations.concurrent.Background;
19+
import com.google.firebase.annotations.concurrent.Blocking;
20+
import dagger.Module;
21+
import dagger.Provides;
22+
import java.util.concurrent.Executor;
23+
import javax.inject.Singleton;
24+
25+
/** Provides executors for running tasks. */
26+
@Module
27+
public class ExecutorsModule {
28+
private final Executor backgroundExecutor;
29+
private final Executor blockingExecutor;
30+
31+
public ExecutorsModule(
32+
@NonNull @Background Executor backgroundExecutor,
33+
@NonNull @Blocking Executor blockingExecutor) {
34+
this.backgroundExecutor = backgroundExecutor;
35+
this.blockingExecutor = blockingExecutor;
36+
}
37+
38+
@Provides
39+
@Singleton
40+
@Background
41+
@NonNull
42+
public Executor providesBackgroundExecutor() {
43+
return backgroundExecutor;
44+
}
45+
46+
@Provides
47+
@Singleton
48+
@Blocking
49+
@NonNull
50+
public Executor providesBlockingExecutor() {
51+
return blockingExecutor;
52+
}
53+
}

firebase-inappmessaging/src/test/java/com/google/firebase/inappmessaging/FirebaseInAppMessagingTest.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import com.google.android.gms.tasks.Tasks;
3434
import com.google.firebase.FirebaseApp;
3535
import com.google.firebase.FirebaseOptions;
36+
import com.google.firebase.concurrent.TestOnlyExecutors;
3637
import com.google.firebase.inappmessaging.CommonTypesProto.Event;
3738
import com.google.firebase.inappmessaging.CommonTypesProto.Priority;
3839
import com.google.firebase.inappmessaging.CommonTypesProto.TriggeringCondition;
@@ -149,7 +150,11 @@ public Builder toBuilder() {
149150
@Mock private DisplayCallbacksFactory displayCallbacksFactory;
150151
@Mock private FirebaseInAppMessagingDisplayCallbacks displayCallbacks;
151152
@Mock private ProgramaticContextualTriggers programaticContextualTriggers;
152-
@Mock DeveloperListenerManager developerListenerManager = new DeveloperListenerManager();
153+
154+
@Mock
155+
DeveloperListenerManager developerListenerManager =
156+
new DeveloperListenerManager(TestOnlyExecutors.background());
157+
153158
FirebaseApp firebaseApp1;
154159
FirebaseOptions options;
155160

0 commit comments

Comments
 (0)