summaryrefslogtreecommitdiff
path: root/core/java
diff options
context:
space:
mode:
authorOlivier Gaillard <gaillard@google.com>2018-09-17 09:35:32 +0100
committerOlivier Gaillard <gaillard@google.com>2018-10-29 17:19:31 +0000
commit510cdfc32caac0beb2fc10918f4113a5226fa02b (patch)
treef8fc4f95893b51387eed1e6f4a30db3737de1ab5 /core/java
parent80665469f50a0cf276b6834861f64d1be3e62988 (diff)
Adds a mechanism to listen to proxy transact method calls.
There are multiple use cases for it: 1) Make it easy for another process to set the worksource. The worksource can be propagated in a thread local - this is how gmscore and soon system server works - the worksource can then be set for all binder calls using Object transactStarted() { Binder.setWorkSource(ThreadLocalWorkSourceUid.get()); return null; // No token needed. } void transactEnded() { Binder.setWorkSource(null); } This will be used by system process and gmscore. 2) SystemUI team was interested in detecting binder calls done from the main thread in dogfood/tests. This listener will make it easy to figure out which thread is used. Performance impact of transact method: - With current code: 45ns per call - With this code: 57ns per call This is not significant compared to the total binder call time which is 10-100s of microseconds. Test: unit test Change-Id: Id0a2f52cba33b390ff83f703284b79471cc80b1c
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/os/Binder.java40
-rw-r--r--core/java/android/os/BinderProxy.java22
2 files changed, 62 insertions, 0 deletions
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 8b6194c29707..b2b1d33cf58f 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -555,6 +555,46 @@ public class Binder implements IBinder {
}
/**
+ * Listener to be notified about each proxy-side binder call.
+ *
+ * See {@link setProxyTransactListener}.
+ * @hide
+ */
+ public interface ProxyTransactListener {
+ /**
+ * Called before onTransact.
+ *
+ * @return an object that will be passed back to #onTransactEnded (or null).
+ */
+ Object onTransactStarted(IBinder binder, int transactionCode);
+
+ /**
+ * Called after onTranact (even when an exception is thrown).
+ *
+ * @param session The object return by #onTransactStarted.
+ */
+ void onTransactEnded(@Nullable Object session);
+ }
+
+ /**
+ * 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
+ */
+ 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.
*
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index 591370ff728b..720c16723c63 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -17,6 +17,7 @@
package android.os;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.util.Log;
import android.util.SparseIntArray;
@@ -45,6 +46,15 @@ public final class BinderProxy implements IBinder {
// Assume the process-wide default value when created
volatile boolean mWarnOnBlocking = Binder.sWarnOnBlocking;
+ private static volatile Binder.ProxyTransactListener sTransactListener = null;
+
+ /**
+ * @see {@link Binder#setProxyTransactListener(listener)}.
+ */
+ public static void setTransactListener(@Nullable Binder.ProxyTransactListener listener) {
+ sTransactListener = listener;
+ }
+
/*
* Map from longs to BinderProxy, retaining only a WeakReference to the BinderProxies.
* We roll our own only because we need to lazily remove WeakReferences during accesses
@@ -469,9 +479,21 @@ public final class BinderProxy implements IBinder {
Trace.traceBegin(Trace.TRACE_TAG_ALWAYS,
stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName());
}
+
+ // Make sure the listener won't change while processing a transaction.
+ final Binder.ProxyTransactListener transactListener = sTransactListener;
+ Object session = null;
+ if (transactListener != null) {
+ session = transactListener.onTransactStarted(this, code);
+ }
+
try {
return transactNative(code, data, reply, flags);
} finally {
+ if (transactListener != null) {
+ transactListener.onTransactEnded(session);
+ }
+
if (tracingEnabled) {
Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
}