Merge "Collect native TIDs for binder threads"

This commit is contained in:
TreeHugger Robot
2020-07-09 01:42:39 +00:00
committed by Android (Google) Code Review
4 changed files with 91 additions and 1 deletions

View File

@@ -122,6 +122,13 @@ public class Binder implements IBinder {
private static native long getNativeFinalizer();
/**
* Returns the TID (task ID) for the current thread. Same as {@link Thread#getNativeTid()}
*
* @hide
*/
public static native int getNativeTid();
// 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 {

View File

@@ -27,6 +27,7 @@ import android.os.UserHandle;
import android.text.format.DateFormat;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IntArray;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
@@ -126,6 +127,11 @@ public class BinderCallsStats implements BinderInternal.Observer {
}
};
private final Object mNativeTidsLock = new Object();
// @GuardedBy("mNativeTidsLock") // Cannot mark it as "GuardedBy" because it's read
// directly, as a volatile field.
private volatile IntArray mNativeTids = new IntArray(0);
/** Injector for {@link BinderCallsStats}. */
public static class Injector {
public Random getRandomGenerator() {
@@ -175,6 +181,8 @@ public class BinderCallsStats implements BinderInternal.Observer {
return null;
}
noteNativeThreadId();
final CallSession s = obtainCallSession();
s.binderClass = binder.getClass();
s.transactionCode = code;
@@ -312,6 +320,27 @@ public class BinderCallsStats implements BinderInternal.Observer {
}
}
private void noteNativeThreadId() {
final int tid = getNativeTid();
int index = mNativeTids.binarySearch(tid);
if (index >= 0) {
return;
}
// Use the copy-on-write approach. The changes occur exceedingly infrequently, so
// this code path is exercised just a few times per boot
synchronized (mNativeTidsLock) {
IntArray nativeTids = mNativeTids;
index = nativeTids.binarySearch(tid);
if (index < 0) {
IntArray copyOnWriteArray = new IntArray(nativeTids.size() + 1);
copyOnWriteArray.addAll(nativeTids);
copyOnWriteArray.add(-index - 1, tid);
mNativeTids = copyOnWriteArray;
}
}
}
/**
* This method is expensive to call.
*/
@@ -505,6 +534,17 @@ public class BinderCallsStats implements BinderInternal.Observer {
return Binder.getCallingUid();
}
protected int getNativeTid() {
return Binder.getNativeTid();
}
/**
* Returns known Linux TIDs for threads taking incoming binder calls.
*/
public int[] getNativeTids() {
return mNativeTids.toArray();
}
protected long getElapsedRealtimeMicro() {
return SystemClock.elapsedRealtimeNanos() / 1000;
}

View File

@@ -30,6 +30,7 @@
#include <unistd.h>
#include <android-base/stringprintf.h>
#include <android-base/threads.h>
#include <binder/BpBinder.h>
#include <binder/IInterface.h>
#include <binder/IPCThreadState.h>
@@ -1047,6 +1048,10 @@ static void android_os_Binder_setExtension(JNIEnv* env, jobject obj, jobject ext
jbh->setExtension(extension);
}
JNIEXPORT jint JNICALL android_os_Binder_getNativeTid(JNIEnv* env, jobject clazz) {
return (jint)android::base::GetThreadId();
}
// ----------------------------------------------------------------------------
static const JNINativeMethod gBinderMethods[] = {
@@ -1078,6 +1083,7 @@ static const JNINativeMethod gBinderMethods[] = {
{ "blockUntilThreadAvailable", "()V", (void*)android_os_Binder_blockUntilThreadAvailable },
{ "getExtension", "()Landroid/os/IBinder;", (void*)android_os_Binder_getExtension },
{ "setExtension", "(Landroid/os/IBinder;)V", (void*)android_os_Binder_setExtension },
{ "getNativeTid", "()I", (void*)android_os_Binder_getNativeTid },
};
const char* const kBinderPathName = "android/os/Binder";

View File

@@ -807,6 +807,38 @@ public class BinderCallsStatsTest {
}
}
@Test
public void testNativeTids() {
TestBinderCallsStats bcs = new TestBinderCallsStats();
Binder binder = new Binder();
bcs.nativeTid = 3;
CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID);
bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID);
bcs.nativeTid = 1;
callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID);
bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID);
bcs.nativeTid = 1;
callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID);
bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID);
bcs.nativeTid = 2;
callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID);
bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID);
int[] tids = bcs.getNativeTids();
assertEquals(3, tids.length);
assertEquals(1, tids[0]);
assertEquals(2, tids[1]);
assertEquals(3, tids[2]);
}
private static class TestHandler extends Handler {
ArrayList<Runnable> mRunnables = new ArrayList<>();
@@ -825,6 +857,7 @@ public class BinderCallsStatsTest {
public int callingUid = CALLING_UID;
public long time = 1234;
public long elapsedTime = 0;
public int nativeTid;
TestBinderCallsStats() {
this(mDeviceState);
@@ -874,6 +907,10 @@ public class BinderCallsStatsTest {
protected void setCallingUid(int uid) {
callingUid = uid;
}
}
@Override
protected int getNativeTid() {
return nativeTid;
}
}
}