diff options
| author | Olivier Gaillard <gaillard@google.com> | 2018-09-17 09:35:32 +0100 |
|---|---|---|
| committer | Olivier Gaillard <gaillard@google.com> | 2018-10-29 17:19:31 +0000 |
| commit | 510cdfc32caac0beb2fc10918f4113a5226fa02b (patch) | |
| tree | f8fc4f95893b51387eed1e6f4a30db3737de1ab5 /core/java | |
| parent | 80665469f50a0cf276b6834861f64d1be3e62988 (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.java | 40 | ||||
| -rw-r--r-- | core/java/android/os/BinderProxy.java | 22 |
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); } |
