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 {