Merge "Add cheap aidl tracing suitable for always-on-tracing (1/3)"
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 4806261..c0a8c1e 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4103,12 +4103,12 @@
     }
 
     private void handleStartBinderTracking() {
-        Binder.enableTracing();
+        Binder.enableStackTracking();
     }
 
     private void handleStopBinderTrackingAndDump(ParcelFileDescriptor fd) {
         try {
-            Binder.disableTracing();
+            Binder.disableStackTracking();
             Binder.getTransactionTracker().writeTracesToFile(fd);
         } finally {
             IoUtils.closeQuietly(fd);
@@ -6647,7 +6647,7 @@
         boolean isAppProfileable = isAppDebuggable || data.appInfo.isProfileable();
         Trace.setAppTracingAllowed(isAppProfileable);
         if ((isAppProfileable || Build.IS_DEBUGGABLE) && data.enableBinderTracking) {
-            Binder.enableTracing();
+            Binder.enableStackTracking();
         }
 
         // Initialize heap profiling.
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 8f904b5..a2578d6 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -520,6 +520,10 @@
     // descriptor.
     @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
     boolean stopBinderTrackingAndDump(in ParcelFileDescriptor fd);
+
+    /** Enables server-side binder tracing for the calling uid. */
+    void enableBinderTracing();
+
     @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
     void suppressResizeConfigChanges(boolean suppress);
     @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index b069fb3..e2d7847 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -22,9 +22,11 @@
 import android.app.AppOpsManager;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.util.ExceptionUtils;
+import android.util.IntArray;
 import android.util.Log;
 import android.util.Slog;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.BinderCallHeavyHitterWatcher;
 import com.android.internal.os.BinderCallHeavyHitterWatcher.BinderCallHeavyHitterListener;
 import com.android.internal.os.BinderInternal;
@@ -140,33 +142,55 @@
     /**
      * Flag indicating whether we should be tracing transact calls.
      */
-    private static volatile boolean sTracingEnabled = false;
+    private static volatile boolean sStackTrackingEnabled = false;
+
+    private static final Object sTracingUidsWriteLock = new Object();
+    private static volatile IntArray sTracingUidsImmutable = new IntArray();
 
     /**
-     * Enable Binder IPC tracing.
+     * Enable Binder IPC stack tracking. If enabled, every binder transaction will be logged to
+     * {@link TransactionTracker}.
      *
      * @hide
      */
-    public static void enableTracing() {
-        sTracingEnabled = true;
+    public static void enableStackTracking() {
+        sStackTrackingEnabled = true;
     }
 
     /**
-     * Disable Binder IPC tracing.
+     * Disable Binder IPC stack tracking.
      *
      * @hide
      */
-    public static void disableTracing() {
-        sTracingEnabled = false;
+    public static void disableStackTracking() {
+        sStackTrackingEnabled = false;
     }
 
     /**
-     * Check if binder transaction tracing is enabled.
+     * @hide
+     */
+    public static void enableTracingForUid(int uid) {
+        synchronized (sTracingUidsWriteLock) {
+            final IntArray copy = sTracingUidsImmutable.clone();
+            copy.add(uid);
+            sTracingUidsImmutable = copy;
+        }
+    }
+
+    /**
+     * Check if binder transaction stack tracking is enabled.
      *
      * @hide
      */
-    public static boolean isTracingEnabled() {
-        return sTracingEnabled;
+    public static boolean isStackTrackingEnabled() {
+        return sStackTrackingEnabled;
+    }
+
+    /**
+     * @hide
+     */
+    public static boolean isTracingEnabled(int callingUid) {
+        return sTracingUidsImmutable.indexOf(callingUid) != -1;
     }
 
     /**
@@ -288,6 +312,9 @@
 
     private IInterface mOwner;
     private String mDescriptor;
+    private volatile String[] mTransactionTraceNames = null;
+    private volatile String mSimpleDescriptor = null;
+    private static final int TRANSACTION_TRACE_NAME_ID_LIMIT = 1024;
 
     /**
      * Return the ID of the process that sent you the current transaction
@@ -884,6 +911,53 @@
     }
 
     /**
+     * @hide
+     */
+    @VisibleForTesting
+    public final @NonNull String getTransactionTraceName(int transactionCode) {
+        if (mTransactionTraceNames == null) {
+            final String descriptor = getSimpleDescriptor();
+            final int highestId = Math.min(getMaxTransactionId(), TRANSACTION_TRACE_NAME_ID_LIMIT);
+            final String[] transactionNames = new String[highestId + 1];
+            final StringBuffer buf = new StringBuffer();
+            for (int i = 0; i <= highestId; i++) {
+                String transactionName = getTransactionName(i + FIRST_CALL_TRANSACTION);
+                if (transactionName != null) {
+                    buf.append(descriptor).append(':').append(transactionName);
+                } else {
+                    buf.append(descriptor).append('#').append(i + FIRST_CALL_TRANSACTION);
+                }
+                transactionNames[i] = buf.toString();
+                buf.setLength(0);
+            }
+            mTransactionTraceNames = transactionNames;
+            mSimpleDescriptor = descriptor;
+        }
+        final int index = transactionCode - FIRST_CALL_TRANSACTION;
+        if (index < 0 || index >= mTransactionTraceNames.length) {
+            return mSimpleDescriptor + "#" + transactionCode;
+        }
+        return mTransactionTraceNames[index];
+    }
+
+    private String getSimpleDescriptor() {
+        final int dot = mDescriptor.lastIndexOf(".");
+        if (dot > 0) {
+            // Strip the package name
+            return mDescriptor.substring(dot + 1);
+        }
+        return mDescriptor;
+    }
+
+    /**
+     * @return The highest user-defined transaction id of all transactions.
+     * @hide
+     */
+    public int getMaxTransactionId() {
+        return 0;
+    }
+
+    /**
      * Implemented to call the more convenient version
      * {@link #dump(FileDescriptor, PrintWriter, String[])}.
      */
@@ -1181,7 +1255,8 @@
         // Log any exceptions as warnings, don't silently suppress them.
         // If the call was {@link IBinder#FLAG_ONEWAY} then these exceptions
         // disappear into the ether.
-        final boolean tracingEnabled = Binder.isTracingEnabled();
+        final boolean tracingEnabled = Trace.isTagEnabled(Trace.TRACE_TAG_AIDL) &&
+                (Binder.isStackTrackingEnabled() || Binder.isTracingEnabled(callingUid));
         try {
             final BinderCallHeavyHitterWatcher heavyHitterWatcher = sHeavyHitterWatcher;
             if (heavyHitterWatcher != null) {
@@ -1189,9 +1264,7 @@
                 heavyHitterWatcher.onTransaction(callingUid, getClass(), code);
             }
             if (tracingEnabled) {
-                final String transactionName = getTransactionName(code);
-                Trace.traceBegin(Trace.TRACE_TAG_ALWAYS, getClass().getName() + ":"
-                        + (transactionName != null ? transactionName : code));
+                Trace.traceBegin(Trace.TRACE_TAG_AIDL, getTransactionTraceName(code));
             }
 
             if ((flags & FLAG_COLLECT_NOTED_APP_OPS) != 0) {
@@ -1226,7 +1299,7 @@
             res = true;
         } finally {
             if (tracingEnabled) {
-                Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
+                Trace.traceEnd(Trace.TRACE_TAG_AIDL);
             }
             if (observer != null) {
                 // The parcel RPC headers have been called during onTransact so we can now access
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index 483b549..e929920 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -545,7 +545,7 @@
             }
         }
 
-        final boolean tracingEnabled = Binder.isTracingEnabled();
+        final boolean tracingEnabled = Binder.isStackTrackingEnabled();
         if (tracingEnabled) {
             final Throwable tr = new Throwable();
             Binder.getTransactionTracker().addTrace(tr);
diff --git a/core/java/android/util/IntArray.java b/core/java/android/util/IntArray.java
index b77265b..7b28b8a 100644
--- a/core/java/android/util/IntArray.java
+++ b/core/java/android/util/IntArray.java
@@ -34,7 +34,7 @@
     private int[] mValues;
     private int mSize;
 
-    private  IntArray(int[] array, int size) {
+    private IntArray(int[] array, int size) {
         mValues = array;
         mSize = Preconditions.checkArgumentInRange(size, 0, array.length, "size");
     }
@@ -178,10 +178,8 @@
     }
 
     @Override
-    public IntArray clone() throws CloneNotSupportedException {
-        final IntArray clone = (IntArray) super.clone();
-        clone.mValues = mValues.clone();
-        return clone;
+    public IntArray clone() {
+        return new IntArray(mValues.clone(), mSize);
     }
 
     /**
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 64b303b..32d72b37 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -23,6 +23,7 @@
     ],
 
     aidl: {
+        generate_get_transaction_name: true,
         local_include_dirs: ["aidl"],
     },
 
diff --git a/core/tests/coretests/src/android/os/AidlTest.java b/core/tests/coretests/src/android/os/AidlTest.java
index 4c51415..5f54b09 100644
--- a/core/tests/coretests/src/android/os/AidlTest.java
+++ b/core/tests/coretests/src/android/os/AidlTest.java
@@ -27,11 +27,12 @@
 public class AidlTest extends TestCase {
 
     private IAidlTest mRemote;
+    private AidlObject mLocal;
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        AidlObject mLocal = new AidlObject();
+        mLocal = new AidlObject();
         mRemote = IAidlTest.Stub.asInterface(mLocal);
     }
 
@@ -417,5 +418,24 @@
         }
         assertEquals(good, true);
     }
+
+    @SmallTest
+    public void testGetTransactionName() throws Exception {
+        assertEquals(15, mLocal.getMaxTransactionId());
+
+        assertEquals("booleanArray",
+                mLocal.getTransactionName(IAidlTest.Stub.TRANSACTION_booleanArray));
+        assertEquals("voidSecurityException",
+                mLocal.getTransactionName(IAidlTest.Stub.TRANSACTION_voidSecurityException));
+        assertEquals("parcelableIn",
+                mLocal.getTransactionName(IAidlTest.Stub.TRANSACTION_parcelableIn));
+
+        assertEquals("IAidlTest:booleanArray",
+                mLocal.getTransactionTraceName(IAidlTest.Stub.TRANSACTION_booleanArray));
+        assertEquals("IAidlTest:voidSecurityException",
+                mLocal.getTransactionTraceName(IAidlTest.Stub.TRANSACTION_voidSecurityException));
+        assertEquals("IAidlTest:parcelableIn",
+                mLocal.getTransactionTraceName(IAidlTest.Stub.TRANSACTION_parcelableIn));
+    }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 8c405ca..63962fa 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui;
 
+import android.app.ActivityManager;
 import android.app.ActivityThread;
 import android.app.Application;
 import android.app.Notification;
@@ -27,6 +28,7 @@
 import android.content.res.Configuration;
 import android.os.Bundle;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.os.UserHandle;
@@ -111,6 +113,13 @@
                         ThreadedRendererCompat.EGL_CONTEXT_PRIORITY_HIGH_IMG);
             }
 
+            // Enable binder tracing on system server for calls originating from SysUI
+            try {
+                ActivityManager.getService().enableBinderTracing();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Unable to enable binder tracing", e);
+            }
+
             registerReceiver(new BroadcastReceiver() {
                 @Override
                 public void onReceive(Context context, Intent intent) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a33aa60..a745e5a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -15659,6 +15659,11 @@
         }
     }
 
+    @Override
+    public void enableBinderTracing() {
+        Binder.enableTracingForUid(Binder.getCallingUid());
+    }
+
     @VisibleForTesting
     public final class LocalService extends ActivityManagerInternal
             implements ActivityManagerLocal {