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