summaryrefslogtreecommitdiff
path: root/quickstep/src/com/android/quickstep/BinderTracker.java
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-02-03 01:29:56 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2024-02-03 01:29:56 +0000
commitb5c5e27ab6bbbaf69203044bab7b9af61efd79dd (patch)
treed51ac9fb3e2a72b592dde8472dcf2bae54adce13 /quickstep/src/com/android/quickstep/BinderTracker.java
parent041c765ca5ee78a8b8c21db1882740b81439c1eb (diff)
parent808fc1574781a8be6700feb728c9ee65426722a8 (diff)
downloadLauncher3-b5c5e27ab6bbbaf69203044bab7b9af61efd79dd.tar.gz
Merge "Snap for 11400057 from ded14cc2110e39408f74abac8a83e0a0f16608d2 to simpleperf-release" into simpleperf-releasesimpleperf-release
Diffstat (limited to 'quickstep/src/com/android/quickstep/BinderTracker.java')
-rw-r--r--quickstep/src/com/android/quickstep/BinderTracker.java187
1 files changed, 187 insertions, 0 deletions
diff --git a/quickstep/src/com/android/quickstep/BinderTracker.java b/quickstep/src/com/android/quickstep/BinderTracker.java
new file mode 100644
index 0000000000..a876cd868b
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/BinderTracker.java
@@ -0,0 +1,187 @@
+/**
+ * Copyright (C) 2023 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 com.android.quickstep;
+
+import static android.os.IBinder.FLAG_ONEWAY;
+
+import android.os.Binder;
+import android.os.Binder.ProxyTransactListener;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.Trace;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.util.SafeCloseable;
+import com.android.launcher3.util.TraceHelper;
+
+import java.util.LinkedList;
+import java.util.Set;
+import java.util.function.Consumer;
+
+import kotlin.random.Random;
+
+/**
+ * A binder proxy transaction listener for tracking binder calls on main thread.
+ */
+public class BinderTracker {
+
+ private static final String TAG = "BinderTracker";
+
+ // Common IPCs that are ok to block the main thread.
+ private static final Set<String> sAllowedFrameworkClasses = Set.of(
+ "android.view.IWindowSession",
+ "android.os.IPowerManager",
+ "android.os.IServiceManager");
+
+ /**
+ * Starts tracking binder class and returns a {@link SafeCloseable} to end tracking
+ */
+ public static SafeCloseable startTracking(Consumer<BinderCallSite> callback) {
+ TraceHelper current = TraceHelper.INSTANCE;
+
+ TraceHelperExtension helper = new TraceHelperExtension(callback);
+ TraceHelper.INSTANCE = helper;
+ Binder.setProxyTransactListener(helper);
+
+ return () -> {
+ Binder.setProxyTransactListener(null);
+ TraceHelper.INSTANCE = current;
+ };
+ }
+
+ private static final LinkedList<String> mMainThreadTraceStack = new LinkedList<>();
+ private static final LinkedList<String> mMainThreadIgnoreIpcStack = new LinkedList<>();
+
+ private static class TraceHelperExtension extends TraceHelper implements ProxyTransactListener {
+
+ private final Consumer<BinderCallSite> mUnexpectedTransactionCallback;
+
+ TraceHelperExtension(Consumer<BinderCallSite> unexpectedTransactionCallback) {
+ mUnexpectedTransactionCallback = unexpectedTransactionCallback;
+ }
+
+ @Override
+ public void beginSection(String sectionName) {
+ if (isMainThread()) {
+ mMainThreadTraceStack.add(sectionName);
+ }
+ super.beginSection(sectionName);
+ }
+
+ @Override
+ public SafeCloseable beginAsyncSection(String sectionName) {
+ if (!isMainThread()) {
+ return super.beginAsyncSection(sectionName);
+ }
+
+ mMainThreadTraceStack.add(sectionName);
+ int cookie = Random.Default.nextInt();
+ Trace.beginAsyncSection(sectionName, cookie);
+ return () -> {
+ Trace.endAsyncSection(sectionName, cookie);
+ mMainThreadTraceStack.remove(sectionName);
+ };
+ }
+
+ @Override
+ public void endSection() {
+ super.endSection();
+ if (isMainThread()) {
+ mMainThreadTraceStack.pollLast();
+ }
+ }
+
+ @Override
+ public SafeCloseable allowIpcs(String rpcName) {
+ if (!isMainThread()) {
+ return super.allowIpcs(rpcName);
+ }
+
+ mMainThreadTraceStack.add(rpcName);
+ mMainThreadIgnoreIpcStack.add(rpcName);
+ int cookie = Random.Default.nextInt();
+ Trace.beginAsyncSection(rpcName, cookie);
+ return () -> {
+ Trace.endAsyncSection(rpcName, cookie);
+ mMainThreadTraceStack.remove(rpcName);
+ mMainThreadIgnoreIpcStack.remove(rpcName);
+ };
+ }
+
+ @Override
+ public Object onTransactStarted(IBinder binder, int transactionCode, int flags) {
+ if (!isMainThread() || (flags & FLAG_ONEWAY) == FLAG_ONEWAY) {
+ return null;
+ }
+
+ String ipcBypass = mMainThreadIgnoreIpcStack.peekLast();
+ String descriptor;
+ try {
+ descriptor = binder.getInterfaceDescriptor();
+ if (sAllowedFrameworkClasses.contains(descriptor)) {
+ return null;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error getting IPC descriptor", e);
+ descriptor = binder.getClass().getSimpleName();
+ }
+
+ if (ipcBypass == null) {
+ mUnexpectedTransactionCallback.accept(new BinderCallSite(
+ mMainThreadTraceStack.peekLast(), descriptor, transactionCode));
+ } else {
+ Log.d(TAG, "MainThread-IPC " + descriptor + " ignored due to " + ipcBypass);
+ }
+ return null;
+ }
+
+ @Override
+ public Object onTransactStarted(IBinder binder, int transactionCode) {
+ // Do nothing
+ return null;
+ }
+
+ @Override
+ public void onTransactEnded(Object session) {
+ // Do nothing
+ }
+ }
+
+ private static boolean isMainThread() {
+ return Thread.currentThread() == Looper.getMainLooper().getThread();
+ }
+
+ /**
+ * Information about a binder call
+ */
+ public static class BinderCallSite {
+
+ @Nullable
+ public final String activeTrace;
+ public final String descriptor;
+ public final int transactionCode;
+
+ BinderCallSite(String activeTrace, String descriptor, int transactionCode) {
+ this.activeTrace = activeTrace;
+ this.descriptor = descriptor;
+ this.transactionCode = transactionCode;
+ }
+ }
+}