• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.car.util.concurrent;
18 
19 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
20 
21 import android.annotation.CallSuper;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.car.annotation.AddedInOrBefore;
25 import android.os.Handler;
26 import android.os.Looper;
27 import android.os.Parcel;
28 import android.os.Parcelable;
29 import android.os.RemoteException;
30 import android.util.Log;
31 
32 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
33 import com.android.internal.annotations.GuardedBy;
34 import com.android.internal.util.Preconditions;
35 
36 import java.lang.reflect.Constructor;
37 import java.util.concurrent.CancellationException;
38 import java.util.concurrent.CompletableFuture;
39 import java.util.concurrent.CompletionStage;
40 import java.util.concurrent.ExecutionException;
41 import java.util.concurrent.Executor;
42 import java.util.concurrent.TimeUnit;
43 import java.util.concurrent.TimeoutException;
44 import java.util.function.BiConsumer;
45 import java.util.function.BiFunction;
46 import java.util.function.Function;
47 import java.util.function.Supplier;
48 
49 /**
50  * code copied from {@code com.android.internal.infra.AndroidFuture}
51  *
52  * @param <T> see {@link CompletableFuture}
53  *
54  * @hide
55  */
56 public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable {
57 
58     private static final boolean DEBUG = false;
59     private static final String LOG_TAG = AndroidFuture.class.getSimpleName();
60     private static final Executor DIRECT_EXECUTOR = Runnable::run;
61     private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0];
62     private static @Nullable Handler sMainHandler;
63 
64     private final @NonNull Object mLock = new Object();
65     @GuardedBy("mLock")
66     private @Nullable BiConsumer<? super T, ? super Throwable> mListener;
67     @GuardedBy("mLock")
68     private @Nullable Executor mListenerExecutor = DIRECT_EXECUTOR;
69     private @NonNull Handler mTimeoutHandler = getMainHandler();
70     private final @Nullable IAndroidFuture mRemoteOrigin;
71 
AndroidFuture()72     public AndroidFuture() {
73         super();
74         mRemoteOrigin = null;
75     }
76 
AndroidFuture(Parcel in)77     AndroidFuture(Parcel in) {
78         super();
79         if (in.readBoolean()) {
80             // Done
81             if (in.readBoolean()) {
82                 // Failed
83                 completeExceptionally(readThrowable(in));
84             } else {
85                 // Success
86                 complete((T) in.readValue(null));
87             }
88             mRemoteOrigin = null;
89         } else {
90             // Not done
91             mRemoteOrigin = IAndroidFuture.Stub.asInterface(in.readStrongBinder());
92         }
93     }
94 
95     @NonNull
getMainHandler()96     private static Handler getMainHandler() {
97         // This isn't thread-safe but we are okay with it.
98         if (sMainHandler == null) {
99             sMainHandler = new Handler(Looper.getMainLooper());
100         }
101         return sMainHandler;
102     }
103 
104     /**
105      * Create a completed future with the given value.
106      *
107      * @param value the value for the completed future
108      * @param <U> the type of the value
109      * @return the completed future
110      */
111     @NonNull
112     @AddedInOrBefore(majorVersion = 33)
completedFuture(U value)113     public static <U> AndroidFuture<U> completedFuture(U value) {
114         AndroidFuture<U> future = new AndroidFuture<>();
115         future.complete(value);
116         return future;
117     }
118 
119     @Override
120     @AddedInOrBefore(majorVersion = 33)
complete(@ullable T value)121     public boolean complete(@Nullable T value) {
122         boolean changed = super.complete(value);
123         if (changed) {
124             onCompleted(value, null);
125         }
126         return changed;
127     }
128 
129     @Override
130     @AddedInOrBefore(majorVersion = 33)
completeExceptionally(@onNull Throwable ex)131     public boolean completeExceptionally(@NonNull Throwable ex) {
132         boolean changed = super.completeExceptionally(ex);
133         if (changed) {
134             onCompleted(null, ex);
135         }
136         return changed;
137     }
138 
139     @Override
140     @AddedInOrBefore(majorVersion = 33)
cancel(boolean mayInterruptIfRunning)141     public boolean cancel(boolean mayInterruptIfRunning) {
142         boolean changed = super.cancel(mayInterruptIfRunning);
143         if (changed) {
144             try {
145                 get();
146                 throw new IllegalStateException("Expected CancellationException");
147             } catch (CancellationException ex) {
148                 onCompleted(null, ex);
149             } catch (Throwable e) {
150                 throw new IllegalStateException("Expected CancellationException", e);
151             }
152         }
153         return changed;
154     }
155 
156     @CallSuper
157     @AddedInOrBefore(majorVersion = 33)
onCompleted(@ullable T res, @Nullable Throwable err)158     protected void onCompleted(@Nullable T res, @Nullable Throwable err) {
159         cancelTimeout();
160 
161         if (DEBUG) {
162             Log.i(LOG_TAG, this + " completed with result " + (err == null ? res : err),
163                     new RuntimeException());
164         }
165 
166         BiConsumer<? super T, ? super Throwable> listener;
167         synchronized (mLock) {
168             listener = mListener;
169             mListener = null;
170         }
171 
172         if (listener != null) {
173             callListenerAsync(listener, res, err);
174         }
175 
176         if (mRemoteOrigin != null) {
177             try {
178                 mRemoteOrigin.complete(this /* resultContainer */);
179             } catch (RemoteException e) {
180                 Log.e(LOG_TAG, "Failed to propagate completion", e);
181             }
182         }
183     }
184 
185     @Override
186     @AddedInOrBefore(majorVersion = 33)
whenComplete(@onNull BiConsumer<? super T, ? super Throwable> action)187     public AndroidFuture<T> whenComplete(@NonNull BiConsumer<? super T, ? super Throwable> action) {
188         return whenCompleteAsync(action, DIRECT_EXECUTOR);
189     }
190 
191     @Override
192     @AddedInOrBefore(majorVersion = 33)
whenCompleteAsync( @onNull BiConsumer<? super T, ? super Throwable> action, @NonNull Executor executor)193     public AndroidFuture<T> whenCompleteAsync(
194             @NonNull BiConsumer<? super T, ? super Throwable> action,
195             @NonNull Executor executor) {
196         Preconditions.checkNotNull(action);
197         Preconditions.checkNotNull(executor);
198         synchronized (mLock) {
199             if (!isDone()) {
200                 BiConsumer<? super T, ? super Throwable> oldListener = mListener;
201 
202                 if (oldListener != null && executor != mListenerExecutor) {
203                     // 2 listeners with different executors
204                     // Too complex - give up on saving allocations and delegate to superclass
205                     super.whenCompleteAsync(action, executor);
206                     return this;
207                 }
208 
209                 mListenerExecutor = executor;
210                 mListener = oldListener == null
211                         ? action
212                         : (res, err) -> {
213                             callListener(oldListener, res, err);
214                             callListener(action, res, err);
215                         };
216                 return this;
217             }
218         }
219 
220         // isDone() == true at this point
221         T res = null;
222         Throwable err = null;
223         try {
224             res = get();
225         } catch (ExecutionException e) {
226             err = e.getCause();
227         } catch (Throwable e) {
228             err = e;
229         }
230         callListenerAsync(action, res, err);
231         return this;
232     }
233 
callListenerAsync(BiConsumer<? super T, ? super Throwable> listener, @Nullable T res, @Nullable Throwable err)234     private void callListenerAsync(BiConsumer<? super T, ? super Throwable> listener,
235             @Nullable T res, @Nullable Throwable err) {
236         if (mListenerExecutor == DIRECT_EXECUTOR) {
237             callListener(listener, res, err);
238         } else {
239             mListenerExecutor.execute(() -> callListener(listener, res, err));
240         }
241     }
242 
243     /**
244      * Calls the provided listener, handling any exceptions that may arise.
245      */
246     // package-private to avoid synthetic method when called from lambda
247     @AddedInOrBefore(majorVersion = 33)
callListener( @onNull BiConsumer<? super TT, ? super Throwable> listener, @Nullable TT res, @Nullable Throwable err)248     static <TT> void callListener(
249             @NonNull BiConsumer<? super TT, ? super Throwable> listener,
250             @Nullable TT res, @Nullable Throwable err) {
251         try {
252             try {
253                 listener.accept(res, err);
254             } catch (Throwable t) {
255                 if (err == null) {
256                     // listener happy-case threw, but exception case might not throw, so report the
257                     // same exception thrown by listener's happy-path to it again
258                     listener.accept(null, t);
259                 } else {
260                     // listener exception-case threw
261                     // give up on listener but preserve the original exception when throwing up
262                     t.addSuppressed(err);
263                     throw t;
264                 }
265             }
266         } catch (Throwable t2) {
267             // give up on listener and log the result & exception to logcat
268             Log.e(LOG_TAG, "Failed to call whenComplete listener. res = " + res, t2);
269         }
270     }
271 
272     /** @inheritDoc */
273     //@Override //TODO uncomment once java 9 APIs are exposed to frameworks
274     @AddedInOrBefore(majorVersion = 33)
orTimeout(long timeout, @NonNull TimeUnit unit)275     public AndroidFuture<T> orTimeout(long timeout, @NonNull TimeUnit unit) {
276         mTimeoutHandler.postDelayed(this::triggerTimeout, this, unit.toMillis(timeout));
277         return this;
278     }
279 
280     @AddedInOrBefore(majorVersion = 33)
triggerTimeout()281     void triggerTimeout() {
282         cancelTimeout();
283         if (!isDone()) {
284             completeExceptionally(new TimeoutException());
285         }
286     }
287 
288     /**
289      * Cancel all timeouts previously set with {@link #orTimeout}, if any.
290      *
291      * @return {@code this} for chaining
292      */
293     @AddedInOrBefore(majorVersion = 33)
cancelTimeout()294     public AndroidFuture<T> cancelTimeout() {
295         mTimeoutHandler.removeCallbacksAndMessages(this);
296         return this;
297     }
298 
299     /**
300      * Specifies the handler on which timeout is to be triggered
301      */
302     @AddedInOrBefore(majorVersion = 33)
setTimeoutHandler(@onNull Handler h)303     public AndroidFuture<T> setTimeoutHandler(@NonNull Handler h) {
304         cancelTimeout();
305         mTimeoutHandler = Preconditions.checkNotNull(h);
306         return this;
307     }
308 
309     @Override
310     @AddedInOrBefore(majorVersion = 33)
thenCompose( @onNull Function<? super T, ? extends CompletionStage<U>> fn)311     public <U> AndroidFuture<U> thenCompose(
312             @NonNull Function<? super T, ? extends CompletionStage<U>> fn) {
313         return thenComposeAsync(fn, DIRECT_EXECUTOR);
314     }
315 
316     @Override
317     @AddedInOrBefore(majorVersion = 33)
thenComposeAsync( @onNull Function<? super T, ? extends CompletionStage<U>> fn, @NonNull Executor executor)318     public <U> AndroidFuture<U> thenComposeAsync(
319             @NonNull Function<? super T, ? extends CompletionStage<U>> fn,
320             @NonNull Executor executor) {
321         return new ThenComposeAsync<>(this, fn, executor);
322     }
323 
324     private static class ThenComposeAsync<T, U> extends AndroidFuture<U>
325             implements BiConsumer<Object, Throwable>, Runnable {
326         private volatile T mSourceResult = null;
327         private final Executor mExecutor;
328         private volatile Function<? super T, ? extends CompletionStage<U>> mFn;
329 
ThenComposeAsync(@onNull AndroidFuture<T> source, @NonNull Function<? super T, ? extends CompletionStage<U>> fn, @NonNull Executor executor)330         ThenComposeAsync(@NonNull AndroidFuture<T> source,
331                 @NonNull Function<? super T, ? extends CompletionStage<U>> fn,
332                 @NonNull Executor executor) {
333             mFn = Preconditions.checkNotNull(fn);
334             mExecutor = Preconditions.checkNotNull(executor);
335 
336             // subscribe to first job completion
337             source.whenComplete(this);
338         }
339 
340         @Override
accept(Object res, Throwable err)341         public void accept(Object res, Throwable err) {
342             if (err != null) {
343                 // first or second job failed
344                 completeExceptionally(err);
345             } else if (mFn != null) {
346                 // first job completed
347                 mSourceResult = (T) res;
348                 // subscribe to second job completion asynchronously
349                 mExecutor.execute(this);
350             } else {
351                 // second job completed
352                 complete((U) res);
353             }
354         }
355 
356         @Override
run()357         public void run() {
358             CompletionStage<U> secondJob;
359             try {
360                 secondJob = Preconditions.checkNotNull(mFn.apply(mSourceResult));
361             } catch (Throwable t) {
362                 completeExceptionally(t);
363                 return;
364             } finally {
365                 // Marks first job complete
366                 mFn = null;
367             }
368             // subscribe to second job completion
369             secondJob.whenComplete(this);
370         }
371     }
372 
373     @Override
374     @AddedInOrBefore(majorVersion = 33)
thenApply(@onNull Function<? super T, ? extends U> fn)375     public <U> AndroidFuture<U> thenApply(@NonNull Function<? super T, ? extends U> fn) {
376         return thenApplyAsync(fn, DIRECT_EXECUTOR);
377     }
378 
379     @Override
380     @AddedInOrBefore(majorVersion = 33)
thenApplyAsync(@onNull Function<? super T, ? extends U> fn, @NonNull Executor executor)381     public <U> AndroidFuture<U> thenApplyAsync(@NonNull Function<? super T, ? extends U> fn,
382             @NonNull Executor executor) {
383         return new ThenApplyAsync<>(this, fn, executor);
384     }
385 
386     private static class ThenApplyAsync<T, U> extends AndroidFuture<U>
387             implements BiConsumer<T, Throwable>, Runnable {
388         private volatile T mSourceResult = null;
389         private final Executor mExecutor;
390         private final Function<? super T, ? extends U> mFn;
391 
ThenApplyAsync(@onNull AndroidFuture<T> source, @NonNull Function<? super T, ? extends U> fn, @NonNull Executor executor)392         ThenApplyAsync(@NonNull AndroidFuture<T> source,
393                 @NonNull Function<? super T, ? extends U> fn,
394                 @NonNull Executor executor) {
395             mExecutor = Preconditions.checkNotNull(executor);
396             mFn = Preconditions.checkNotNull(fn);
397 
398             // subscribe to job completion
399             source.whenComplete(this);
400         }
401 
402         @Override
accept(T res, Throwable err)403         public void accept(T res, Throwable err) {
404             if (err != null) {
405                 completeExceptionally(err);
406             } else {
407                 mSourceResult = res;
408                 mExecutor.execute(this);
409             }
410         }
411 
412         @Override
run()413         public void run() {
414             try {
415                 complete(mFn.apply(mSourceResult));
416             } catch (Throwable t) {
417                 completeExceptionally(t);
418             }
419         }
420     }
421 
422     @Override
423     @AddedInOrBefore(majorVersion = 33)
thenCombine( @onNull CompletionStage<? extends U> other, @NonNull BiFunction<? super T, ? super U, ? extends V> combineResults)424     public <U, V> AndroidFuture<V> thenCombine(
425             @NonNull CompletionStage<? extends U> other,
426             @NonNull BiFunction<? super T, ? super U, ? extends V> combineResults) {
427         return new ThenCombine<T, U, V>(this, other, combineResults);
428     }
429 
430     /** @see CompletionStage#thenCombine */
431     @AddedInOrBefore(majorVersion = 33)
thenCombine(@onNull CompletionStage<Void> other)432     public AndroidFuture<T> thenCombine(@NonNull CompletionStage<Void> other) {
433         return thenCombine(other, (res, aVoid) -> res);
434     }
435 
436     private static class ThenCombine<T, U, V> extends AndroidFuture<V>
437             implements BiConsumer<Object, Throwable> {
438         private volatile @Nullable T mResultT = null;
439         private volatile @NonNull CompletionStage<? extends U> mSourceU;
440         private final @NonNull BiFunction<? super T, ? super U, ? extends V> mCombineResults;
441 
ThenCombine(CompletableFuture<T> sourceT, CompletionStage<? extends U> sourceU, BiFunction<? super T, ? super U, ? extends V> combineResults)442         ThenCombine(CompletableFuture<T> sourceT,
443                 CompletionStage<? extends U> sourceU,
444                 BiFunction<? super T, ? super U, ? extends V> combineResults) {
445             mSourceU = Preconditions.checkNotNull(sourceU);
446             mCombineResults = Preconditions.checkNotNull(combineResults);
447 
448             sourceT.whenComplete(this);
449         }
450 
451         @Override
accept(Object res, Throwable err)452         public void accept(Object res, Throwable err) {
453             if (err != null) {
454                 completeExceptionally(err);
455                 return;
456             }
457 
458             if (mSourceU != null) {
459                 // T done
460                 mResultT = (T) res;
461 
462                 // Subscribe to the second job completion.
463                 mSourceU.whenComplete((r, e) -> {
464                     // Mark the first job completion by setting mSourceU to null, so that next time
465                     // the execution flow goes to the else case below.
466                     mSourceU = null;
467                     accept(r, e);
468                 });
469             } else {
470                 // U done
471                 try {
472                     complete(mCombineResults.apply(mResultT, (U) res));
473                 } catch (Throwable t) {
474                     completeExceptionally(t);
475                 }
476             }
477         }
478     }
479 
480     /**
481      * Similar to {@link CompletableFuture#supplyAsync} but
482      * runs the given action directly.
483      *
484      * The resulting future is immediately completed.
485      */
486     @AddedInOrBefore(majorVersion = 33)
supply(Supplier<T> supplier)487     public static <T> AndroidFuture<T> supply(Supplier<T> supplier) {
488         return supplyAsync(supplier, DIRECT_EXECUTOR);
489     }
490 
491     /**
492      * @see CompletableFuture#supplyAsync(Supplier, Executor)
493      */
494     @AddedInOrBefore(majorVersion = 33)
supplyAsync(Supplier<T> supplier, Executor executor)495     public static <T> AndroidFuture<T> supplyAsync(Supplier<T> supplier, Executor executor) {
496         return new SupplyAsync<>(supplier, executor);
497     }
498 
499     private static class SupplyAsync<T> extends AndroidFuture<T> implements Runnable {
500         private final @NonNull Supplier<T> mSupplier;
501 
SupplyAsync(Supplier<T> supplier, Executor executor)502         SupplyAsync(Supplier<T> supplier, Executor executor) {
503             mSupplier = supplier;
504             executor.execute(this);
505         }
506 
507         @Override
run()508         public void run() {
509             try {
510                 complete(mSupplier.get());
511             } catch (Throwable t) {
512                 completeExceptionally(t);
513             }
514         }
515     }
516 
517     @Override
518     @AddedInOrBefore(majorVersion = 33)
writeToParcel(Parcel dest, int flags)519     public void writeToParcel(Parcel dest, int flags) {
520         boolean done = isDone();
521         dest.writeBoolean(done);
522         if (done) {
523             T result;
524             try {
525                 result = get();
526             } catch (Throwable t) {
527                 dest.writeBoolean(true);
528                 writeThrowable(dest, unwrapExecutionException(t));
529                 return;
530             }
531             dest.writeBoolean(false);
532             dest.writeValue(result);
533         } else {
534             dest.writeStrongBinder(new IAndroidFuture.Stub() {
535                 @Override
536                 public void complete(AndroidFuture resultContainer) {
537                     boolean changed;
538                     try {
539                         changed = AndroidFuture.this.complete((T) resultContainer.get());
540                     } catch (Throwable t) {
541                         changed = completeExceptionally(unwrapExecutionException(t));
542                     }
543                     if (!changed) {
544                         Log.w(LOG_TAG, "Remote result " + resultContainer
545                                 + " ignored, as local future is already completed: "
546                                 + AndroidFuture.this);
547                     }
548                 }
549             }.asBinder());
550         }
551     }
552 
553     /**
554      * Exceptions coming out of {@link #get} are wrapped in {@link ExecutionException}
555      */
556     @AddedInOrBefore(majorVersion = 33)
unwrapExecutionException(Throwable t)557     Throwable unwrapExecutionException(Throwable t) {
558         return t instanceof ExecutionException
559                 ? t.getCause()
560                 : t;
561     }
562 
563     /**
564      * Alternative to {@link Parcel#writeException} that stores the stack trace, in a
565      * way consistent with the binder IPC exception propagation behavior.
566      */
writeThrowable(@onNull Parcel parcel, @Nullable Throwable throwable)567     private static void writeThrowable(@NonNull Parcel parcel, @Nullable Throwable throwable) {
568         boolean hasThrowable = throwable != null;
569         parcel.writeBoolean(hasThrowable);
570         if (!hasThrowable) {
571             return;
572         }
573 
574         boolean isFrameworkParcelable = throwable instanceof Parcelable
575                 && throwable.getClass().getClassLoader() == Parcelable.class.getClassLoader();
576         parcel.writeBoolean(isFrameworkParcelable);
577         if (isFrameworkParcelable) {
578             parcel.writeParcelable((Parcelable) throwable,
579                     Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
580             return;
581         }
582 
583         parcel.writeString(throwable.getClass().getName());
584         parcel.writeString(throwable.getMessage());
585         StackTraceElement[] stackTrace = throwable.getStackTrace();
586         StringBuilder stackTraceBuilder = new StringBuilder();
587         int truncatedStackTraceLength = Math.min(stackTrace != null ? stackTrace.length : 0, 5);
588         for (int i = 0; i < truncatedStackTraceLength; i++) {
589             if (i > 0) {
590                 stackTraceBuilder.append('\n');
591             }
592             stackTraceBuilder.append("\tat ").append(stackTrace[i]);
593         }
594         parcel.writeString(stackTraceBuilder.toString());
595         writeThrowable(parcel, throwable.getCause());
596     }
597 
598     /**
599      * @see #writeThrowable
600      */
readThrowable(@onNull Parcel parcel)601     private static @Nullable Throwable readThrowable(@NonNull Parcel parcel) {
602         final boolean hasThrowable = parcel.readBoolean();
603         if (!hasThrowable) {
604             return null;
605         }
606 
607         boolean isFrameworkParcelable = parcel.readBoolean();
608         if (isFrameworkParcelable) {
609             return parcel.readParcelable(Parcelable.class.getClassLoader());
610         }
611 
612         String className = parcel.readString();
613         String message = parcel.readString();
614         String stackTrace = parcel.readString();
615         String messageWithStackTrace = message + '\n' + stackTrace;
616         Throwable throwable;
617         try {
618             Class<?> clazz = Class.forName(className, true, Parcelable.class.getClassLoader());
619             if (Throwable.class.isAssignableFrom(clazz)) {
620                 Constructor<?> constructor = clazz.getConstructor(String.class);
621                 throwable = (Throwable) constructor.newInstance(messageWithStackTrace);
622             } else {
623                 android.util.EventLog.writeEvent(0x534e4554, "186530450", -1, "");
624                 throwable = new RuntimeException(className + ": " + messageWithStackTrace);
625             }
626         } catch (Throwable t) {
627             throwable = new RuntimeException(className + ": " + messageWithStackTrace);
628             throwable.addSuppressed(t);
629         }
630         throwable.setStackTrace(EMPTY_STACK_TRACE);
631         Throwable cause = readThrowable(parcel);
632         if (cause != null) {
633             throwable.initCause(cause);
634         }
635         return throwable;
636     }
637 
638     @Override
639     @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
640     @AddedInOrBefore(majorVersion = 33)
describeContents()641     public int describeContents() {
642         return 0;
643     }
644 
645     @AddedInOrBefore(majorVersion = 33)
646     public static final @NonNull Parcelable.Creator<AndroidFuture> CREATOR =
647             new Parcelable.Creator<AndroidFuture>() {
648                 public AndroidFuture createFromParcel(Parcel parcel) {
649                     return new AndroidFuture(parcel);
650                 }
651 
652                 public AndroidFuture[] newArray(int size) {
653                     return new AndroidFuture[size];
654                 }
655             };
656 }
657