Skip to content

Commit c35626a

Browse files
Don't deadlock during shutdown() (#3374)
1 parent d131c6e commit c35626a

File tree

3 files changed

+12
-18
lines changed

3 files changed

+12
-18
lines changed

firebase-firestore/CHANGELOG.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ by opting into a release at
44

55
# 24.0.2
66
- [fixed] Fixed an AppCheck issue that caused Firestore listeners to stop
7-
working and receive a "Permission Denied" error. This issue only occurred for
8-
AppCheck users that set their expiration time to under an hour.
7+
working and receive a "Permission Denied" error. This issue only occurred for
8+
AppCheck users that set their expiration time to under an hour.
9+
- [fixed] Fixed a potential problem during Firestore's shutdown that prevented
10+
the shutdown from proceeding if a network connection was opened right before.
911

1012
# 24.0.1
1113
- [changed] Improved performance for databases that contain many document

firebase-firestore/src/main/java/com/google/firebase/firestore/remote/FirestoreCallCredentials.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.google.firebase.FirebaseApiNotAvailableException;
2020
import com.google.firebase.firestore.auth.CredentialsProvider;
2121
import com.google.firebase.firestore.auth.User;
22+
import com.google.firebase.firestore.util.Executors;
2223
import com.google.firebase.firestore.util.Logger;
2324
import com.google.firebase.internal.api.FirebaseNoSignedInUserException;
2425
import io.grpc.CallCredentials;
@@ -58,7 +59,12 @@ public void applyRequestMetadata(
5859

5960
Tasks.whenAll(authTask, appCheckTask)
6061
.addOnCompleteListener(
61-
executor,
62+
// We previously used the executor that is passed to us by the callee of the method
63+
// (which happens to be the AsyncQueue). This sometimes led to deadlocks during
64+
// shutdown, as Firestore's termiante() runs on the AsyncQueue, which would then invoke
65+
// GRPC's shutdown(), which would then wait for this callback to be scheduled on the
66+
// AsyncQueue.
67+
Executors.DIRECT_EXECUTOR,
6268
unused -> {
6369
Metadata metadata = new Metadata();
6470

firebase-firestore/src/main/java/com/google/firebase/firestore/remote/GrpcCallProvider.java

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
package com.google.firebase.firestore.remote;
1616

1717
import android.content.Context;
18-
import androidx.annotation.VisibleForTesting;
1918
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
2019
import com.google.android.gms.common.GooglePlayServicesRepairableException;
2120
import com.google.android.gms.security.ProviderInstaller;
@@ -64,19 +63,6 @@ public class GrpcCallProvider {
6463
private final DatabaseInfo databaseInfo;
6564
private final CallCredentials firestoreHeaders;
6665

67-
/**
68-
* Helper function to globally override the channel that RPCs use. Useful for testing when you
69-
* want to bypass SSL certificate checking.
70-
*
71-
* @param channelBuilderSupplier The supplier for a channel builder that is used to create gRPC
72-
* channels.
73-
*/
74-
@VisibleForTesting
75-
public static void overrideChannelBuilder(
76-
Supplier<ManagedChannelBuilder<?>> channelBuilderSupplier) {
77-
overrideChannelBuilderSupplier = channelBuilderSupplier;
78-
}
79-
8066
GrpcCallProvider(
8167
AsyncQueue asyncQueue,
8268
Context context,
@@ -142,7 +128,7 @@ <ReqT, RespT> Task<ClientCall<ReqT, RespT>> createClientCall(
142128
void shutdown() {
143129
// Handling shutdown synchronously to avoid re-enqueuing on the AsyncQueue after shutdown has
144130
// started.
145-
ManagedChannel channel = null;
131+
ManagedChannel channel;
146132
try {
147133
channel = Tasks.await(channelTask);
148134
} catch (ExecutionException e) {

0 commit comments

Comments
 (0)