Loading core/java/com/android/internal/infra/AndroidFuture.java +70 −40 Original line number Diff line number Diff line Loading @@ -16,23 +16,20 @@ package com.android.internal.infra; import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; import android.annotation.CallSuper; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Handler; import android.os.Message; import android.os.Looper; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; import android.util.ExceptionUtils; import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; import com.android.internal.util.function.pooled.PooledLambda; import java.lang.reflect.Constructor; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; Loading Loading @@ -75,14 +72,16 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable private static final boolean DEBUG = false; private static final String LOG_TAG = AndroidFuture.class.getSimpleName(); private static final Executor DIRECT_EXECUTOR = Runnable::run; private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0]; private static @Nullable Handler sMainHandler; private final @NonNull Object mLock = new Object(); @GuardedBy("mLock") private @Nullable BiConsumer<? super T, ? super Throwable> mListener; @GuardedBy("mLock") private @Nullable Executor mListenerExecutor = DIRECT_EXECUTOR; private @NonNull Handler mTimeoutHandler = Handler.getMain(); private @NonNull Handler mTimeoutHandler = getMainHandler(); private final @Nullable IAndroidFuture mRemoteOrigin; public AndroidFuture() { Loading @@ -96,7 +95,7 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable // Done if (in.readBoolean()) { // Failed completeExceptionally(unparcelException(in)); completeExceptionally(readThrowable(in)); } else { // Success complete((T) in.readValue(null)); Loading @@ -108,6 +107,15 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable } } @NonNull private static Handler getMainHandler() { // This isn't thread-safe but we are okay with it. if (sMainHandler == null) { sMainHandler = new Handler(Looper.getMainLooper()); } return sMainHandler; } /** * Create a completed future with the given value. * Loading Loading @@ -236,9 +244,7 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable if (mListenerExecutor == DIRECT_EXECUTOR) { callListener(listener, res, err); } else { mListenerExecutor.execute(PooledLambda .obtainRunnable(AndroidFuture::callListener, listener, res, err) .recycleOnUse()); mListenerExecutor.execute(() -> callListener(listener, res, err)); } } Loading @@ -260,7 +266,8 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable } else { // listener exception-case threw // give up on listener but preserve the original exception when throwing up throw ExceptionUtils.appendCause(t, err); t.addSuppressed(err); throw t; } } } catch (Throwable t2) { Loading @@ -272,9 +279,7 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable /** @inheritDoc */ //@Override //TODO uncomment once java 9 APIs are exposed to frameworks public AndroidFuture<T> orTimeout(long timeout, @NonNull TimeUnit unit) { Message msg = PooledLambda.obtainMessage(AndroidFuture::triggerTimeout, this); msg.obj = this; mTimeoutHandler.sendMessageDelayed(msg, unit.toMillis(timeout)); mTimeoutHandler.postDelayed(this::triggerTimeout, this, unit.toMillis(timeout)); return this; } Loading Loading @@ -507,7 +512,7 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable result = get(); } catch (Throwable t) { dest.writeBoolean(true); parcelException(dest, unwrapExecutionException(t)); writeThrowable(dest, unwrapExecutionException(t)); return; } dest.writeBoolean(false); Loading Loading @@ -545,45 +550,70 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable * Alternative to {@link Parcel#writeException} that stores the stack trace, in a * way consistent with the binder IPC exception propagation behavior. */ private static void parcelException(Parcel p, @Nullable Throwable t) { p.writeBoolean(t == null); if (t == null) { private static void writeThrowable(@NonNull Parcel parcel, @Nullable Throwable throwable) { boolean hasThrowable = throwable != null; parcel.writeBoolean(hasThrowable); if (!hasThrowable) { return; } p.writeInt(Parcel.getExceptionCode(t)); p.writeString(t.getClass().getName()); p.writeString(t.getMessage()); p.writeStackTrace(t); parcelException(p, t.getCause()); boolean isFrameworkParcelable = throwable instanceof Parcelable && throwable.getClass().getClassLoader() == Parcelable.class.getClassLoader(); parcel.writeBoolean(isFrameworkParcelable); if (isFrameworkParcelable) { parcel.writeParcelable((Parcelable) throwable, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); return; } parcel.writeString(throwable.getClass().getName()); parcel.writeString(throwable.getMessage()); StackTraceElement[] stackTrace = throwable.getStackTrace(); StringBuilder stackTraceBuilder = new StringBuilder(); int truncatedStackTraceLength = Math.min(stackTrace != null ? stackTrace.length : 0, 5); for (int i = 0; i < truncatedStackTraceLength; i++) { if (i > 0) { stackTraceBuilder.append('\n'); } stackTraceBuilder.append("\tat ").append(stackTrace[i]); } parcel.writeString(stackTraceBuilder.toString()); writeThrowable(parcel, throwable.getCause()); } /** * @see #parcelException * @see #writeThrowable */ private static @Nullable Throwable unparcelException(Parcel p) { if (p.readBoolean()) { private static @Nullable Throwable readThrowable(@NonNull Parcel parcel) { final boolean hasThrowable = parcel.readBoolean(); if (!hasThrowable) { return null; } int exCode = p.readInt(); String cls = p.readString(); String msg = p.readString(); String stackTrace = p.readInt() > 0 ? p.readString() : "\t<stack trace unavailable>"; msg += "\n" + stackTrace; Exception ex = p.createExceptionOrNull(exCode, msg); if (ex == null) { ex = new RuntimeException(cls + ": " + msg); boolean isFrameworkParcelable = parcel.readBoolean(); if (isFrameworkParcelable) { return parcel.readParcelable(Parcelable.class.getClassLoader()); } ex.setStackTrace(EMPTY_STACK_TRACE); Throwable cause = unparcelException(p); String className = parcel.readString(); String message = parcel.readString(); String stackTrace = parcel.readString(); String messageWithStackTrace = message + '\n' + stackTrace; Throwable throwable; try { Class<?> clazz = Class.forName(className); Constructor<?> constructor = clazz.getConstructor(String.class); throwable = (Throwable) constructor.newInstance(messageWithStackTrace); } catch (Throwable t) { throwable = new RuntimeException(className + ": " + messageWithStackTrace); throwable.addSuppressed(t); } throwable.setStackTrace(EMPTY_STACK_TRACE); Throwable cause = readThrowable(parcel); if (cause != null) { ex.initCause(ex); throwable.initCause(cause); } return ex; return throwable; } @Override Loading core/java/com/android/internal/infra/ServiceConnector.java +10 −18 Original line number Diff line number Diff line Loading @@ -26,14 +26,11 @@ import android.content.ServiceConnection; import android.os.Handler; import android.os.IBinder; import android.os.IInterface; import android.os.Looper; import android.os.RemoteException; import android.os.UserHandle; import android.text.TextUtils; import android.util.DebugUtils; import android.util.Log; import com.android.internal.util.function.pooled.PooledLambda; import java.io.PrintWriter; import java.util.ArrayDeque; import java.util.ArrayList; Loading @@ -47,7 +44,6 @@ import java.util.concurrent.TimeUnit; import java.util.function.BiConsumer; import java.util.function.Function; /** * Takes care of managing a {@link ServiceConnection} and auto-disconnecting from the service upon * a certain timeout. Loading Loading @@ -220,6 +216,7 @@ public interface ServiceConnector<I extends IInterface> { private final @NonNull Queue<Job<I, ?>> mQueue = this; private final @NonNull List<CompletionAwareJob<I, ?>> mUnfinishedJobs = new ArrayList<>(); private final @NonNull Handler mMainHandler = new Handler(Looper.getMainLooper()); private final @NonNull ServiceConnection mServiceConnection = this; private final @NonNull Runnable mTimeoutDisconnect = this; Loading Loading @@ -250,9 +247,8 @@ public interface ServiceConnector<I extends IInterface> { * {@link IInterface}. * Typically this is {@code IMyInterface.Stub::asInterface} */ public Impl(@NonNull Context context, @NonNull Intent intent, @Context.BindServiceFlags int bindingFlags, @UserIdInt int userId, @Nullable Function<IBinder, I> binderAsInterface) { public Impl(@NonNull Context context, @NonNull Intent intent, int bindingFlags, @UserIdInt int userId, @Nullable Function<IBinder, I> binderAsInterface) { mContext = context; mIntent = intent; mBindingFlags = bindingFlags; Loading @@ -264,7 +260,7 @@ public interface ServiceConnector<I extends IInterface> { * {@link Handler} on which {@link Job}s will be called */ protected Handler getJobHandler() { return Handler.getMain(); return mMainHandler; } /** Loading Loading @@ -391,8 +387,7 @@ public interface ServiceConnector<I extends IInterface> { private boolean enqueue(@NonNull Job<I, ?> job) { cancelTimeout(); return getJobHandler().sendMessage(PooledLambda.obtainMessage( ServiceConnector.Impl::enqueueJobThread, this, job)); return getJobHandler().post(() -> enqueueJobThread(job)); } void enqueueJobThread(@NonNull Job<I, ?> job) { Loading Loading @@ -422,7 +417,7 @@ public interface ServiceConnector<I extends IInterface> { if (DEBUG) { logTrace(); } Handler.getMain().removeCallbacks(mTimeoutDisconnect); mMainHandler.removeCallbacks(mTimeoutDisconnect); } void completeExceptionally(@NonNull Job<?, ?> job, @NonNull Throwable ex) { Loading Loading @@ -486,7 +481,7 @@ public interface ServiceConnector<I extends IInterface> { } long timeout = getAutoDisconnectTimeoutMs(); if (timeout > 0) { Handler.getMain().postDelayed(mTimeoutDisconnect, timeout); mMainHandler.postDelayed(mTimeoutDisconnect, timeout); } else if (DEBUG) { Log.i(LOG_TAG, "Not scheduling unbind for permanently bound " + this); } Loading @@ -502,7 +497,7 @@ public interface ServiceConnector<I extends IInterface> { logTrace(); } mUnbinding = true; getJobHandler().sendMessage(PooledLambda.obtainMessage(Impl::unbindJobThread, this)); getJobHandler().post(this::unbindJobThread); } void unbindJobThread() { Loading Loading @@ -659,10 +654,7 @@ public interface ServiceConnector<I extends IInterface> { } private void logTrace() { Log.i(LOG_TAG, TextUtils.join(" -> ", DebugUtils.callersWithin(ServiceConnector.class, /* offset= */ 1)) + "(" + this + ")"); Log.i(LOG_TAG, "See stacktrace", new Throwable()); } /** Loading Loading
core/java/com/android/internal/infra/AndroidFuture.java +70 −40 Original line number Diff line number Diff line Loading @@ -16,23 +16,20 @@ package com.android.internal.infra; import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; import android.annotation.CallSuper; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Handler; import android.os.Message; import android.os.Looper; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; import android.util.ExceptionUtils; import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; import com.android.internal.util.function.pooled.PooledLambda; import java.lang.reflect.Constructor; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; Loading Loading @@ -75,14 +72,16 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable private static final boolean DEBUG = false; private static final String LOG_TAG = AndroidFuture.class.getSimpleName(); private static final Executor DIRECT_EXECUTOR = Runnable::run; private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0]; private static @Nullable Handler sMainHandler; private final @NonNull Object mLock = new Object(); @GuardedBy("mLock") private @Nullable BiConsumer<? super T, ? super Throwable> mListener; @GuardedBy("mLock") private @Nullable Executor mListenerExecutor = DIRECT_EXECUTOR; private @NonNull Handler mTimeoutHandler = Handler.getMain(); private @NonNull Handler mTimeoutHandler = getMainHandler(); private final @Nullable IAndroidFuture mRemoteOrigin; public AndroidFuture() { Loading @@ -96,7 +95,7 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable // Done if (in.readBoolean()) { // Failed completeExceptionally(unparcelException(in)); completeExceptionally(readThrowable(in)); } else { // Success complete((T) in.readValue(null)); Loading @@ -108,6 +107,15 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable } } @NonNull private static Handler getMainHandler() { // This isn't thread-safe but we are okay with it. if (sMainHandler == null) { sMainHandler = new Handler(Looper.getMainLooper()); } return sMainHandler; } /** * Create a completed future with the given value. * Loading Loading @@ -236,9 +244,7 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable if (mListenerExecutor == DIRECT_EXECUTOR) { callListener(listener, res, err); } else { mListenerExecutor.execute(PooledLambda .obtainRunnable(AndroidFuture::callListener, listener, res, err) .recycleOnUse()); mListenerExecutor.execute(() -> callListener(listener, res, err)); } } Loading @@ -260,7 +266,8 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable } else { // listener exception-case threw // give up on listener but preserve the original exception when throwing up throw ExceptionUtils.appendCause(t, err); t.addSuppressed(err); throw t; } } } catch (Throwable t2) { Loading @@ -272,9 +279,7 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable /** @inheritDoc */ //@Override //TODO uncomment once java 9 APIs are exposed to frameworks public AndroidFuture<T> orTimeout(long timeout, @NonNull TimeUnit unit) { Message msg = PooledLambda.obtainMessage(AndroidFuture::triggerTimeout, this); msg.obj = this; mTimeoutHandler.sendMessageDelayed(msg, unit.toMillis(timeout)); mTimeoutHandler.postDelayed(this::triggerTimeout, this, unit.toMillis(timeout)); return this; } Loading Loading @@ -507,7 +512,7 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable result = get(); } catch (Throwable t) { dest.writeBoolean(true); parcelException(dest, unwrapExecutionException(t)); writeThrowable(dest, unwrapExecutionException(t)); return; } dest.writeBoolean(false); Loading Loading @@ -545,45 +550,70 @@ public class AndroidFuture<T> extends CompletableFuture<T> implements Parcelable * Alternative to {@link Parcel#writeException} that stores the stack trace, in a * way consistent with the binder IPC exception propagation behavior. */ private static void parcelException(Parcel p, @Nullable Throwable t) { p.writeBoolean(t == null); if (t == null) { private static void writeThrowable(@NonNull Parcel parcel, @Nullable Throwable throwable) { boolean hasThrowable = throwable != null; parcel.writeBoolean(hasThrowable); if (!hasThrowable) { return; } p.writeInt(Parcel.getExceptionCode(t)); p.writeString(t.getClass().getName()); p.writeString(t.getMessage()); p.writeStackTrace(t); parcelException(p, t.getCause()); boolean isFrameworkParcelable = throwable instanceof Parcelable && throwable.getClass().getClassLoader() == Parcelable.class.getClassLoader(); parcel.writeBoolean(isFrameworkParcelable); if (isFrameworkParcelable) { parcel.writeParcelable((Parcelable) throwable, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); return; } parcel.writeString(throwable.getClass().getName()); parcel.writeString(throwable.getMessage()); StackTraceElement[] stackTrace = throwable.getStackTrace(); StringBuilder stackTraceBuilder = new StringBuilder(); int truncatedStackTraceLength = Math.min(stackTrace != null ? stackTrace.length : 0, 5); for (int i = 0; i < truncatedStackTraceLength; i++) { if (i > 0) { stackTraceBuilder.append('\n'); } stackTraceBuilder.append("\tat ").append(stackTrace[i]); } parcel.writeString(stackTraceBuilder.toString()); writeThrowable(parcel, throwable.getCause()); } /** * @see #parcelException * @see #writeThrowable */ private static @Nullable Throwable unparcelException(Parcel p) { if (p.readBoolean()) { private static @Nullable Throwable readThrowable(@NonNull Parcel parcel) { final boolean hasThrowable = parcel.readBoolean(); if (!hasThrowable) { return null; } int exCode = p.readInt(); String cls = p.readString(); String msg = p.readString(); String stackTrace = p.readInt() > 0 ? p.readString() : "\t<stack trace unavailable>"; msg += "\n" + stackTrace; Exception ex = p.createExceptionOrNull(exCode, msg); if (ex == null) { ex = new RuntimeException(cls + ": " + msg); boolean isFrameworkParcelable = parcel.readBoolean(); if (isFrameworkParcelable) { return parcel.readParcelable(Parcelable.class.getClassLoader()); } ex.setStackTrace(EMPTY_STACK_TRACE); Throwable cause = unparcelException(p); String className = parcel.readString(); String message = parcel.readString(); String stackTrace = parcel.readString(); String messageWithStackTrace = message + '\n' + stackTrace; Throwable throwable; try { Class<?> clazz = Class.forName(className); Constructor<?> constructor = clazz.getConstructor(String.class); throwable = (Throwable) constructor.newInstance(messageWithStackTrace); } catch (Throwable t) { throwable = new RuntimeException(className + ": " + messageWithStackTrace); throwable.addSuppressed(t); } throwable.setStackTrace(EMPTY_STACK_TRACE); Throwable cause = readThrowable(parcel); if (cause != null) { ex.initCause(ex); throwable.initCause(cause); } return ex; return throwable; } @Override Loading
core/java/com/android/internal/infra/ServiceConnector.java +10 −18 Original line number Diff line number Diff line Loading @@ -26,14 +26,11 @@ import android.content.ServiceConnection; import android.os.Handler; import android.os.IBinder; import android.os.IInterface; import android.os.Looper; import android.os.RemoteException; import android.os.UserHandle; import android.text.TextUtils; import android.util.DebugUtils; import android.util.Log; import com.android.internal.util.function.pooled.PooledLambda; import java.io.PrintWriter; import java.util.ArrayDeque; import java.util.ArrayList; Loading @@ -47,7 +44,6 @@ import java.util.concurrent.TimeUnit; import java.util.function.BiConsumer; import java.util.function.Function; /** * Takes care of managing a {@link ServiceConnection} and auto-disconnecting from the service upon * a certain timeout. Loading Loading @@ -220,6 +216,7 @@ public interface ServiceConnector<I extends IInterface> { private final @NonNull Queue<Job<I, ?>> mQueue = this; private final @NonNull List<CompletionAwareJob<I, ?>> mUnfinishedJobs = new ArrayList<>(); private final @NonNull Handler mMainHandler = new Handler(Looper.getMainLooper()); private final @NonNull ServiceConnection mServiceConnection = this; private final @NonNull Runnable mTimeoutDisconnect = this; Loading Loading @@ -250,9 +247,8 @@ public interface ServiceConnector<I extends IInterface> { * {@link IInterface}. * Typically this is {@code IMyInterface.Stub::asInterface} */ public Impl(@NonNull Context context, @NonNull Intent intent, @Context.BindServiceFlags int bindingFlags, @UserIdInt int userId, @Nullable Function<IBinder, I> binderAsInterface) { public Impl(@NonNull Context context, @NonNull Intent intent, int bindingFlags, @UserIdInt int userId, @Nullable Function<IBinder, I> binderAsInterface) { mContext = context; mIntent = intent; mBindingFlags = bindingFlags; Loading @@ -264,7 +260,7 @@ public interface ServiceConnector<I extends IInterface> { * {@link Handler} on which {@link Job}s will be called */ protected Handler getJobHandler() { return Handler.getMain(); return mMainHandler; } /** Loading Loading @@ -391,8 +387,7 @@ public interface ServiceConnector<I extends IInterface> { private boolean enqueue(@NonNull Job<I, ?> job) { cancelTimeout(); return getJobHandler().sendMessage(PooledLambda.obtainMessage( ServiceConnector.Impl::enqueueJobThread, this, job)); return getJobHandler().post(() -> enqueueJobThread(job)); } void enqueueJobThread(@NonNull Job<I, ?> job) { Loading Loading @@ -422,7 +417,7 @@ public interface ServiceConnector<I extends IInterface> { if (DEBUG) { logTrace(); } Handler.getMain().removeCallbacks(mTimeoutDisconnect); mMainHandler.removeCallbacks(mTimeoutDisconnect); } void completeExceptionally(@NonNull Job<?, ?> job, @NonNull Throwable ex) { Loading Loading @@ -486,7 +481,7 @@ public interface ServiceConnector<I extends IInterface> { } long timeout = getAutoDisconnectTimeoutMs(); if (timeout > 0) { Handler.getMain().postDelayed(mTimeoutDisconnect, timeout); mMainHandler.postDelayed(mTimeoutDisconnect, timeout); } else if (DEBUG) { Log.i(LOG_TAG, "Not scheduling unbind for permanently bound " + this); } Loading @@ -502,7 +497,7 @@ public interface ServiceConnector<I extends IInterface> { logTrace(); } mUnbinding = true; getJobHandler().sendMessage(PooledLambda.obtainMessage(Impl::unbindJobThread, this)); getJobHandler().post(this::unbindJobThread); } void unbindJobThread() { Loading Loading @@ -659,10 +654,7 @@ public interface ServiceConnector<I extends IInterface> { } private void logTrace() { Log.i(LOG_TAG, TextUtils.join(" -> ", DebugUtils.callersWithin(ServiceConnector.class, /* offset= */ 1)) + "(" + this + ")"); Log.i(LOG_TAG, "See stacktrace", new Throwable()); } /** Loading