Use Guava's AbstractFuture to implement GceFuture.
This required adding Guava to the java Android.mk file, but allows
GceFuture to implement the more powerful ListenableFuture type with less
implementation.
AbstractFuture docs:
https://google.github.io/guava/releases/20.0/api/docs/com/google/common/util/concurrent/AbstractFuture.html
Bug: 110903523
Test: Ran cf_x86_64_phone-userdebug locally.
Change-Id: I305646473f3a0710f5315285912f4e106ed272c7
Merged-In: I305646473f3a0710f5315285912f4e106ed272c7
(cherry picked from commit 66032e135ad28a39d680b9ee7c0e2199cc27a1e1)
diff --git a/guest/monitoring/vsoc_service/Android.mk b/guest/monitoring/vsoc_service/Android.mk
index 49816da..635018b 100644
--- a/guest/monitoring/vsoc_service/Android.mk
+++ b/guest/monitoring/vsoc_service/Android.mk
@@ -18,6 +18,7 @@
LOCAL_CERTIFICATE := platform
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, java)
+LOCAL_STATIC_JAVA_LIBRARIES := guava
LOCAL_PACKAGE_NAME := VSoCService
LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_PROGUARD_FLAGS := -include build/core/proguard.flags
diff --git a/guest/monitoring/vsoc_service/java/com/android/google/gce/gceservice/GceFuture.java b/guest/monitoring/vsoc_service/java/com/android/google/gce/gceservice/GceFuture.java
index ea41409..055377d 100644
--- a/guest/monitoring/vsoc_service/java/com/android/google/gce/gceservice/GceFuture.java
+++ b/guest/monitoring/vsoc_service/java/com/android/google/gce/gceservice/GceFuture.java
@@ -22,12 +22,10 @@
import java.util.concurrent.Future;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.TimeUnit;
+import com.google.common.util.concurrent.AbstractFuture;
-public class GceFuture<T> implements Future<T> {
+public class GceFuture<T> extends AbstractFuture<T> {
private static final String LOG_TAG = "GceFuture";
- private boolean mDone = false;
- private Exception mException = null;
- private T mResult = null;
private final String mName;
@@ -41,113 +39,52 @@
}
- public void set(T value) {
- synchronized(this) {
- if (mDone) {
- Exception e = new Exception();
- Log.e(LOG_TAG, mName + ": Multiple return values from a future object.", e);
- return;
- }
-
- mResult = value;
- mDone = true;
- notifyAll();
+ @Override
+ public boolean set(T value) {
+ if (super.set(value)) {
+ return true;
+ } else {
+ Exception e = new Exception();
+ Log.e(LOG_TAG, mName + ": Multiple return values from a future object.", e);
+ return false;
}
}
public void set(Exception e) {
- synchronized(this) {
- if (mDone) {
- Log.w(LOG_TAG, mName + ": Discarding execution exception -- job done.", e);
- return;
- }
-
- Log.w(LOG_TAG, mName + ": Could not complete job: " + e.getMessage(), e);
- mException = e;
- mDone = true;
- notifyAll();
+ if (!super.setException(e)) {
+ Log.w(LOG_TAG, mName + ": Discarding execution exception -- job done.", e);
+ return;
}
+ Log.w(LOG_TAG, mName + ": Could not complete job: " + e.getMessage(), e);
}
@Override
public boolean cancel(boolean canInterrupt) {
+ // TODO(schuffelen): See if this can be deleted, since GceFuture.cancel is never invoked
+ // directly.
// We do not support interrupting jobs on purpose:
// this offers us little benefit (stripping maybe a second or two), at the expense
// of killing something that may cascade, like BroadcastReceiver.
- synchronized(this) {
- if (mDone) return false;
- set(new CancellationException("cancelled"));
- }
-
- return true;
+ return super.setException(new CancellationException("cancelled"));
}
@Override
public boolean isCancelled() {
- synchronized(this) {
- return (mException != null) && (mException instanceof CancellationException);
- }
- }
-
-
- @Override
- public boolean isDone() {
- synchronized(this) {
- return mDone;
- }
- }
-
-
- @Override
- public T get() throws CancellationException, ExecutionException, InterruptedException {
- try {
- return get(-1, TimeUnit.SECONDS);
- } catch (TimeoutException e) {
- // This is a really interesting case to consider.
- // Fatal error to add to the drama.
- Log.wtf(LOG_TAG, mName + ": Unexpected condition: Infinite wait timed out.");
- return null;
- }
- }
-
-
- @Override
- public T get(long timeout, TimeUnit units)
- throws CancellationException, ExecutionException, InterruptedException, TimeoutException {
- waitDone(timeout, units);
-
- if (mException != null) {
- if (mException instanceof CancellationException)
- throw (CancellationException)mException;
- throw new ExecutionException(mException);
- }
-
- return mResult;
- }
-
-
- /** Wait for final result.
- *
- * Result is considered available, when:
- * - provider returned value,
- * - this object was cancelled,
- * - provider threw an exception.
- */
- private void waitDone(long timeout, TimeUnit units)
- throws InterruptedException, TimeoutException {
- while (!mDone) {
- synchronized(this) {
- if (timeout >= 0) {
- this.wait(units.toMillis(timeout));
- if (!mDone) throw new InterruptedException();
- } else {
- this.wait();
- }
+ if (isDone()) {
+ try {
+ get();
+ } catch (ExecutionException ex) {
+ return ex.getCause() instanceof CancellationException;
+ } catch (InterruptedException ex) {
+ return false;
+ } catch (CancellationException ex) {
+ return true;
}
}
+ return false;
}