Merge changes I02e88c93,Id0a2f52c
* changes: Use the BinderProxy#TransactListener to propagate the UID. Adds a mechanism to listen to proxy transact method calls.
This commit is contained in:
committed by
Android (Google) Code Review
commit
78ecd34d29
@@ -554,6 +554,79 @@ public class Binder implements IBinder {
|
||||
sDumpDisabled = msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ThreadLocalWorkSourceUid#set(int)}.
|
||||
* @hide
|
||||
*/
|
||||
public static class PropagateWorkSourceTransactListener implements ProxyTransactListener {
|
||||
@Override
|
||||
public Object onTransactStarted(IBinder binder, int transactionCode) {
|
||||
// Note that {@link Binder#getCallingUid()} is already set to the UID of the current
|
||||
// process when this method is called.
|
||||
//
|
||||
// We use ThreadLocalWorkSourceUid instead. It also allows feature owners to set
|
||||
// {@link ThreadLocalWorkSourceUid#set(int) manually to attribute resources to a UID.
|
||||
int uid = ThreadLocalWorkSourceUid.get();
|
||||
if (uid >= 0) {
|
||||
int originalUid = Binder.setThreadWorkSource(uid);
|
||||
return Integer.valueOf(originalUid);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTransactEnded(Object session) {
|
||||
if (session != null) {
|
||||
int uid = (int) session;
|
||||
Binder.setThreadWorkSource(uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
88
core/tests/coretests/src/android/os/BinderProxyTest.java
Normal file
88
core/tests/coretests/src/android/os/BinderProxyTest.java
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.Nullable;
|
||||
import android.content.Context;
|
||||
import android.test.AndroidTestCase;
|
||||
import android.test.suitebuilder.annotation.MediumTest;
|
||||
|
||||
public class BinderProxyTest extends AndroidTestCase {
|
||||
private static class CountingListener implements Binder.ProxyTransactListener {
|
||||
int mStartedCount;
|
||||
int mEndedCount;
|
||||
|
||||
public Object onTransactStarted(IBinder binder, int transactionCode) {
|
||||
mStartedCount++;
|
||||
return null;
|
||||
}
|
||||
|
||||
public void onTransactEnded(@Nullable Object session) {
|
||||
mEndedCount++;
|
||||
}
|
||||
};
|
||||
|
||||
private PowerManager mPowerManager;
|
||||
|
||||
/**
|
||||
* Setup any common data for the upcoming tests.
|
||||
*/
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
public void testNoListener() throws Exception {
|
||||
CountingListener listener = new CountingListener();
|
||||
Binder.setProxyTransactListener(listener);
|
||||
Binder.setProxyTransactListener(null);
|
||||
|
||||
mPowerManager.isInteractive();
|
||||
|
||||
assertEquals(0, listener.mStartedCount);
|
||||
assertEquals(0, listener.mEndedCount);
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
public void testListener() throws Exception {
|
||||
CountingListener listener = new CountingListener();
|
||||
Binder.setProxyTransactListener(listener);
|
||||
|
||||
mPowerManager.isInteractive();
|
||||
|
||||
assertEquals(1, listener.mStartedCount);
|
||||
assertEquals(1, listener.mEndedCount);
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
public void testSessionPropagated() throws Exception {
|
||||
Binder.setProxyTransactListener(new Binder.ProxyTransactListener() {
|
||||
public Object onTransactStarted(IBinder binder, int transactionCode) {
|
||||
return "foo";
|
||||
}
|
||||
|
||||
public void onTransactEnded(@Nullable Object session) {
|
||||
assertEquals("foo", session);
|
||||
}
|
||||
});
|
||||
|
||||
// Check it does not throw..
|
||||
mPowerManager.isInteractive();
|
||||
}
|
||||
}
|
||||
@@ -49,6 +49,7 @@ public class BinderCallsStatsService extends Binder {
|
||||
private static final String PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING
|
||||
= "persist.sys.binder_calls_detailed_tracking";
|
||||
|
||||
|
||||
/** Listens for flag changes. */
|
||||
private static class SettingsObserver extends ContentObserver {
|
||||
private static final String SETTINGS_ENABLED_KEY = "enabled";
|
||||
@@ -101,7 +102,14 @@ public class BinderCallsStatsService extends Binder {
|
||||
final boolean enabled =
|
||||
mParser.getBoolean(SETTINGS_ENABLED_KEY, BinderCallsStats.ENABLED_DEFAULT);
|
||||
if (mEnabled != enabled) {
|
||||
Binder.setObserver(enabled ? mBinderCallsStats : null);
|
||||
if (enabled) {
|
||||
Binder.setObserver(mBinderCallsStats);
|
||||
Binder.setProxyTransactListener(
|
||||
new Binder.PropagateWorkSourceTransactListener());
|
||||
} else {
|
||||
Binder.setObserver(null);
|
||||
Binder.setProxyTransactListener(null);
|
||||
}
|
||||
mEnabled = enabled;
|
||||
mBinderCallsStats.reset();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user