Fix the infinite loop bug for AndroidFuture.ThenCombine.

The bug was found and fixed in
android.car.util.concurrent.AndroidFuture. The same fix is being
duplicated from commit 9dcaf6862035676b2574e92cb72cba67ff0a879b.

Bug: 218377773

Test: atest com.android.internal.infra.AndroidFutureTest

Change-Id: I1e13d512a449a7330c74ed06f6afd90e3c4f9493
This commit is contained in:
bkchoi
2022-02-09 12:57:58 -08:00
parent d0e75eb2c4
commit 052cba1feb
2 changed files with 40 additions and 1 deletions

View File

@@ -455,7 +455,14 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable
if (mSourceU != null) {
// T done
mResultT = (T) res;
mSourceU.whenComplete(this);
// Subscribe to the second job completion.
mSourceU.whenComplete((r, e) -> {
// Mark the first job completion by setting mSourceU to null, so that next time
// the execution flow goes to the else case below.
mSourceU = null;
accept(r, e);
});
} else {
// U done
try {

View File

@@ -29,6 +29,7 @@ import org.junit.runner.RunWith;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.function.BiFunction;
/**
* Unit test for {@link AndroidFuture}.
@@ -154,4 +155,35 @@ public class AndroidFutureTest {
expectThrows(ExecutionException.class, future1::get);
assertThat(executionException.getCause()).isInstanceOf(UnsupportedOperationException.class);
}
@Test
public void testThenCombine() throws Exception {
String nearFutureString = "near future comes";
AndroidFuture<String> nearFuture = AndroidFuture.supply(() -> nearFutureString);
String farFutureString = " before far future.";
AndroidFuture<String> farFuture = AndroidFuture.supply(() -> farFutureString);
AndroidFuture<String> combinedFuture =
nearFuture.thenCombine(farFuture, ((s1, s2) -> s1 + s2));
assertThat(combinedFuture.get()).isEqualTo(nearFutureString + farFutureString);
}
@Test
public void testThenCombine_functionThrowingException() throws Exception {
String nearFutureString = "near future comes";
AndroidFuture<String> nearFuture = AndroidFuture.supply(() -> nearFutureString);
String farFutureString = " before far future.";
AndroidFuture<String> farFuture = AndroidFuture.supply(() -> farFutureString);
UnsupportedOperationException exception = new UnsupportedOperationException(
"Unsupported operation exception thrown!");
BiFunction<String, String, String> throwingFunction = (s1, s2) -> {
throw exception;
};
AndroidFuture<String> combinedFuture = nearFuture.thenCombine(farFuture, throwingFunction);
ExecutionException thrown = expectThrows(ExecutionException.class,
() -> combinedFuture.get());
assertThat(thrown.getCause()).isSameInstanceAs(exception);
}
}