| /* |
| * Copyright (C) 2006 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.os; |
| |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.annotation.SystemApi; |
| import android.app.AppOpsManager; |
| import android.compat.annotation.UnsupportedAppUsage; |
| import android.util.ExceptionUtils; |
| import android.util.Log; |
| import android.util.Slog; |
| |
| import com.android.internal.annotations.VisibleForTesting; |
| import com.android.internal.os.BinderCallHeavyHitterWatcher; |
| import com.android.internal.os.BinderCallHeavyHitterWatcher.BinderCallHeavyHitterListener; |
| import com.android.internal.os.BinderInternal; |
| import com.android.internal.os.BinderInternal.CallSession; |
| import com.android.internal.os.SomeArgs; |
| import com.android.internal.util.FastPrintWriter; |
| import com.android.internal.util.FunctionalUtils.ThrowingRunnable; |
| import com.android.internal.util.FunctionalUtils.ThrowingSupplier; |
| import com.android.internal.util.Preconditions; |
| |
| import dalvik.annotation.optimization.CriticalNative; |
| |
| import libcore.io.IoUtils; |
| import libcore.util.NativeAllocationRegistry; |
| |
| import java.io.FileDescriptor; |
| import java.io.FileInputStream; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.PrintWriter; |
| import java.lang.reflect.Modifier; |
| import java.util.concurrent.atomic.AtomicReferenceArray; |
| import java.util.function.Supplier; |
| |
| /** |
| * Base class for a remotable object, the core part of a lightweight |
| * remote procedure call mechanism defined by {@link IBinder}. |
| * This class is an implementation of IBinder that provides |
| * standard local implementation of such an object. |
| * |
| * <p>Most developers will not implement this class directly, instead using the |
| * <a href="{@docRoot}guide/components/aidl.html">aidl</a> tool to describe the desired |
| * interface, having it generate the appropriate Binder subclass. You can, |
| * however, derive directly from Binder to implement your own custom RPC |
| * protocol or simply instantiate a raw Binder object directly to use as a |
| * token that can be shared across processes. |
| * |
| * <p>This class is just a basic IPC primitive; it has no impact on an application's |
| * lifecycle, and is valid only as long as the process that created it continues to run. |
| * To use this correctly, you must be doing so within the context of a top-level |
| * application component (a {@link android.app.Service}, {@link android.app.Activity}, |
| * or {@link android.content.ContentProvider}) that lets the system know your process |
| * should remain running. |
| * |
| * <p>You must keep in mind the situations in which your process |
| * could go away, and thus require that you later re-create a new Binder and re-attach |
| * it when the process starts again. For example, if you are using this within an |
| * {@link android.app.Activity}, your activity's process may be killed any time the |
| * activity is not started; if the activity is later re-created you will need to |
| * create a new Binder and hand it back to the correct place again; you need to be |
| * aware that your process may be started for another reason (for example to receive |
| * a broadcast) that will not involve re-creating the activity and thus run its code |
| * to create a new Binder. |
| * |
| * @see IBinder |
| */ |
| public class Binder implements IBinder { |
| /* |
| * Set this flag to true to detect anonymous, local or member classes |
| * that extend this Binder class and that are not static. These kind |
| * of classes can potentially create leaks. |
| */ |
| private static final boolean FIND_POTENTIAL_LEAKS = false; |
| /** @hide */ |
| public static final boolean CHECK_PARCEL_SIZE = false; |
| static final String TAG = "Binder"; |
| |
| /** @hide */ |
| public static boolean LOG_RUNTIME_EXCEPTION = false; // DO NOT SUBMIT WITH TRUE |
| |
| /** |
| * Value to represents that a calling work source is not set. |
| * |
| * <p>This constant needs to be kept in sync with IPCThreadState::kUnsetWorkSource. |
| * |
| * @hide |
| */ |
| public static final int UNSET_WORKSOURCE = -1; |
| |
| /** |
| * Control whether {@link #dump(FileDescriptor, PrintWriter, String[]) dump()} |
| * calls are allowed. |
| */ |
| private static volatile String sDumpDisabled = null; |
| |
| /** |
| * Global transaction tracker instance for this process. |
| */ |
| private static volatile TransactionTracker sTransactionTracker = null; |
| |
| /** |
| * Global observer for this process. |
| */ |
| private static BinderInternal.Observer sObserver = null; |
| |
| /** |
| * Guestimate of native memory associated with a Binder. |
| */ |
| private static final int NATIVE_ALLOCATION_SIZE = 500; |
| |
| private static native long getNativeFinalizer(); |
| |
| // Use a Holder to allow static initialization of Binder in the boot image, and |
| // possibly to avoid some initialization ordering issues. |
| private static class NoImagePreloadHolder { |
| public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry( |
| Binder.class.getClassLoader(), getNativeFinalizer(), NATIVE_ALLOCATION_SIZE); |
| } |
| |
| /** |
| * The watcher to monitor the heavy hitter from incoming transactions |
| */ |
| private static volatile BinderCallHeavyHitterWatcher sHeavyHitterWatcher = null; |
| |
| // Transaction tracking code. |
| |
| /** |
| * Flag indicating whether we should be tracing transact calls. |
| */ |
| private static volatile boolean sStackTrackingEnabled = false; |
| |
| /** |
| * Enable Binder IPC stack tracking. If enabled, every binder transaction will be logged to |
| * {@link TransactionTracker}. |
| * |
| * @hide |
| */ |
| public static void enableStackTracking() { |
| sStackTrackingEnabled = true; |
| } |
| |
| /** |
| * Disable Binder IPC stack tracking. |
| * |
| * @hide |
| */ |
| public static void disableStackTracking() { |
| sStackTrackingEnabled = false; |
| } |
| |
| /** |
| * Check if binder transaction stack tracking is enabled. |
| * |
| * @hide |
| */ |
| public static boolean isStackTrackingEnabled() { |
| return sStackTrackingEnabled; |
| } |
| |
| /** |
| * Get the binder transaction tracker for this process. |
| * |
| * @hide |
| */ |
| public synchronized static TransactionTracker getTransactionTracker() { |
| if (sTransactionTracker == null) |
| sTransactionTracker = new TransactionTracker(); |
| return sTransactionTracker; |
| } |
| |
| /** |
| * Get the binder transaction observer for this process. |
| * |
| * TODO(b/299356196): only applies to Java code, not C++/Rust |
| * |
| * @hide |
| */ |
| public static void setObserver(@Nullable BinderInternal.Observer observer) { |
| sObserver = observer; |
| } |
| |
| /** @hide */ |
| static volatile boolean sWarnOnBlocking = false; |
| |
| /** |
| * Warn if any blocking binder transactions are made out from this process. |
| * This is typically only useful for the system process, to prevent it from |
| * blocking on calls to external untrusted code. Instead, all outgoing calls |
| * that require a result must be sent as {@link IBinder#FLAG_ONEWAY} calls |
| * which deliver results through a callback interface. |
| * |
| * TODO(b/299355525): only applies to Java code, not C++/Rust |
| * |
| * @hide |
| */ |
| public static void setWarnOnBlocking(boolean warnOnBlocking) { |
| sWarnOnBlocking = warnOnBlocking; |
| } |
| |
| /** |
| * Allow blocking calls on the given interface, overriding the requested |
| * value of {@link #setWarnOnBlocking(boolean)}. |
| * |
| * <p>This should only be rarely called when you are <em>absolutely sure</em> |
| * the remote interface is a built-in system component that can never be |
| * upgraded. In particular, this <em>must never</em> be called for |
| * interfaces hosted by package that could be upgraded or replaced, |
| * otherwise you risk system instability if that remote interface wedges. |
| * |
| * TODO(b/299355525): only applies to Java code, not C++/Rust |
| * |
| * @hide |
| */ |
| public static IBinder allowBlocking(IBinder binder) { |
| try { |
| if (binder instanceof BinderProxy) { |
| ((BinderProxy) binder).mWarnOnBlocking = false; |
| } else if (binder != null && binder.getInterfaceDescriptor() != null |
| && binder.queryLocalInterface(binder.getInterfaceDescriptor()) == null) { |
| Log.w(TAG, "Unable to allow blocking on interface " + binder); |
| } |
| } catch (RemoteException ignored) { |
| } |
| return binder; |
| } |
| |
| /** |
| * Reset the given interface back to the default blocking behavior, |
| * reverting any changes made by {@link #allowBlocking(IBinder)}. |
| * |
| * @hide |
| */ |
| public static IBinder defaultBlocking(IBinder binder) { |
| if (binder instanceof BinderProxy) { |
| ((BinderProxy) binder).mWarnOnBlocking = sWarnOnBlocking; |
| } |
| return binder; |
| } |
| |
| /** |
| * Inherit the current {@link #allowBlocking(IBinder)} value from one given |
| * interface to another. |
| * |
| * @hide |
| */ |
| public static void copyAllowBlocking(IBinder fromBinder, IBinder toBinder) { |
| if (fromBinder instanceof BinderProxy && toBinder instanceof BinderProxy) { |
| ((BinderProxy) toBinder).mWarnOnBlocking = ((BinderProxy) fromBinder).mWarnOnBlocking; |
| } |
| } |
| |
| static ThreadLocal<Boolean> sWarnOnBlockingOnCurrentThread = |
| ThreadLocal.withInitial(() -> sWarnOnBlocking); |
| |
| /** |
| * Allow blocking calls for the current thread. |
| * |
| * @see {@link #allowBlocking}. |
| * |
| * @hide |
| */ |
| public static void allowBlockingForCurrentThread() { |
| sWarnOnBlockingOnCurrentThread.set(false); |
| } |
| |
| /** |
| * Reset the current thread to the default blocking behavior. |
| * |
| * @see {@link #defaultBlocking}. |
| * |
| * @hide |
| */ |
| public static void defaultBlockingForCurrentThread() { |
| sWarnOnBlockingOnCurrentThread.set(sWarnOnBlocking); |
| } |
| |
| private static volatile ThreadLocal<SomeArgs> sIdentity$ravenwood; |
| |
| @android.ravenwood.annotation.RavenwoodKeepWholeClass |
| private static class IdentitySupplier implements Supplier<SomeArgs> { |
| @Override |
| public SomeArgs get() { |
| final SomeArgs args = SomeArgs.obtain(); |
| // Match IPCThreadState behavior |
| args.arg1 = Boolean.FALSE; |
| args.argi1 = android.os.Process.myUid(); |
| args.argi2 = android.os.Process.myPid(); |
| return args; |
| } |
| } |
| |
| /** @hide */ |
| @android.ravenwood.annotation.RavenwoodKeep |
| public static void init$ravenwood() { |
| sIdentity$ravenwood = ThreadLocal.withInitial(new IdentitySupplier()); |
| } |
| |
| /** @hide */ |
| @android.ravenwood.annotation.RavenwoodKeep |
| public static void reset$ravenwood() { |
| sIdentity$ravenwood = null; |
| } |
| |
| /** |
| * Raw native pointer to JavaBBinderHolder object. Owned by this Java object. Not null. |
| */ |
| @UnsupportedAppUsage |
| private final long mObject; |
| |
| private IInterface mOwner; |
| @Nullable |
| private String mDescriptor; |
| private volatile AtomicReferenceArray<String> mTransactionTraceNames = null; |
| private volatile String mSimpleDescriptor = null; |
| private static final int TRANSACTION_TRACE_NAME_ID_LIMIT = 1024; |
| |
| /** |
| * Return the ID of the process that sent you the current transaction |
| * that is being processed. This PID can be used with higher-level |
| * system services to determine its identity and check permissions. |
| * If the current thread is not currently executing an incoming transaction, |
| * then its own PID is returned. |
| * |
| * Warning: oneway transactions do not receive PID. Even if you expect |
| * a transaction to be synchronous, a misbehaving client could send it |
| * as a asynchronous call and result in a 0 PID here. Additionally, if |
| * there is a race and the calling process dies, the PID may still be |
| * 0 for a synchronous call. |
| */ |
| @CriticalNative |
| @android.ravenwood.annotation.RavenwoodReplace |
| public static final native int getCallingPid(); |
| |
| /** @hide */ |
| public static final int getCallingPid$ravenwood() { |
| return Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get().argi2; |
| } |
| |
| /** |
| * Return the Linux UID assigned to the process that sent you the |
| * current transaction that is being processed. This UID can be used with |
| * higher-level system services to determine its identity and check |
| * permissions. If the current thread is not currently executing an |
| * incoming transaction, then its own UID is returned. |
| */ |
| @CriticalNative |
| @android.ravenwood.annotation.RavenwoodReplace |
| public static final native int getCallingUid(); |
| |
| /** @hide */ |
| public static final int getCallingUid$ravenwood() { |
| return Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get().argi1; |
| } |
| |
| /** |
| * Returns {@code true} if the current thread is currently executing an |
| * incoming transaction. |
| * |
| * @hide |
| */ |
| @CriticalNative |
| @android.ravenwood.annotation.RavenwoodReplace |
| public static final native boolean isDirectlyHandlingTransactionNative(); |
| |
| /** @hide */ |
| public static final boolean isDirectlyHandlingTransactionNative$ravenwood() { |
| // Ravenwood doesn't support IPC |
| return false; |
| } |
| |
| private static boolean sIsHandlingBinderTransaction = false; |
| |
| /** |
| * @hide |
| */ |
| @android.ravenwood.annotation.RavenwoodKeep |
| public static final boolean isDirectlyHandlingTransaction() { |
| return sIsHandlingBinderTransaction || isDirectlyHandlingTransactionNative(); |
| } |
| |
| /** |
| * This is Test API which will be used to override output of isDirectlyHandlingTransactionNative |
| * @hide |
| */ |
| @android.ravenwood.annotation.RavenwoodKeep |
| public static void setIsDirectlyHandlingTransactionOverride(boolean isInTransaction) { |
| sIsHandlingBinderTransaction = isInTransaction; |
| } |
| |
| /** |
| * Returns {@code true} if the current thread has had its identity |
| * set explicitly via {@link #clearCallingIdentity()} |
| * |
| * @hide |
| */ |
| @CriticalNative |
| @android.ravenwood.annotation.RavenwoodReplace |
| private static native boolean hasExplicitIdentity(); |
| |
| /** @hide */ |
| private static boolean hasExplicitIdentity$ravenwood() { |
| return Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get().arg1 |
| == Boolean.TRUE; |
| } |
| |
| /** |
| * Return the Linux UID assigned to the process that sent the transaction |
| * currently being processed. |
| * |
| * @throws IllegalStateException if the current thread is not currently |
| * executing an incoming transaction and the calling identity has not been |
| * explicitly set with {@link #clearCallingIdentity()} |
| */ |
| @android.ravenwood.annotation.RavenwoodKeep |
| public static final int getCallingUidOrThrow() { |
| if (!isDirectlyHandlingTransaction() && !hasExplicitIdentity()) { |
| throw new IllegalStateException( |
| "Thread is not in a binder transaction, " |
| + "and the calling identity has not been " |
| + "explicitly set with clearCallingIdentity"); |
| } |
| return getCallingUid(); |
| } |
| |
| /** |
| * Return the Linux UID assigned to the process that sent the transaction |
| * currently being processed. |
| * |
| * Slog.wtf if the current thread is not currently |
| * executing an incoming transaction and the calling identity has not been |
| * explicitly set with {@link #clearCallingIdentity()} |
| * |
| * @hide |
| */ |
| public static final int getCallingUidOrWtf(String message) { |
| if (!isDirectlyHandlingTransaction() && !hasExplicitIdentity()) { |
| Slog.wtf(TAG, |
| message + ": Thread is not in a binder transaction, " |
| + "and the calling identity has not been " |
| + "explicitly set with clearCallingIdentity"); |
| } |
| return getCallingUid(); |
| } |
| |
| /** |
| * Return the UserHandle assigned to the process that sent you the |
| * current transaction that is being processed. This is the user |
| * of the caller. It is distinct from {@link #getCallingUid()} in that a |
| * particular user will have multiple distinct apps running under it each |
| * with their own UID. If the current thread is not currently executing an |
| * incoming transaction, then its own UserHandle is returned. |
| * |
| * @see UserHandle |
| */ |
| public static final @NonNull UserHandle getCallingUserHandle() { |
| return UserHandle.of(UserHandle.getUserId(getCallingUid())); |
| } |
| |
| /** |
| * Reset the identity of the incoming IPC on the current thread. This can |
| * be useful if, while handling an incoming call, you will be calling |
| * on interfaces of other objects that may be local to your process and |
| * need to do permission checks on the calls coming into them (so they |
| * will check the permission of your own local process, and not whatever |
| * process originally called you). |
| * |
| * @return Returns an opaque token that can be used to restore the |
| * original calling identity by passing it to |
| * {@link #restoreCallingIdentity(long)}. |
| * |
| * @see #getCallingPid() |
| * @see #getCallingUid() |
| * @see #restoreCallingIdentity(long) |
| */ |
| @CriticalNative |
| @android.ravenwood.annotation.RavenwoodReplace |
| public static final native long clearCallingIdentity(); |
| |
| /** @hide */ |
| public static final long clearCallingIdentity$ravenwood() { |
| final SomeArgs args = Preconditions.requireNonNullViaRavenwoodRule( |
| sIdentity$ravenwood).get(); |
| long res = ((long) args.argi1 << 32) | args.argi2; |
| if (args.arg1 == Boolean.TRUE) { |
| res |= (0x1 << 30); |
| } else { |
| res &= ~(0x1 << 30); |
| } |
| // Match IPCThreadState behavior |
| args.arg1 = Boolean.TRUE; |
| args.argi1 = android.os.Process.myUid(); |
| args.argi2 = android.os.Process.myPid(); |
| return res; |
| } |
| |
| /** |
| * Restore the identity of the incoming IPC on the current thread |
| * back to a previously identity that was returned by {@link |
| * #clearCallingIdentity}. |
| * |
| * @param token The opaque token that was previously returned by |
| * {@link #clearCallingIdentity}. |
| * |
| * @see #clearCallingIdentity |
| */ |
| @CriticalNative |
| @android.ravenwood.annotation.RavenwoodReplace |
| public static final native void restoreCallingIdentity(long token); |
| |
| /** @hide */ |
| public static final void restoreCallingIdentity$ravenwood(long token) { |
| final SomeArgs args = Preconditions.requireNonNullViaRavenwoodRule( |
| sIdentity$ravenwood).get(); |
| args.arg1 = ((token & (0x1 << 30)) != 0) ? Boolean.TRUE : Boolean.FALSE; |
| args.argi1 = (int) (token >> 32); |
| args.argi2 = (int) (token & ~(0x1 << 30)); |
| } |
| |
| /** |
| * Convenience method for running the provided action enclosed in |
| * {@link #clearCallingIdentity}/{@link #restoreCallingIdentity}. |
| * |
| * <p>Any exception thrown by the given action will be caught and |
| * rethrown after the call to {@link #restoreCallingIdentity}. |
| * |
| * @hide |
| */ |
| public static final void withCleanCallingIdentity(@NonNull ThrowingRunnable action) { |
| Throwable throwableToPropagate = null; |
| final long callingIdentity = clearCallingIdentity(); |
| try { |
| action.runOrThrow(); |
| } catch (Throwable throwable) { |
| throwableToPropagate = throwable; |
| } finally { |
| restoreCallingIdentity(callingIdentity); |
| if (throwableToPropagate != null) { |
| throw ExceptionUtils.propagate(throwableToPropagate); |
| } |
| } |
| } |
| |
| /** |
| * Convenience method for running the provided action enclosed in |
| * {@link #clearCallingIdentity}/{@link #restoreCallingIdentity} returning the result. |
| * |
| * <p>Any exception thrown by the given action will be caught and rethrown after |
| * the call to {@link #restoreCallingIdentity}. |
| * |
| * @hide |
| */ |
| public static final <T> T withCleanCallingIdentity(@NonNull ThrowingSupplier<T> action) { |
| Throwable throwableToPropagate = null; |
| final long callingIdentity = clearCallingIdentity(); |
| try { |
| return action.getOrThrow(); |
| } catch (Throwable throwable) { |
| throwableToPropagate = throwable; |
| return null; // overridden by throwing in finally block |
| } finally { |
| restoreCallingIdentity(callingIdentity); |
| if (throwableToPropagate != null) { |
| throw ExceptionUtils.propagate(throwableToPropagate); |
| } |
| } |
| } |
| |
| /** |
| * Sets the native thread-local StrictMode policy mask. |
| * |
| * <p>The StrictMode settings are kept in two places: a Java-level |
| * threadlocal for libcore/Dalvik, and a native threadlocal (set |
| * here) for propagation via Binder calls. This is a little |
| * unfortunate, but necessary to break otherwise more unfortunate |
| * dependencies either of Dalvik on Android, or Android |
| * native-only code on Dalvik. |
| * |
| * @see StrictMode |
| * |
| * @hide |
| */ |
| @CriticalNative |
| public static final native void setThreadStrictModePolicy(int policyMask); |
| |
| /** |
| * Gets the current native thread-local StrictMode policy mask. |
| * |
| * @see #setThreadStrictModePolicy |
| * |
| * @hide |
| */ |
| @CriticalNative |
| public static final native int getThreadStrictModePolicy(); |
| |
| /** |
| * Sets the work source for this thread. |
| * |
| * <p>All the following binder calls on this thread will use the provided work source. If this |
| * is called during an on-going binder transaction, all the following binder calls will use the |
| * work source until the end of the transaction. |
| * |
| * <p>The concept of worksource is similar to {@link WorkSource}. However, for performance |
| * reasons, we only support one UID. This UID represents the original user responsible for the |
| * binder calls. |
| * |
| * <p>{@link #restoreCallingWorkSource(long)} must always be called after setting the |
| * worksource. |
| * |
| * <p>A typical use case would be |
| * <pre> |
| * long token = Binder.setCallingWorkSourceUid(uid); |
| * try { |
| * // Call an API. |
| * } finally { |
| * Binder.restoreCallingWorkSource(token); |
| * } |
| * </pre> |
| * |
| * <p>The work source will be propagated for future outgoing binder transactions |
| * executed on this thread. |
| * |
| * @param workSource The original UID responsible for the binder call. |
| * @return token to restore original work source. |
| */ |
| @CriticalNative |
| public static final native long setCallingWorkSourceUid(int workSource); |
| |
| /** |
| * Returns the work source set by the caller. |
| * |
| * <p>Unlike {@link #getCallingUid()}, this result of this method cannot be trusted. The |
| * caller can set the value to whatever they want. Only use this value if you trust the calling |
| * UID. |
| * |
| * @return The original UID responsible for the binder transaction. |
| */ |
| @CriticalNative |
| public static final native int getCallingWorkSourceUid(); |
| |
| /** |
| * Clears the work source on this thread. |
| * |
| * <p>The work source will be propagated for future outgoing binder transactions |
| * executed on this thread. |
| * |
| * <p>{@link #restoreCallingWorkSource(long)} must always be called after clearing the |
| * worksource. |
| * |
| * <p>A typical use case would be |
| * <pre> |
| * long token = Binder.clearCallingWorkSource(); |
| * try { |
| * // Call an API. |
| * } finally { |
| * Binder.restoreCallingWorkSource(token); |
| * } |
| * </pre> |
| * |
| * @return token to restore original work source. |
| */ |
| @CriticalNative |
| public static final native long clearCallingWorkSource(); |
| |
| /** |
| * Restores the work source on this thread using a token returned by |
| * {@link #setCallingWorkSourceUid(int)} or {@link #clearCallingWorkSource()}. |
| * |
| * <p>A typical use case would be |
| * <pre> |
| * long token = Binder.setCallingWorkSourceUid(uid); |
| * try { |
| * // Call an API. |
| * } finally { |
| * Binder.restoreCallingWorkSource(token); |
| * } |
| * </pre> |
| */ |
| @CriticalNative |
| public static final native void restoreCallingWorkSource(long token); |
| |
| /** |
| * Mark as being built with VINTF-level stability promise. This API should |
| * only ever be invoked by generated code from the aidl compiler. It means |
| * that the interface represented by this binder is guaranteed to be kept |
| * stable for several years, according to the VINTF compatibility lifecycle, |
| * and the build system also keeps snapshots of these APIs and invokes the |
| * AIDL compiler to make sure that these snapshots are backwards compatible. |
| * Instead of using this API, use the @VintfStability annotation on your |
| * AIDL interface. |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.PRIVILEGED_APPS) |
| public final native void markVintfStability(); |
| |
| /** |
| * Use a VINTF-stability binder w/o VINTF requirements. Should be called |
| * on a binder before it is sent out of process. |
| * |
| * <p>This must be called before the object is sent to another process. |
| * |
| * @hide |
| */ |
| public final native void forceDowngradeToSystemStability(); |
| |
| /** |
| * Flush any Binder commands pending in the current thread to the kernel |
| * driver. This can be |
| * useful to call before performing an operation that may block for a long |
| * time, to ensure that any pending object references have been released |
| * in order to prevent the process from holding on to objects longer than |
| * it needs to. |
| */ |
| @android.ravenwood.annotation.RavenwoodReplace |
| public static final native void flushPendingCommands(); |
| |
| /** @hide */ |
| public static final void flushPendingCommands$ravenwood() { |
| // Ravenwood doesn't support IPC; ignored |
| } |
| |
| /** |
| * Add the calling thread to the IPC thread pool. This function does |
| * not return until the current process is exiting. |
| */ |
| public static final void joinThreadPool() { |
| BinderInternal.joinThreadPool(); |
| } |
| |
| /** |
| * Returns true if the specified interface is a proxy. |
| * |
| * @hide |
| */ |
| public static final boolean isProxy(IInterface iface) { |
| return iface.asBinder() != iface; |
| } |
| |
| /** |
| * Call blocks until the number of executing binder threads is less |
| * than the maximum number of binder threads allowed for this process. |
| * |
| * @hide |
| */ |
| public static final native void blockUntilThreadAvailable(); |
| |
| |
| /** |
| * TODO (b/308179628): Move this to libbinder for non-Java usages. |
| */ |
| private static IBinderCallback sBinderCallback = null; |
| |
| /** |
| * Set callback function for unexpected binder transaction errors. |
| * |
| * @hide |
| */ |
| public static final void setTransactionCallback(IBinderCallback callback) { |
| sBinderCallback = callback; |
| } |
| |
| /** |
| * Execute the callback function if it's already set. |
| * |
| * @hide |
| */ |
| public static final void transactionCallback(int pid, int code, int flags, int err) { |
| if (sBinderCallback != null) { |
| sBinderCallback.onTransactionError(pid, code, flags, err); |
| } |
| } |
| |
| /** |
| * Default constructor just initializes the object. |
| * |
| * <p>If you're creating a Binder token (a Binder object without an attached interface), |
| * you should use {@link #Binder(String)} instead. |
| */ |
| @android.ravenwood.annotation.RavenwoodKeep |
| public Binder() { |
| this(null); |
| } |
| |
| /** |
| * Constructor for creating a raw Binder object (token) along with a descriptor. |
| * |
| * <p>The descriptor of binder objects usually specifies the interface they are implementing. |
| * In case of binder tokens, no interface is implemented, and the descriptor can be used |
| * as a sort of tag to help identify the binder token. This will help identify remote |
| * references to these objects more easily when debugging. |
| * |
| * @param descriptor Used to identify the creator of this token, for example the class name. |
| * Instead of creating multiple tokens with the same descriptor, consider adding a suffix to |
| * help identify them. |
| */ |
| @android.ravenwood.annotation.RavenwoodKeep |
| public Binder(@Nullable String descriptor) { |
| mObject = getNativeBBinderHolder(); |
| if (mObject != 0L) { |
| NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mObject); |
| } |
| |
| if (FIND_POTENTIAL_LEAKS) { |
| final Class<? extends Binder> klass = getClass(); |
| if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && |
| (klass.getModifiers() & Modifier.STATIC) == 0) { |
| Log.w(TAG, "The following Binder class should be static or leaks might occur: " + |
| klass.getCanonicalName()); |
| } |
| } |
| mDescriptor = descriptor; |
| } |
| |
| /** |
| * Convenience method for associating a specific interface with the Binder. |
| * After calling, {@link #queryLocalInterface(String) queryLocalInterface()} |
| * will be implemented for you to return the given owner IInterface when |
| * the corresponding descriptor is requested. |
| */ |
| @android.ravenwood.annotation.RavenwoodKeep |
| public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) { |
| mOwner = owner; |
| mDescriptor = descriptor; |
| } |
| |
| /** |
| * Default implementation returns an empty interface name. |
| */ |
| @android.ravenwood.annotation.RavenwoodKeep |
| public @Nullable String getInterfaceDescriptor() { |
| return mDescriptor; |
| } |
| |
| /** |
| * Default implementation always returns true -- if you got here, |
| * the object is alive. |
| */ |
| @android.ravenwood.annotation.RavenwoodKeep |
| public boolean pingBinder() { |
| return true; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * Note that if you're calling on a local binder, this always returns true |
| * because your process is alive if you're calling it. |
| */ |
| @android.ravenwood.annotation.RavenwoodKeep |
| public boolean isBinderAlive() { |
| return true; |
| } |
| |
| /** |
| * Use information supplied to {@link #attachInterface attachInterface()} |
| * to return the associated {@link IInterface} if it matches the requested |
| * descriptor. |
| */ |
| @android.ravenwood.annotation.RavenwoodKeep |
| public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) { |
| if (mDescriptor != null && mDescriptor.equals(descriptor)) { |
| return mOwner; |
| } |
| return null; |
| } |
| |
| /** |
| * Control disabling of dump calls in this process. This is used by the system |
| * process watchdog to disable incoming dump calls while it has detecting the system |
| * is hung and is reporting that back to the activity controller. This is to |
| * prevent the controller from getting hung up on bug reports at this point. |
| * |
| * @param msg The message to show instead of the dump; if null, dumps are |
| * re-enabled. |
| * |
| * @hide |
| */ |
| public static void setDumpDisabled(String msg) { |
| sDumpDisabled = msg; |
| } |
| |
| /** |
| * Listener to be notified about each proxy-side binder call. |
| * |
| * @see {@link #setProxyTransactListener}. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public interface ProxyTransactListener { |
| /** |
| * Called before onTransact. |
| * |
| * @return an object that will be passed back to {@link #onTransactEnded} (or null)., |
| * |
| * @hide |
| */ |
| @Nullable |
| default Object onTransactStarted(@NonNull IBinder binder, int transactionCode, int flags) { |
| return onTransactStarted(binder, transactionCode); |
| } |
| |
| /** |
| * Called before onTransact. |
| * |
| * @return an object that will be passed back to {@link #onTransactEnded} (or null). |
| */ |
| @Nullable |
| Object onTransactStarted(@NonNull IBinder binder, int transactionCode); |
| |
| /** |
| * Called after onTransact (even when an exception is thrown). |
| * |
| * @param session The object return by {@link #onTransactStarted}. |
| */ |
| void onTransactEnded(@Nullable Object session); |
| } |
| |
| /** |
| * Propagates the work source to binder calls executed by the system server. |
| * |
| * <li>By default, this listener will propagate the worksource if the outgoing call happens on |
| * the same thread as the incoming binder call. |
| * <li>Custom attribution can be done by calling {@link ThreadLocalWorkSource#setUid(int)}. |
| * |
| * @hide |
| */ |
| public static class PropagateWorkSourceTransactListener implements ProxyTransactListener { |
| @Override |
| public Object onTransactStarted(IBinder binder, int transactionCode) { |
| // Note that {@link #getCallingUid()} is already set to the UID of the current |
| // process when this method is called. |
| // |
| // We use {@link ThreadLocalWorkSource} instead. It also allows feature owners to set |
| // {@link ThreadLocalWorkSource#set(int)} manually to attribute resources to a UID. |
| int uid = ThreadLocalWorkSource.getUid(); |
| if (uid != ThreadLocalWorkSource.UID_NONE) { |
| return Binder.setCallingWorkSourceUid(uid); |
| } |
| return null; |
| } |
| |
| @Override |
| public void onTransactEnded(Object session) { |
| if (session != null) { |
| long token = (long) session; |
| Binder.restoreCallingWorkSource(token); |
| } |
| } |
| } |
| |
| /** |
| * Sets a listener for the transact method on the proxy-side. |
| * |
| * <li>The listener is global. Only fast operations should be done to avoid thread |
| * contentions. |
| * <li>The listener implementation needs to handle synchronization if needed. The methods on the |
| * listener can be called concurrently. |
| * <li>Listener set will be used for new transactions. On-going transaction will still use the |
| * previous listener (if already set). |
| * <li>The listener is called on the critical path of the binder transaction so be careful about |
| * performance. |
| * <li>Never execute another binder transaction inside the listener. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static void setProxyTransactListener(@Nullable ProxyTransactListener listener) { |
| BinderProxy.setTransactListener(listener); |
| } |
| |
| /** |
| * Default implementation is a stub that returns false. You will want |
| * to override this to do the appropriate unmarshalling of transactions. |
| * |
| * <p>If you want to call this, call transact(). |
| * |
| * <p>Implementations that are returning a result should generally use |
| * {@link Parcel#writeNoException() Parcel.writeNoException} and |
| * {@link Parcel#writeException(Exception) Parcel.writeException} to propagate |
| * exceptions back to the caller. |
| * |
| * @param code The action to perform. This should be a number between |
| * {@link #FIRST_CALL_TRANSACTION} and {@link #LAST_CALL_TRANSACTION}. |
| * @param data Marshalled data being received from the caller. |
| * @param reply If the caller is expecting a result back, it should be marshalled |
| * in to here. |
| * @param flags Additional operation flags. Either 0 for a normal |
| * RPC, or {@link #FLAG_ONEWAY} for a one-way RPC. |
| * |
| * @return Return true on a successful call; returning false is generally used to |
| * indicate that you did not understand the transaction code. |
| */ |
| protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, |
| int flags) throws RemoteException { |
| if (code == INTERFACE_TRANSACTION) { |
| reply.writeString(getInterfaceDescriptor()); |
| return true; |
| } else if (code == DUMP_TRANSACTION) { |
| ParcelFileDescriptor fd = data.readFileDescriptor(); |
| String[] args = data.readStringArray(); |
| if (fd != null) { |
| try { |
| dump(fd.getFileDescriptor(), args); |
| } finally { |
| IoUtils.closeQuietly(fd); |
| } |
| } |
| // Write the StrictMode header. |
| if (reply != null) { |
| reply.writeNoException(); |
| } else { |
| StrictMode.clearGatheredViolations(); |
| } |
| return true; |
| } else if (code == SHELL_COMMAND_TRANSACTION) { |
| ParcelFileDescriptor in = data.readFileDescriptor(); |
| ParcelFileDescriptor out = data.readFileDescriptor(); |
| ParcelFileDescriptor err = data.readFileDescriptor(); |
| String[] args = data.readStringArray(); |
| ShellCallback shellCallback = ShellCallback.CREATOR.createFromParcel(data); |
| ResultReceiver resultReceiver = ResultReceiver.CREATOR.createFromParcel(data); |
| try { |
| if (out != null) { |
| shellCommand(in != null ? in.getFileDescriptor() : null, |
| out.getFileDescriptor(), |
| err != null ? err.getFileDescriptor() : out.getFileDescriptor(), |
| args, shellCallback, resultReceiver); |
| } |
| } finally { |
| IoUtils.closeQuietly(in); |
| IoUtils.closeQuietly(out); |
| IoUtils.closeQuietly(err); |
| // Write the StrictMode header. |
| if (reply != null) { |
| reply.writeNoException(); |
| } else { |
| StrictMode.clearGatheredViolations(); |
| } |
| } |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Resolves a transaction code to a human readable name. |
| * |
| * <p>Default implementation is a stub that returns null. |
| * |
| * <p>AIDL generated code will return the original method name. |
| * |
| * @param transactionCode The code to resolve. |
| * @return A human readable name. |
| * |
| * @hide |
| */ |
| @android.ravenwood.annotation.RavenwoodKeep |
| public @Nullable String getTransactionName(int transactionCode) { |
| return null; |
| } |
| |
| /** |
| * @hide |
| */ |
| @VisibleForTesting |
| @android.ravenwood.annotation.RavenwoodKeep |
| public final @Nullable String getTransactionTraceName(int transactionCode) { |
| final boolean isInterfaceUserDefined = getMaxTransactionId() == 0; |
| if (mTransactionTraceNames == null) { |
| final int highestId = isInterfaceUserDefined ? TRANSACTION_TRACE_NAME_ID_LIMIT |
| : Math.min(getMaxTransactionId(), TRANSACTION_TRACE_NAME_ID_LIMIT); |
| mSimpleDescriptor = getSimpleDescriptor(); |
| mTransactionTraceNames = new AtomicReferenceArray(highestId + 1); |
| } |
| |
| final int index = isInterfaceUserDefined |
| ? transactionCode : transactionCode - FIRST_CALL_TRANSACTION; |
| if (index >= mTransactionTraceNames.length() || index < 0) { |
| return null; |
| } |
| |
| String transactionTraceName = mTransactionTraceNames.getAcquire(index); |
| if (transactionTraceName == null) { |
| final String transactionName = getTransactionName(transactionCode); |
| final StringBuffer buf = new StringBuffer(); |
| |
| // Keep trace name consistent with cpp trace name in: |
| // system/tools/aidl/generate_cpp.cpp |
| buf.append("AIDL::java::"); |
| if (transactionName != null) { |
| buf.append(mSimpleDescriptor).append("::").append(transactionName); |
| } else { |
| buf.append(mSimpleDescriptor).append("::#").append(transactionCode); |
| } |
| buf.append("::server"); |
| |
| transactionTraceName = buf.toString(); |
| mTransactionTraceNames.setRelease(index, transactionTraceName); |
| } |
| |
| return transactionTraceName; |
| } |
| |
| @android.ravenwood.annotation.RavenwoodKeep |
| private @NonNull String getSimpleDescriptor() { |
| String descriptor = mDescriptor; |
| if (descriptor == null) { |
| // Just "Binder" to avoid null checks in transaction name tracing. |
| return "Binder"; |
| } |
| |
| final int dot = descriptor.lastIndexOf("."); |
| if (dot > 0) { |
| // Strip the package name |
| return descriptor.substring(dot + 1); |
| } |
| return descriptor; |
| } |
| |
| /** |
| * @return The highest user-defined transaction id of all transactions. |
| * @hide |
| */ |
| @android.ravenwood.annotation.RavenwoodKeep |
| public int getMaxTransactionId() { |
| return 0; |
| } |
| |
| /** |
| * Implemented to call the more convenient version |
| * {@link #dump(FileDescriptor, PrintWriter, String[])}. |
| */ |
| public void dump(@NonNull FileDescriptor fd, @Nullable String[] args) { |
| FileOutputStream fout = new FileOutputStream(fd); |
| PrintWriter pw = new FastPrintWriter(fout); |
| try { |
| doDump(fd, pw, args); |
| } finally { |
| pw.flush(); |
| } |
| } |
| |
| void doDump(FileDescriptor fd, PrintWriter pw, String[] args) { |
| final String disabled = sDumpDisabled; |
| if (disabled == null) { |
| try { |
| dump(fd, pw, args); |
| } catch (SecurityException e) { |
| pw.println("Security exception: " + e.getMessage()); |
| throw e; |
| } catch (Throwable e) { |
| // Unlike usual calls, in this case if an exception gets thrown |
| // back to us we want to print it back in to the dump data, since |
| // that is where the caller expects all interesting information to |
| // go. |
| pw.println(); |
| pw.println("Exception occurred while dumping:"); |
| e.printStackTrace(pw); |
| } |
| } else { |
| pw.println(sDumpDisabled); |
| } |
| } |
| |
| /** |
| * Like {@link #dump(FileDescriptor, String[])}, but ensures the target |
| * executes asynchronously. |
| */ |
| public void dumpAsync(@NonNull final FileDescriptor fd, @Nullable final String[] args) { |
| final FileOutputStream fout = new FileOutputStream(fd); |
| final PrintWriter pw = new FastPrintWriter(fout); |
| Thread thr = new Thread("Binder.dumpAsync") { |
| public void run() { |
| try { |
| dump(fd, pw, args); |
| } finally { |
| pw.flush(); |
| } |
| } |
| }; |
| thr.start(); |
| } |
| |
| /** |
| * Print the object's state into the given stream. |
| * |
| * @param fd The raw file descriptor that the dump is being sent to. |
| * @param fout The file to which you should dump your state. This will be |
| * closed for you after you return. |
| * @param args additional arguments to the dump request. |
| */ |
| protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout, |
| @Nullable String[] args) { |
| } |
| |
| /** |
| * @param in The raw file descriptor that an input data stream can be read from. |
| * @param out The raw file descriptor that normal command messages should be written to. |
| * @param err The raw file descriptor that command error messages should be written to. |
| * @param args Command-line arguments. |
| * @param callback Callback through which to interact with the invoking shell. |
| * @param resultReceiver Called when the command has finished executing, with the result code. |
| * @throws RemoteException |
| * |
| * @hide |
| */ |
| public void shellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out, |
| @Nullable FileDescriptor err, |
| @NonNull String[] args, @Nullable ShellCallback callback, |
| @NonNull ResultReceiver resultReceiver) throws RemoteException { |
| onShellCommand(in, out, err, args, callback, resultReceiver); |
| } |
| |
| /** |
| * Handle a call to {@link #shellCommand}. |
| * |
| * <p>The default implementation performs a caller check to make sure the caller UID is of |
| * SHELL or ROOT, and then call {@link #handleShellCommand}. |
| * |
| * <p class="caution">Note: no permission checking is done before calling this method; you must |
| * apply any security checks as appropriate for the command being executed. |
| * Consider using {@link ShellCommand} to help in the implementation. |
| * |
| * @hide |
| */ |
| public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out, |
| @Nullable FileDescriptor err, |
| @NonNull String[] args, @Nullable ShellCallback callback, |
| @NonNull ResultReceiver resultReceiver) throws RemoteException { |
| |
| final int callingUid = Binder.getCallingUid(); |
| if (callingUid != Process.ROOT_UID && callingUid != Process.SHELL_UID) { |
| resultReceiver.send(-1, null); |
| throw new SecurityException("Shell commands are only callable by ADB"); |
| } |
| |
| // First, convert in, out and err to @NonNull, by redirecting any that's null to /dev/null. |
| try { |
| if (in == null) { |
| in = new FileInputStream("/dev/null").getFD(); |
| } |
| if (out == null) { |
| out = new FileOutputStream("/dev/null").getFD(); |
| } |
| if (err == null) { |
| err = out; |
| } |
| } catch (IOException e) { |
| PrintWriter pw = new FastPrintWriter(new FileOutputStream(err != null ? err : out)); |
| pw.println("Failed to open /dev/null: " + e.getMessage()); |
| pw.flush(); |
| resultReceiver.send(-1, null); |
| return; |
| } |
| // Also make args @NonNull. |
| if (args == null) { |
| args = new String[0]; |
| } |
| |
| int result = -1; |
| try (ParcelFileDescriptor inPfd = ParcelFileDescriptor.dup(in); |
| ParcelFileDescriptor outPfd = ParcelFileDescriptor.dup(out); |
| ParcelFileDescriptor errPfd = ParcelFileDescriptor.dup(err)) { |
| result = handleShellCommand(inPfd, outPfd, errPfd, args); |
| } catch (IOException e) { |
| PrintWriter pw = new FastPrintWriter(new FileOutputStream(err)); |
| pw.println("dup() failed: " + e.getMessage()); |
| pw.flush(); |
| } finally { |
| resultReceiver.send(result, null); |
| } |
| } |
| |
| /** |
| * System services can implement this method to implement ADB shell commands. |
| * |
| * <p>A system binder service can implement it to handle shell commands on ADB. For example, |
| * the Job Scheduler service implements it to handle {@code adb shell cmd jobscheduler}. |
| * |
| * <p>Commands are only executable by ADB shell; i.e. only {@link Process#SHELL_UID} and |
| * {@link Process#ROOT_UID} can call them. |
| * |
| * @param in standard input |
| * @param out standard output |
| * @param err standard error |
| * @param args arguments passed to the command. Can be empty. The first argument is typically |
| * a subcommand, such as {@code run} for {@code adb shell cmd jobscheduler run}. |
| * @return the status code returned from the {@code cmd} command. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public int handleShellCommand(@NonNull ParcelFileDescriptor in, |
| @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, |
| @NonNull String[] args) { |
| FileOutputStream ferr = new FileOutputStream(err.getFileDescriptor()); |
| PrintWriter pw = new FastPrintWriter(ferr); |
| pw.println("No shell command implementation."); |
| pw.flush(); |
| return 0; |
| } |
| |
| /** @hide */ |
| @Override |
| public final native @Nullable IBinder getExtension(); |
| |
| /** |
| * Set the binder extension. |
| * This should be called immediately when the object is created. |
| * |
| * @hide |
| */ |
| public final native void setExtension(@Nullable IBinder extension); |
| |
| /** |
| * Default implementation rewinds the parcels and calls onTransact. On |
| * the remote side, transact calls into the binder to do the IPC. |
| */ |
| public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, |
| int flags) throws RemoteException { |
| if (false) Log.v("Binder", "Transact: " + code + " to " + this); |
| |
| if (data != null) { |
| data.setDataPosition(0); |
| } |
| boolean r = onTransact(code, data, reply, flags); |
| if (reply != null) { |
| reply.setDataPosition(0); |
| } |
| return r; |
| } |
| |
| /** |
| * Local implementation is a no-op. |
| */ |
| @android.ravenwood.annotation.RavenwoodKeep |
| public void linkToDeath(@NonNull DeathRecipient recipient, int flags) { |
| } |
| |
| /** |
| * Local implementation is a no-op. |
| */ |
| @android.ravenwood.annotation.RavenwoodKeep |
| public boolean unlinkToDeath(@NonNull DeathRecipient recipient, int flags) { |
| return true; |
| } |
| |
| static void checkParcel(IBinder obj, int code, Parcel parcel, String msg) { |
| if (CHECK_PARCEL_SIZE && parcel.dataSize() >= 800*1024) { |
| // Trying to send > 800k, this is way too much. |
| StringBuilder sb = new StringBuilder(); |
| sb.append(msg); |
| sb.append(": on "); |
| sb.append(obj); |
| sb.append(" calling "); |
| sb.append(code); |
| sb.append(" size "); |
| sb.append(parcel.dataSize()); |
| sb.append(" (data: "); |
| parcel.setDataPosition(0); |
| sb.append(parcel.readInt()); |
| sb.append(", "); |
| sb.append(parcel.readInt()); |
| sb.append(", "); |
| sb.append(parcel.readInt()); |
| sb.append(")"); |
| Slog.wtfStack(TAG, sb.toString()); |
| } |
| } |
| |
| @android.ravenwood.annotation.RavenwoodReplace |
| private static native long getNativeBBinderHolder(); |
| |
| private static long getNativeBBinderHolder$ravenwood() { |
| return 0L; |
| } |
| |
| /** |
| * By default, we use the calling UID since we can always trust it. |
| */ |
| private static volatile BinderInternal.WorkSourceProvider sWorkSourceProvider = |
| (x) -> Binder.getCallingUid(); |
| |
| /** |
| * Sets the work source provider. |
| * |
| * <li>The callback is global. Only fast operations should be done to avoid thread |
| * contentions. |
| * <li>The callback implementation needs to handle synchronization if needed. The methods on the |
| * callback can be called concurrently. |
| * <li>The callback is called on the critical path of the binder transaction so be careful about |
| * performance. |
| * <li>Never execute another binder transaction inside the callback. |
| * |
| * @hide |
| */ |
| public static void setWorkSourceProvider(BinderInternal.WorkSourceProvider workSourceProvider) { |
| if (workSourceProvider == null) { |
| throw new IllegalArgumentException("workSourceProvider cannot be null"); |
| } |
| sWorkSourceProvider = workSourceProvider; |
| } |
| |
| // Entry point from android_util_Binder.cpp's onTransact. |
| @UnsupportedAppUsage |
| private boolean execTransact(int code, long dataObj, long replyObj, |
| int flags) { |
| |
| Parcel data = Parcel.obtain(dataObj); |
| Parcel reply = Parcel.obtain(replyObj); |
| |
| // At that point, the parcel request headers haven't been parsed so we do not know what |
| // {@link WorkSource} the caller has set. Use calling UID as the default. |
| // |
| // TODO: this is wrong - we should attribute along the entire call route |
| // also this attribution logic should move to native code - it only works |
| // for Java now |
| // |
| // This attribution support is not generic and therefore not support in RPC mode |
| final int callingUid = data.isForRpc() ? -1 : Binder.getCallingUid(); |
| final long origWorkSource = callingUid == -1 |
| ? -1 : ThreadLocalWorkSource.setUid(callingUid); |
| |
| try { |
| return execTransactInternal(code, data, reply, flags, callingUid); |
| } finally { |
| reply.recycle(); |
| data.recycle(); |
| |
| if (callingUid != -1) { |
| ThreadLocalWorkSource.restore(origWorkSource); |
| } |
| } |
| } |
| |
| private boolean execTransactInternal(int code, Parcel data, Parcel reply, int flags, |
| int callingUid) { |
| // Make sure the observer won't change while processing a transaction. |
| final BinderInternal.Observer observer = sObserver; |
| |
| // TODO(b/299356196): observer should also observe transactions in native code |
| final CallSession callSession = |
| observer != null ? observer.callStarted(this, code, UNSET_WORKSOURCE) : null; |
| // Theoretically, we should call transact, which will call onTransact, |
| // but all that does is rewind it, and we just got these from an IPC, |
| // so we'll just call it directly. |
| boolean res; |
| // Log any exceptions as warnings, don't silently suppress them. |
| // If the call was {@link IBinder#FLAG_ONEWAY} then these exceptions |
| // disappear into the ether. |
| final boolean tagEnabled = Trace.isTagEnabled(Trace.TRACE_TAG_AIDL); |
| final boolean hasFullyQualifiedName = getMaxTransactionId() > 0; |
| final String transactionTraceName; |
| |
| if (tagEnabled) { |
| // If tracing enabled and we have a fully qualified name, fetch the name |
| transactionTraceName = getTransactionTraceName(code); |
| } else { |
| transactionTraceName = null; |
| } |
| |
| final boolean tracingEnabled = tagEnabled && transactionTraceName != null; |
| try { |
| // TODO(b/299356201) - this logic should not be in Java - it should be in native |
| // code in libbinder so that it works for all binder users. |
| final BinderCallHeavyHitterWatcher heavyHitterWatcher = sHeavyHitterWatcher; |
| if (heavyHitterWatcher != null && callingUid != -1) { |
| // Notify the heavy hitter watcher, if it's enabled. |
| heavyHitterWatcher.onTransaction(callingUid, getClass(), code); |
| } |
| if (tracingEnabled) { |
| Trace.traceBegin(Trace.TRACE_TAG_AIDL, transactionTraceName); |
| } |
| |
| // TODO(b/299353919) - this logic should not be in Java - it should be |
| // in native code in libbinder so that it works for all binder users. |
| // Further, this should not re-use flags. |
| if ((flags & FLAG_COLLECT_NOTED_APP_OPS) != 0 && callingUid != -1) { |
| AppOpsManager.startNotedAppOpsCollection(callingUid); |
| try { |
| res = onTransact(code, data, reply, flags); |
| } finally { |
| AppOpsManager.finishNotedAppOpsCollection(); |
| } |
| } else { |
| res = onTransact(code, data, reply, flags); |
| } |
| } catch (RemoteException|RuntimeException e) { |
| if (observer != null) { |
| observer.callThrewException(callSession, e); |
| } |
| if (LOG_RUNTIME_EXCEPTION) { |
| Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e); |
| } |
| if ((flags & FLAG_ONEWAY) != 0) { |
| if (e instanceof RemoteException) { |
| Log.w(TAG, "Binder call failed.", e); |
| } else { |
| Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e); |
| } |
| } else { |
| // Clear the parcel before writing the exception. |
| reply.setDataSize(0); |
| reply.setDataPosition(0); |
| reply.writeException(e); |
| } |
| res = true; |
| } finally { |
| if (tracingEnabled) { |
| Trace.traceEnd(Trace.TRACE_TAG_AIDL); |
| } |
| if (observer != null) { |
| // The parcel RPC headers have been called during onTransact so we can now access |
| // the worksource UID from the parcel. |
| final int workSourceUid = sWorkSourceProvider.resolveWorkSourceUid( |
| data.readCallingWorkSourceUid()); |
| observer.callEnded(callSession, data.dataSize(), reply.dataSize(), workSourceUid); |
| } |
| |
| checkParcel(this, code, reply, "Unreasonably large binder reply buffer"); |
| } |
| |
| // Just in case -- we are done with the IPC, so there should be no more strict |
| // mode violations that have gathered for this thread. Either they have been |
| // parceled and are now in transport off to the caller, or we are returning back |
| // to the main transaction loop to wait for another incoming transaction. Either |
| // way, strict mode begone! |
| StrictMode.clearGatheredViolations(); |
| return res; |
| } |
| |
| /** |
| * Set the configuration for the heavy hitter watcher. |
| * |
| * @hide |
| */ |
| public static synchronized void setHeavyHitterWatcherConfig(final boolean enabled, |
| final int batchSize, final float threshold, |
| @Nullable final BinderCallHeavyHitterListener listener) { |
| Slog.i(TAG, "Setting heavy hitter watcher config: " |
| + enabled + ", " + batchSize + ", " + threshold); |
| BinderCallHeavyHitterWatcher watcher = sHeavyHitterWatcher; |
| if (enabled) { |
| if (listener == null) { |
| throw new IllegalArgumentException(); |
| } |
| boolean newWatcher = false; |
| if (watcher == null) { |
| watcher = BinderCallHeavyHitterWatcher.getInstance(); |
| newWatcher = true; |
| } |
| watcher.setConfig(true, batchSize, threshold, listener); |
| if (newWatcher) { |
| sHeavyHitterWatcher = watcher; |
| } |
| } else if (watcher != null) { |
| watcher.setConfig(false, 0, 0.0f, null); |
| } |
| } |
| } |