Skip to content

Commit 0c974a9

Browse files
committed
fix: Remove possible deadlock with nested callAsync()
1 parent d812307 commit 0c974a9

File tree

1 file changed

+23
-21
lines changed

1 file changed

+23
-21
lines changed

src/main/java/com/google/firebase/messaging/FirebaseMessaging.java

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import com.google.common.base.Supplier;
2727
import com.google.common.base.Suppliers;
2828
import com.google.common.collect.ImmutableList;
29+
import com.google.common.util.concurrent.MoreExecutors;
2930
import com.google.firebase.ErrorCode;
3031
import com.google.firebase.FirebaseApp;
3132
import com.google.firebase.ImplFirebaseTrampolines;
@@ -159,7 +160,7 @@ protected String execute() throws FirebaseMessagingException {
159160
* no failures are only indicated by a {@link BatchResponse}.
160161
*/
161162
public BatchResponse sendEach(@NonNull List<Message> messages) throws FirebaseMessagingException {
162-
return sendEachOp(messages, false).call();
163+
return sendEach(messages, false);
163164
}
164165

165166

@@ -186,7 +187,11 @@ public BatchResponse sendEach(@NonNull List<Message> messages) throws FirebaseMe
186187
*/
187188
public BatchResponse sendEach(
188189
@NonNull List<Message> messages, boolean dryRun) throws FirebaseMessagingException {
189-
return sendEachOp(messages, dryRun).call();
190+
try {
191+
return sendEachOpAsync(messages, dryRun).get();
192+
} catch (InterruptedException | ExecutionException e) {
193+
throw new FirebaseMessagingException(ErrorCode.CANCELLED, SERVICE_ID);
194+
}
190195
}
191196

192197
/**
@@ -197,7 +202,7 @@ public BatchResponse sendEach(
197202
* the messages have been sent.
198203
*/
199204
public ApiFuture<BatchResponse> sendEachAsync(@NonNull List<Message> messages) {
200-
return sendEachOp(messages, false).callAsync(app);
205+
return sendEachOpAsync(messages, false);
201206
}
202207

203208
/**
@@ -209,32 +214,29 @@ public ApiFuture<BatchResponse> sendEachAsync(@NonNull List<Message> messages) {
209214
* the messages have been sent.
210215
*/
211216
public ApiFuture<BatchResponse> sendEachAsync(@NonNull List<Message> messages, boolean dryRun) {
212-
return sendEachOp(messages, dryRun).callAsync(app);
217+
return sendEachOpAsync(messages, dryRun);
213218
}
214219

215-
private CallableOperation<BatchResponse, FirebaseMessagingException> sendEachOp(
220+
private ApiFuture<BatchResponse> sendEachOpAsync(
216221
final List<Message> messages, final boolean dryRun) {
217222
final List<Message> immutableMessages = ImmutableList.copyOf(messages);
218223
checkArgument(!immutableMessages.isEmpty(), "messages list must not be empty");
219224
checkArgument(immutableMessages.size() <= 500,
220225
"messages list must not contain more than 500 elements");
221226

222-
return new CallableOperation<BatchResponse, FirebaseMessagingException>() {
223-
@Override
224-
protected BatchResponse execute() throws FirebaseMessagingException {
225-
List<ApiFuture<SendResponse>> list = new ArrayList<>();
226-
for (Message message : immutableMessages) {
227-
ApiFuture<SendResponse> messageId = sendOpForSendResponse(message, dryRun).callAsync(app);
228-
list.add(messageId);
229-
}
230-
try {
231-
List<SendResponse> responses = ApiFutures.allAsList(list).get();
232-
return new BatchResponseImpl(responses);
233-
} catch (InterruptedException | ExecutionException e) {
234-
throw new FirebaseMessagingException(ErrorCode.CANCELLED, SERVICE_ID);
235-
}
236-
}
237-
};
227+
List<ApiFuture<SendResponse>> list = new ArrayList<>();
228+
for (Message message : immutableMessages) {
229+
ApiFuture<SendResponse> messageId = sendOpForSendResponse(message, dryRun).callAsync(app);
230+
list.add(messageId);
231+
}
232+
233+
ApiFuture<List<SendResponse>> responsesFuture = ApiFutures.allAsList(list);
234+
return ApiFutures.transform(
235+
responsesFuture,
236+
(responses) -> {
237+
return new BatchResponseImpl(responses);
238+
},
239+
MoreExecutors.directExecutor());
238240
}
239241

240242
private CallableOperation<SendResponse, FirebaseMessagingException> sendOpForSendResponse(

0 commit comments

Comments
 (0)