Skip to content

Commit 0c4e05b

Browse files
committed
Register executors as components.
The intent for those is to be used by all Firebase SDKs and forbid creating their own at will.
1 parent 6f05a97 commit 0c4e05b

22 files changed

+768
-35
lines changed

firebase-annotations/firebase-annotations.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,7 @@ java {
2929
tasks.withType(JavaCompile) {
3030
options.compilerArgs << "-Werror"
3131
}
32+
33+
dependencies {
34+
implementation 'javax.inject:javax.inject:1'
35+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.google.firebase.annotations.concurrent;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Target;
5+
6+
import javax.inject.Qualifier;
7+
8+
/**
9+
* An executor/coroutine dispatcher for long running tasks including disk IO, heavy CPU
10+
* computations.
11+
*/
12+
@Qualifier
13+
@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
14+
public @interface Background {}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.google.firebase.annotations.concurrent;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Target;
5+
6+
import javax.inject.Qualifier;
7+
8+
/**
9+
* An executor/coroutine dispatcher for tasks that can block for long periods of time, e.g network
10+
* IO.
11+
*/
12+
@Qualifier
13+
@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
14+
public @interface Blocking {}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.google.firebase.annotations.concurrent;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Target;
5+
6+
import javax.inject.Qualifier;
7+
8+
/**
9+
* An executor/coroutine dispatcher for lightweight tasks that never block(on IO or other tasks).
10+
*/
11+
@Qualifier
12+
@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
13+
public @interface Lightweight {}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.google.firebase.annotations.concurrent;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Target;
5+
6+
import javax.inject.Qualifier;
7+
8+
/** An executor/coroutine dispatcher for work that must run on the UI thread. */
9+
@Qualifier
10+
@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
11+
public @interface UiThread {}

firebase-common/firebase-common.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ dependencies {
6666
implementation project(':firebase-components')
6767
implementation 'com.google.android.gms:play-services-basement:18.1.0'
6868
implementation "com.google.android.gms:play-services-tasks:18.0.1"
69+
implementation 'androidx.concurrent:concurrent-futures:1.1.0'
6970

7071
// FirebaseApp references storage, so storage needs to be on classpath when dokka runs.
7172
javadocClasspath project(path: ':firebase-storage')

firebase-common/ktx/ktx.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ android {
3838
dependencies {
3939
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
4040

41+
implementation project(':firebase-annotations')
4142
implementation project(':firebase-common')
4243
implementation project(':firebase-components')
4344
implementation 'androidx.annotation:annotation:1.1.0'

firebase-common/ktx/src/main/kotlin/com/google/firebase/ktx/Firebase.kt

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,18 @@ import android.content.Context
1717
import androidx.annotation.Keep
1818
import com.google.firebase.FirebaseApp
1919
import com.google.firebase.FirebaseOptions
20+
import com.google.firebase.annotations.concurrent.Background
21+
import com.google.firebase.annotations.concurrent.Blocking
22+
import com.google.firebase.annotations.concurrent.Lightweight
23+
import com.google.firebase.annotations.concurrent.UiThread
2024
import com.google.firebase.components.Component
2125
import com.google.firebase.components.ComponentRegistrar
26+
import com.google.firebase.components.Dependency
27+
import com.google.firebase.components.Qualified
2228
import com.google.firebase.platforminfo.LibraryVersionComponent
29+
import kotlinx.coroutines.CoroutineDispatcher
30+
import kotlinx.coroutines.asCoroutineDispatcher
31+
import java.util.concurrent.Executor
2332

2433
/**
2534
* Single access point to all firebase SDKs from Kotlin.
@@ -40,11 +49,11 @@ fun Firebase.initialize(context: Context): FirebaseApp? = FirebaseApp.initialize
4049

4150
/** Initializes and returns a FirebaseApp. */
4251
fun Firebase.initialize(context: Context, options: FirebaseOptions): FirebaseApp =
43-
FirebaseApp.initializeApp(context, options)
52+
FirebaseApp.initializeApp(context, options)
4453

4554
/** Initializes and returns a FirebaseApp. */
4655
fun Firebase.initialize(context: Context, options: FirebaseOptions, name: String): FirebaseApp =
47-
FirebaseApp.initializeApp(context, options, name)
56+
FirebaseApp.initializeApp(context, options, name)
4857

4958
/** Returns options of default FirebaseApp */
5059
val Firebase.options: FirebaseOptions
@@ -57,6 +66,27 @@ internal const val LIBRARY_NAME: String = "fire-core-ktx"
5766
class FirebaseCommonKtxRegistrar : ComponentRegistrar {
5867
override fun getComponents(): List<Component<*>> {
5968
return listOf(
60-
LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME))
69+
LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME),
70+
coroutineDispatcher<Background>(),
71+
coroutineDispatcher<Lightweight>(),
72+
coroutineDispatcher<Blocking>(),
73+
coroutineDispatcher<UiThread>()
74+
)
6175
}
6276
}
77+
78+
private inline fun <reified T : Annotation> coroutineDispatcher(): Component<CoroutineDispatcher> =
79+
Component.builder(
80+
Qualified.qualified(T::class.java, CoroutineDispatcher::class.java)
81+
).add(
82+
Dependency.required(
83+
Qualified.qualified(
84+
T::class.java,
85+
Executor::class.java
86+
)
87+
)
88+
).factory { c ->
89+
c.get(
90+
Qualified.qualified(T::class.java, Executor::class.java)
91+
).asCoroutineDispatcher()
92+
}.build()

firebase-common/src/main/java/com/google/firebase/FirebaseApp.java

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323
import android.content.Intent;
2424
import android.content.IntentFilter;
2525
import android.os.Build;
26-
import android.os.Handler;
27-
import android.os.Looper;
2826
import android.text.TextUtils;
2927
import android.util.Log;
3028
import androidx.annotation.GuardedBy;
@@ -47,6 +45,7 @@
4745
import com.google.firebase.components.ComponentRegistrar;
4846
import com.google.firebase.components.ComponentRuntime;
4947
import com.google.firebase.components.Lazy;
48+
import com.google.firebase.concurrent.ExecutorsRegistrar;
5049
import com.google.firebase.events.Publisher;
5150
import com.google.firebase.heartbeatinfo.DefaultHeartBeatController;
5251
import com.google.firebase.inject.Provider;
@@ -59,7 +58,6 @@
5958
import java.util.List;
6059
import java.util.Map;
6160
import java.util.concurrent.CopyOnWriteArrayList;
62-
import java.util.concurrent.Executor;
6361
import java.util.concurrent.atomic.AtomicBoolean;
6462
import java.util.concurrent.atomic.AtomicReference;
6563

@@ -97,16 +95,10 @@ public class FirebaseApp {
9795

9896
private static final Object LOCK = new Object();
9997

100-
private static final Executor UI_EXECUTOR = new UiExecutor();
101-
10298
/** A map of (name, FirebaseApp) instances. */
10399
@GuardedBy("LOCK")
104100
static final Map<String, FirebaseApp> INSTANCES = new ArrayMap<>();
105101

106-
private static final String FIREBASE_ANDROID = "fire-android";
107-
private static final String FIREBASE_COMMON = "fire-core";
108-
private static final String KOTLIN = "kotlin";
109-
110102
private final Context applicationContext;
111103
private final String name;
112104
private final FirebaseOptions options;
@@ -427,9 +419,10 @@ protected FirebaseApp(Context applicationContext, String name, FirebaseOptions o
427419

428420
FirebaseTrace.pushTrace("Runtime");
429421
componentRuntime =
430-
ComponentRuntime.builder(UI_EXECUTOR)
422+
ComponentRuntime.builder(com.google.firebase.concurrent.UiExecutor.INSTANCE)
431423
.addLazyComponentRegistrars(registrars)
432424
.addComponentRegistrar(new FirebaseCommonRegistrar())
425+
.addComponentRegistrar(new ExecutorsRegistrar())
433426
.addComponent(Component.of(applicationContext, Context.class))
434427
.addComponent(Component.of(this, FirebaseApp.class))
435428
.addComponent(Component.of(options, FirebaseOptions.class))
@@ -712,14 +705,4 @@ public void onBackgroundStateChanged(boolean background) {
712705
}
713706
}
714707
}
715-
716-
private static class UiExecutor implements Executor {
717-
718-
private static final Handler HANDLER = new Handler(Looper.getMainLooper());
719-
720-
@Override
721-
public void execute(@NonNull Runnable command) {
722-
HANDLER.post(command);
723-
}
724-
}
725708
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.google.firebase.concurrent;
2+
3+
import java.util.Locale;
4+
import java.util.concurrent.Executors;
5+
import java.util.concurrent.ThreadFactory;
6+
import java.util.concurrent.atomic.AtomicLong;
7+
8+
class CustomThreadFactory implements ThreadFactory {
9+
private static final ThreadFactory DEFAULT = Executors.defaultThreadFactory();
10+
private final AtomicLong threadCount = new AtomicLong();
11+
private final String namePrefix;
12+
private final int priority;
13+
14+
CustomThreadFactory(String namePrefix, int priority) {
15+
this.namePrefix = namePrefix;
16+
this.priority = priority;
17+
}
18+
19+
@Override
20+
public Thread newThread(Runnable r) {
21+
Thread thread = DEFAULT.newThread(r);
22+
thread.setPriority(priority);
23+
thread.setName(
24+
String.format(Locale.ROOT, "%s Thread #%d", namePrefix, threadCount.getAndIncrement()));
25+
return thread;
26+
}
27+
}

0 commit comments

Comments
 (0)