1580 lines
58 KiB
Java
1580 lines
58 KiB
Java
/*
|
|
* 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);
|
|
}
|
|
}
|
|
}
|