Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ce28b257 authored by Dmitri Plotnikov's avatar Dmitri Plotnikov
Browse files

Collect native TIDs for binder threads

This information will be used for attribution of CPU
usage to work source UIDs.

Bug: 158232997
Test: atest FrameworksCoreTests:com.android.internal.os.BinderCallsStatsTest

Change-Id: Ic9fcc1d62515dd11a1fbade80264412615014919
parent 94eb3025
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -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 {
+40 −0
Original line number Diff line number Diff line
@@ -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;
    }
+6 −0
Original line number Diff line number Diff line
@@ -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";
+38 −1
Original line number Diff line number Diff line
@@ -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;
        }
    }
}