Adding main thread binder tracing in development build.

> Unifying multiple binder tracing implementations
> Removing wallpaper customization check as it has been rolled out
  few years ago, this avoids additional RPC to check for wallpaper
> Removing RaceConditionReproducer as it is not used anywhere and
  is not integrated with this tracing anymore

Bug: 273718665
Test: Presubmit
Flag: N/A
Change-Id: I801af5d039a9d38d5d39e803723ec6da50a9d59f
diff --git a/quickstep/src/com/android/launcher3/uioverrides/DejankBinderTracker.java b/quickstep/src/com/android/launcher3/uioverrides/DejankBinderTracker.java
deleted file mode 100644
index d8aa235..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/DejankBinderTracker.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/**
- * Copyright (C) 2019 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.launcher3.uioverrides;
-
-import static android.os.IBinder.FLAG_ONEWAY;
-
-import android.os.Binder;
-import android.os.Build;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.RemoteException;
-import android.util.Log;
-
-import androidx.annotation.MainThread;
-
-import java.util.HashSet;
-import java.util.Locale;
-import java.util.function.BiConsumer;
-import java.util.function.Supplier;
-
-/**
- * A binder proxy transaction listener for tracking non-whitelisted binder calls.
- */
-public class DejankBinderTracker implements Binder.ProxyTransactListener {
-    private static final String TAG = "DejankBinderTracker";
-
-    private static final Object sLock = new Object();
-    private static final HashSet<String> sWhitelistedFrameworkClasses = new HashSet<>();
-    static {
-        // Common IPCs that are ok to block the main thread.
-        sWhitelistedFrameworkClasses.add("android.view.IWindowSession");
-        sWhitelistedFrameworkClasses.add("android.os.IPowerManager");
-    }
-    private static boolean sTemporarilyIgnoreTracking = false;
-
-    // Used by the client to limit binder tracking to specific regions
-    private static boolean sTrackingAllowed = false;
-
-    private BiConsumer<String, Integer> mUnexpectedTransactionCallback;
-    private boolean mIsTracking = false;
-
-    /**
-     * Temporarily ignore blocking binder calls for the duration of this {@link Runnable}.
-     */
-    @MainThread
-    public static void whitelistIpcs(Runnable runnable) {
-        sTemporarilyIgnoreTracking = true;
-        runnable.run();
-        sTemporarilyIgnoreTracking = false;
-    }
-
-    /**
-     * Temporarily ignore blocking binder calls for the duration of this {@link Supplier}.
-     */
-    @MainThread
-    public static <T> T whitelistIpcs(Supplier<T> supplier) {
-        sTemporarilyIgnoreTracking = true;
-        T value = supplier.get();
-        sTemporarilyIgnoreTracking = false;
-        return value;
-    }
-
-    /**
-     * Enables binder tracking during a test.
-     */
-    @MainThread
-    public static void allowBinderTrackingInTests() {
-        sTrackingAllowed = true;
-    }
-
-    /**
-     * Disables binder tracking during a test.
-     */
-    @MainThread
-    public static void disallowBinderTrackingInTests() {
-        sTrackingAllowed = false;
-    }
-
-    public DejankBinderTracker(BiConsumer<String, Integer> unexpectedTransactionCallback) {
-        mUnexpectedTransactionCallback = unexpectedTransactionCallback;
-    }
-
-    @MainThread
-    public void startTracking() {
-        if (!Build.TYPE.toLowerCase(Locale.ROOT).contains("debug")
-                && !Build.TYPE.toLowerCase(Locale.ROOT).equals("eng")) {
-            Log.wtf(TAG, "Unexpected use of binder tracker in non-debug build", new Exception());
-            return;
-        }
-        if (mIsTracking) {
-            return;
-        }
-        mIsTracking = true;
-        Binder.setProxyTransactListener(this);
-    }
-
-    @MainThread
-    public void stopTracking() {
-        if (!mIsTracking) {
-            return;
-        }
-        mIsTracking = false;
-        Binder.setProxyTransactListener(null);
-    }
-
-    // Override the hidden Binder#onTransactStarted method
-    public synchronized Object onTransactStarted(IBinder binder, int transactionCode, int flags) {
-        if (!mIsTracking
-                || !sTrackingAllowed
-                || sTemporarilyIgnoreTracking
-                || (flags & FLAG_ONEWAY) == FLAG_ONEWAY
-                || !isMainThread()) {
-            return null;
-        }
-
-        String descriptor;
-        try {
-            descriptor = binder.getInterfaceDescriptor();
-            if (sWhitelistedFrameworkClasses.contains(descriptor)) {
-                return null;
-            }
-        } catch (RemoteException e) {
-            e.printStackTrace();
-            descriptor = binder.getClass().getSimpleName();
-        }
-
-        mUnexpectedTransactionCallback.accept(descriptor, transactionCode);
-        return null;
-    }
-
-    @Override
-    public Object onTransactStarted(IBinder binder, int transactionCode) {
-        // Do nothing
-        return null;
-    }
-
-    @Override
-    public void onTransactEnded(Object session) {
-        // Do nothing
-    }
-
-    public static boolean isMainThread() {
-        return Thread.currentThread() == Looper.getMainLooper().getThread();
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 2b92188..bf4896d 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -112,6 +112,7 @@
 import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter;
 import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.util.TraceHelper;
 import com.android.launcher3.util.VibratorWrapper;
 import com.android.launcher3.util.WindowBounds;
@@ -587,7 +588,7 @@
         if (mWasLauncherAlreadyVisible) {
             mStateCallback.setState(STATE_LAUNCHER_DRAWN);
         } else {
-            Object traceToken = TraceHelper.INSTANCE.beginSection("WTS-init");
+            SafeCloseable traceToken = TraceHelper.INSTANCE.beginAsyncSection("WTS-init");
             View dragLayer = activity.getDragLayer();
             dragLayer.getViewTreeObserver().addOnDrawListener(new OnDrawListener() {
                 boolean mHandled = false;
@@ -599,7 +600,7 @@
                     }
                     mHandled = true;
 
-                    TraceHelper.INSTANCE.endSection(traceToken);
+                    traceToken.close();
                     dragLayer.post(() ->
                             dragLayer.getViewTreeObserver().removeOnDrawListener(this));
                     if (activity != mActivity) {
@@ -681,11 +682,10 @@
     private void initializeLauncherAnimationController() {
         buildAnimationController();
 
-        Object traceToken = TraceHelper.INSTANCE.beginSection("logToggleRecents",
-                TraceHelper.FLAG_IGNORE_BINDERS);
-        LatencyTracker.getInstance(mContext).logAction(LatencyTracker.ACTION_TOGGLE_RECENTS,
-                (int) (mLauncherFrameDrawnTime - mTouchTimeMs));
-        TraceHelper.INSTANCE.endSection(traceToken);
+        try (SafeCloseable c = TraceHelper.INSTANCE.allowIpcs("logToggleRecents")) {
+            LatencyTracker.getInstance(mContext).logAction(LatencyTracker.ACTION_TOGGLE_RECENTS,
+                    (int) (mLauncherFrameDrawnTime - mTouchTimeMs));
+        }
 
         // This method is only called when STATE_GESTURE_STARTED is set, so we can enable the
         // high-res thumbnail loader here once we are sure that we will end up in an overview state
@@ -2039,10 +2039,9 @@
 
     private void setScreenshotCapturedState() {
         // If we haven't posted a draw callback, set the state immediately.
-        Object traceToken = TraceHelper.INSTANCE.beginSection(SCREENSHOT_CAPTURED_EVT,
-                TraceHelper.FLAG_CHECK_FOR_RACE_CONDITIONS);
+        TraceHelper.INSTANCE.beginSection(SCREENSHOT_CAPTURED_EVT);
         mStateCallback.setStateOnUiThread(STATE_SCREENSHOT_CAPTURED);
-        TraceHelper.INSTANCE.endSection(traceToken);
+        TraceHelper.INSTANCE.endSection();
     }
 
     private void finishCurrentTransitionToRecents() {
diff --git a/quickstep/src/com/android/quickstep/BinderTracker.java b/quickstep/src/com/android/quickstep/BinderTracker.java
new file mode 100644
index 0000000..a876cd8
--- /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;
+        }
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/InstantAppResolverImpl.java b/quickstep/src/com/android/quickstep/InstantAppResolverImpl.java
index 7638541..529213c 100644
--- a/quickstep/src/com/android/quickstep/InstantAppResolverImpl.java
+++ b/quickstep/src/com/android/quickstep/InstantAppResolverImpl.java
@@ -16,10 +16,13 @@
 
 package com.android.quickstep;
 
+import android.app.ActivityThread;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.os.RemoteException;
+import android.util.Log;
 
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.util.InstantAppResolver;
@@ -49,4 +52,14 @@
         ComponentName cn = info.getTargetComponent();
         return cn != null && cn.getClassName().equals(COMPONENT_CLASS_MARKER);
     }
+
+    @Override
+    public boolean isInstantApp(String packageName, int userId) {
+        try {
+            return ActivityThread.getPackageManager().isInstantApp(packageName, userId);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to determine whether package is instant app " + packageName, e);
+            return false;
+        }
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java b/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
index 5f589bf..128b045 100644
--- a/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
+++ b/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
@@ -60,5 +60,10 @@
         // Elevate GPU priority for Quickstep and Remote animations.
         ThreadedRenderer.setContextPriority(
                 ThreadedRenderer.EGL_CONTEXT_PRIORITY_HIGH_IMG);
+
+        if (BuildConfig.IS_STUDIO_BUILD) {
+            BinderTracker.startTracking(call ->  Log.e("BinderCall",
+                    call.descriptor + " called on mainthread under " + call.activeTrace));
+        }
     }
 }
diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
index 8135238..810c028 100644
--- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
@@ -393,11 +393,12 @@
         @Override
         public List<SystemShortcut> getShortcuts(BaseDraggingActivity activity,
                 TaskIdAttributeContainer taskContainer) {
-            return InstantAppResolver.newInstance(activity).isInstantApp(activity,
-                    taskContainer.getTask().getTopComponent().getPackageName()) ?
-                    Collections.singletonList(new SystemShortcut.Install(activity,
-                            taskContainer.getItemInfo(), taskContainer.getTaskView())) :
-                    null;
+            Task t = taskContainer.getTask();
+            return InstantAppResolver.newInstance(activity).isInstantApp(
+                    t.getTopComponent().getPackageName(), t.getKey().userId)
+                    ? Collections.singletonList(new SystemShortcut.Install(activity,
+                            taskContainer.getItemInfo(), taskContainer.getTaskView()))
+                    : null;
         }
     };
 
diff --git a/quickstep/src/com/android/quickstep/TaskUtils.java b/quickstep/src/com/android/quickstep/TaskUtils.java
index 67360c4..80a449b 100644
--- a/quickstep/src/com/android/quickstep/TaskUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskUtils.java
@@ -33,6 +33,7 @@
 import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.PackageManagerHelper;
+import com.android.launcher3.util.TraceHelper;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 
@@ -51,7 +52,8 @@
      * TODO: remove this once we switch to getting the icon and label from IconCache.
      */
     public static CharSequence getTitle(Context context, Task task) {
-        return getTitle(context, task.key.userId, task.getTopComponent().getPackageName());
+        return TraceHelper.allowIpcs("TaskUtils.getTitle", () ->
+                getTitle(context, task.key.userId, task.getTopComponent().getPackageName()));
     }
 
     public static CharSequence getTitle(
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 8d05fa9..a060c7c 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -102,6 +102,7 @@
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.LockedUserState;
 import com.android.launcher3.util.OnboardingPrefs;
+import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.util.TraceHelper;
 import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
 import com.android.quickstep.inputconsumers.AssistantInputConsumer;
@@ -654,8 +655,7 @@
             return;
         }
 
-        Object traceToken = TraceHelper.INSTANCE.beginFlagsOverride(
-                TraceHelper.FLAG_ALLOW_BINDER_TRACKING);
+        SafeCloseable traceToken = TraceHelper.INSTANCE.allowIpcs("TIS.onInputEvent");
 
         final int action = event.getActionMasked();
         // Note this will create a new consumer every mouse click, as after ACTION_UP from the click
@@ -751,7 +751,7 @@
         if (cleanUpConsumer) {
             reset();
         }
-        TraceHelper.INSTANCE.endFlagsOverride(traceToken);
+        traceToken.close();
         ProtoTracer.INSTANCE.get(this).scheduleFrameUpdate();
     }
 
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index 5b27f9b..10c6316 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -28,7 +28,6 @@
 import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
 import static com.android.launcher3.Utilities.squaredHypot;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import static com.android.launcher3.util.TraceHelper.FLAG_CHECK_FOR_RACE_CONDITIONS;
 import static com.android.launcher3.util.VelocityUtils.PX_PER_MS;
 import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID;
 
@@ -229,8 +228,7 @@
                 // Until we detect the gesture, handle events as we receive them
                 mInputEventReceiver.setBatchingEnabled(false);
 
-                Object traceToken = TraceHelper.INSTANCE.beginSection(DOWN_EVT,
-                        FLAG_CHECK_FOR_RACE_CONDITIONS);
+                TraceHelper.INSTANCE.beginSection(DOWN_EVT);
                 mActivePointerId = ev.getPointerId(0);
                 mDownPos.set(ev.getX(), ev.getY());
                 mLastPos.set(mDownPos);
@@ -241,7 +239,7 @@
                     startTouchTrackingForWindowAnimation(ev.getEventTime());
                 }
 
-                TraceHelper.INSTANCE.endSection(traceToken);
+                TraceHelper.INSTANCE.endSection();
                 break;
             }
             case ACTION_POINTER_DOWN: {
@@ -417,8 +415,7 @@
      * the animation can still be running.
      */
     private void finishTouchTracking(MotionEvent ev) {
-        Object traceToken = TraceHelper.INSTANCE.beginSection(UP_EVT,
-                FLAG_CHECK_FOR_RACE_CONDITIONS);
+        TraceHelper.INSTANCE.beginSection(UP_EVT);
 
         if (mPassedWindowMoveSlop && mInteractionHandler != null) {
             if (ev.getActionMasked() == ACTION_CANCEL) {
@@ -455,7 +452,7 @@
             onInteractionGestureFinished();
         }
         cleanupAfterGesture();
-        TraceHelper.INSTANCE.endSection(traceToken);
+        TraceHelper.INSTANCE.endSection();
     }
 
     private void cleanupAfterGesture() {
diff --git a/quickstep/src/com/android/quickstep/util/BinderTracker.java b/quickstep/src/com/android/quickstep/util/BinderTracker.java
deleted file mode 100644
index cb04e5b..0000000
--- a/quickstep/src/com/android/quickstep/util/BinderTracker.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2019 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.util;
-
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.Looper;
-import android.util.Log;
-
-import com.android.launcher3.config.FeatureFlags;
-
-/**
- * Utility class to test and check binder calls during development.
- */
-public class BinderTracker {
-
-    private static final String TAG = "BinderTracker";
-
-    public static void start() {
-        if (!FeatureFlags.IS_STUDIO_BUILD) {
-            Log.wtf(TAG, "Accessing tracker in released code.", new Exception());
-            return;
-        }
-
-        Binder.setProxyTransactListener(new Tracker());
-    }
-
-    public static void stop() {
-        if (!FeatureFlags.IS_STUDIO_BUILD) {
-            Log.wtf(TAG, "Accessing tracker in released code.", new Exception());
-            return;
-        }
-        Binder.setProxyTransactListener(null);
-    }
-
-    private static class Tracker implements Binder.ProxyTransactListener {
-
-        @Override
-        public Object onTransactStarted(IBinder iBinder, int code) {
-            if (Looper.myLooper() == Looper.getMainLooper()) {
-                Log.e(TAG, "Binder call on ui thread", new Exception());
-            }
-            return null;
-        }
-
-        @Override
-        public void onTransactEnded(Object session) { }
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index f8893bd..7f035a2 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -112,8 +112,7 @@
         mContext = context;
         mSizeStrategy = sizeStrategy;
 
-        // TODO(b/187074722): Don't create this per-TaskViewSimulator
-        mOrientationState = TraceHelper.allowIpcs("",
+        mOrientationState = TraceHelper.allowIpcs("TaskViewSimulator.init",
                 () -> new RecentsOrientedState(context, sizeStrategy, i -> { }));
         mOrientationState.setGestureActive(true);
         mCurrentFullscreenParams = new FullscreenDrawParams(context);
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 200252a..46dd94b 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -32,6 +32,7 @@
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
 import static com.android.launcher3.util.SplitConfigurationOptions.getLogEventForPosition;
+import static com.android.quickstep.TaskOverlayFactory.getEnabledShortcuts;
 import static com.android.quickstep.util.BorderAnimator.DEFAULT_BORDER_COLOR;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -88,6 +89,7 @@
 import com.android.launcher3.util.RunnableList;
 import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
+import com.android.launcher3.util.TraceHelper;
 import com.android.launcher3.util.TransformingTouchDelegate;
 import com.android.launcher3.util.ViewPool.Reusable;
 import com.android.quickstep.RecentsModel;
@@ -1556,8 +1558,8 @@
             if (taskContainer == null) {
                 continue;
             }
-            for (SystemShortcut s : TaskOverlayFactory.getEnabledShortcuts(this,
-                    taskContainer)) {
+            for (SystemShortcut s : TraceHelper.allowIpcs(
+                    "TV.a11yInfo", () -> getEnabledShortcuts(this, taskContainer))) {
                 info.addAction(s.createAccessibilityAction(context));
             }
         }
@@ -1594,7 +1596,7 @@
             if (taskContainer == null) {
                 continue;
             }
-            for (SystemShortcut s : TaskOverlayFactory.getEnabledShortcuts(this,
+            for (SystemShortcut s : getEnabledShortcuts(this,
                     taskContainer)) {
                 if (s.hasHandlerForAction(action)) {
                     s.onClick(this);
diff --git a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
index df5303f..5127190 100644
--- a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
+++ b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
@@ -20,7 +20,6 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.launcher3.ui.TaplTestsLauncher3;
-import com.android.launcher3.util.RaceConditionReproducer;
 import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
 
 import org.junit.Before;
@@ -45,18 +44,6 @@
         startTestActivity(2);
     }
 
-    private void runTest(String... eventSequence) {
-        final RaceConditionReproducer eventProcessor = new RaceConditionReproducer(eventSequence);
-
-        // Destroy Launcher activity.
-        closeLauncherActivity();
-
-        // The test action.
-        eventProcessor.startIteration();
-        mLauncher.goHome();
-        eventProcessor.finishIteration();
-    }
-
     @Ignore
     @Test
     @NavigationModeSwitch
diff --git a/res/drawable/ic_wallpaper.xml b/res/drawable/ic_wallpaper.xml
deleted file mode 100644
index 9543f88..0000000
--- a/res/drawable/ic_wallpaper.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-   Copyright (C) 2016 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="@dimen/options_menu_icon_size"
-        android:height="@dimen/options_menu_icon_size"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/textColorPrimary">
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M9,12.71l2.14,2.58l3-3.87L18,16.57H6L9,12.71z M5,5h6V3H5C3.9,3,3,3.9,3,5v6h2V5z M19,19h-6v2h6c1.1,0,2-0.9,2-2v-6h-2V19z
-            M5,19v-6H3v6c0,1.1,0.9,2,2,2h6v-2H5z M19,5v6h2V5c0-1.1-0.9-2-2-2h-6v2H19z M16,9c0.55,0,1-0.45,1-1s-0.45-1-1-1
-            c-0.55,0-1,0.45-1,1S15.45,9,16,9z"/>
-</vector>
diff --git a/res/values/config.xml b/res/values/config.xml
index 5a6698b..83f840d 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -102,8 +102,6 @@
 
     <!-- Default packages -->
     <string name="wallpaper_picker_package" translatable="false"></string>
-    <string name="custom_activity_picker" translatable="false">
-        com.android.customization.picker.CustomizationPickerActivity</string>
     <string name="local_colors_extraction_class" translatable="false"></string>
     <string name="search_session_manager_class" translatable="false"></string>
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index c2eb373..1b46b4d 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -250,8 +250,6 @@
 
     <!-- Strings for the customization mode -->
     <!-- Text for wallpaper change button [CHAR LIMIT=30]-->
-    <string name="wallpaper_button_text">Wallpapers</string>
-    <!-- Text for wallpaper change button [CHAR LIMIT=30]-->
     <string name="styles_wallpaper_button_text">Wallpaper &amp; style</string>
     <!-- Text for edit home screen button [CHAR LIMIT=30]-->
     <string name="edit_home_screen">Edit Home Screen</string>
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index db5a27a..ac46c82 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -442,8 +442,7 @@
             Trace.beginAsyncSection(DISPLAY_ALL_APPS_TRACE_METHOD_NAME,
                     DISPLAY_ALL_APPS_TRACE_COOKIE);
         }
-        Object traceToken = TraceHelper.INSTANCE.beginSection(ON_CREATE_EVT,
-                TraceHelper.FLAG_UI_EVENT);
+        TraceHelper.INSTANCE.beginSection(ON_CREATE_EVT);
         if (DEBUG_STRICT_MODE) {
             StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                     .detectDiskReads()
@@ -576,7 +575,7 @@
                 LauncherOverlayPlugin.class, false /* allowedMultiple */);
 
         mRotationHelper.initialize();
-        TraceHelper.INSTANCE.endSection(traceToken);
+        TraceHelper.INSTANCE.endSection();
 
         mUserChangedCallbackCloseable = UserCache.INSTANCE.get(this).addUserChangeListener(
                 () -> getStateManager().goToState(NORMAL));
@@ -1074,15 +1073,14 @@
 
     @Override
     protected void onStart() {
-        Object traceToken = TraceHelper.INSTANCE.beginSection(ON_START_EVT,
-                TraceHelper.FLAG_UI_EVENT);
+        TraceHelper.INSTANCE.beginSection(ON_START_EVT);
         super.onStart();
         if (!mDeferOverlayCallbacks) {
             mOverlayManager.onActivityStarted(this);
         }
 
         mAppWidgetHolder.setActivityStarted(true);
-        TraceHelper.INSTANCE.endSection(traceToken);
+        TraceHelper.INSTANCE.endSection();
     }
 
     @Override
@@ -1253,8 +1251,7 @@
 
     @Override
     protected void onResume() {
-        Object traceToken = TraceHelper.INSTANCE.beginSection(ON_RESUME_EVT,
-                TraceHelper.FLAG_UI_EVENT);
+        TraceHelper.INSTANCE.beginSection(ON_RESUME_EVT);
         super.onResume();
 
         if (mDeferOverlayCallbacks) {
@@ -1264,7 +1261,7 @@
         }
 
         DragView.removeAllViews(this);
-        TraceHelper.INSTANCE.endSection(traceToken);
+        TraceHelper.INSTANCE.endSection();
     }
 
     @Override
@@ -1652,7 +1649,7 @@
         if (Utilities.isRunningInTestHarness()) {
             Log.d(TestProtocol.PERMANENT_DIAG_TAG, "Launcher.onNewIntent: " + intent);
         }
-        Object traceToken = TraceHelper.INSTANCE.beginSection(ON_NEW_INTENT_EVT);
+        TraceHelper.INSTANCE.beginSection(ON_NEW_INTENT_EVT);
         super.onNewIntent(intent);
 
         boolean alreadyOnHome = hasWindowFocus() && ((intent.getFlags() &
@@ -1699,7 +1696,7 @@
             showAllAppsWorkTabFromIntent(alreadyOnHome);
         }
 
-        TraceHelper.INSTANCE.endSection(traceToken);
+        TraceHelper.INSTANCE.endSection();
     }
 
     protected void toggleAllAppsFromIntent(boolean alreadyOnHome) {
@@ -2298,7 +2295,7 @@
      * Implementation of the method from LauncherModel.Callbacks.
      */
     public void startBinding() {
-        Object traceToken = TraceHelper.INSTANCE.beginSection("startBinding");
+        TraceHelper.INSTANCE.beginSection("startBinding");
         // Floating panels (except the full widget sheet) are associated with individual icons. If
         // we are starting a fresh bind, close all such panels as all the icons are about
         // to go away.
@@ -2316,7 +2313,7 @@
         if (mHotseat != null) {
             mHotseat.resetLayout(getDeviceProfile().isVerticalBarLayout());
         }
-        TraceHelper.INSTANCE.endSection(traceToken);
+        TraceHelper.INSTANCE.endSection();
     }
 
     @Override
@@ -2569,7 +2566,7 @@
             return view;
         }
 
-        Object traceToken = TraceHelper.INSTANCE.beginSection("BIND_WIDGET_id=" + item.appWidgetId);
+        TraceHelper.INSTANCE.beginSection("BIND_WIDGET_id=" + item.appWidgetId);
 
         try {
             final LauncherAppWidgetProviderInfo appWidgetInfo;
@@ -2699,7 +2696,7 @@
             }
             prepareAppWidget(view, item);
         } finally {
-            TraceHelper.INSTANCE.endSection(traceToken);
+            TraceHelper.INSTANCE.endSection();
         }
 
         return view;
@@ -2792,7 +2789,7 @@
      * Implementation of the method from LauncherModel.Callbacks.
      */
     public void finishBindingItems(IntSet pagesBoundFirst) {
-        Object traceToken = TraceHelper.INSTANCE.beginSection("finishBindingItems");
+        TraceHelper.INSTANCE.beginSection("finishBindingItems");
         mWorkspace.restoreInstanceStateForRemainingPages();
 
         setWorkspaceLoading(false);
@@ -2817,7 +2814,7 @@
                 mDeviceProfile.inv.numFolderColumns * mDeviceProfile.inv.numFolderRows);
         getViewCache().setCacheSize(R.layout.folder_page, 2);
 
-        TraceHelper.INSTANCE.endSection(traceToken);
+        TraceHelper.INSTANCE.endSection();
 
         mWorkspace.removeExtraEmptyScreen(true);
     }
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index d2a8174..73a06b6 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -201,7 +201,7 @@
             }
         }
 
-        Object traceToken = TraceHelper.INSTANCE.beginSection(TAG);
+        TraceHelper.INSTANCE.beginSection(TAG);
         LoaderMemoryLogger memoryLogger = new LoaderMemoryLogger();
         try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
             List<ShortcutInfo> allShortcuts = new ArrayList<>();
@@ -325,7 +325,7 @@
             memoryLogger.printLogs();
             throw e;
         }
-        TraceHelper.INSTANCE.endSection(traceToken);
+        TraceHelper.INSTANCE.endSection();
     }
 
     public synchronized void stopLocked() {
diff --git a/src/com/android/launcher3/util/InstantAppResolver.java b/src/com/android/launcher3/util/InstantAppResolver.java
index 6f706d2..bdb5e77 100644
--- a/src/com/android/launcher3/util/InstantAppResolver.java
+++ b/src/com/android/launcher3/util/InstantAppResolver.java
@@ -42,14 +42,7 @@
         return false;
     }
 
-    public boolean isInstantApp(Context context, String packageName) {
-        PackageManager packageManager = context.getPackageManager();
-        try {
-            return isInstantApp(packageManager.getPackageInfo(packageName, 0).applicationInfo);
-        } catch (PackageManager.NameNotFoundException e) {
-            Log.e("InstantAppResolver", "Failed to determine whether package is instant app "
-                    + packageName, e);
-        }
+    public boolean isInstantApp(String packageName, int userId) {
         return false;
     }
 }
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index 1d6bc25..91203a7 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -164,13 +164,6 @@
         }
     }
 
-    public static Intent getStyleWallpapersIntent(Context context) {
-        return new Intent(Intent.ACTION_SET_WALLPAPER).setComponent(
-                new ComponentName(context.getString(R.string.wallpaper_picker_package),
-                    context.getString(R.string.custom_activity_picker)
-                ));
-    }
-
     /**
      * Starts the details activity for {@code info}
      */
diff --git a/src/com/android/launcher3/util/TraceHelper.java b/src/com/android/launcher3/util/TraceHelper.java
index c23df77..d5056ee 100644
--- a/src/com/android/launcher3/util/TraceHelper.java
+++ b/src/com/android/launcher3/util/TraceHelper.java
@@ -21,6 +21,8 @@
 
 import java.util.function.Supplier;
 
+import kotlin.random.Random;
+
 /**
  * A wrapper around {@link Trace} to allow better testing.
  *
@@ -36,54 +38,53 @@
     // Temporarily ignore blocking binder calls for this trace.
     public static final int FLAG_IGNORE_BINDERS = 1 << 1;
 
-    public static final int FLAG_CHECK_FOR_RACE_CONDITIONS = 1 << 2;
-
-    public static final int FLAG_UI_EVENT =
-            FLAG_ALLOW_BINDER_TRACKING | FLAG_CHECK_FOR_RACE_CONDITIONS;
-
     /**
      * Static instance of Trace helper, overridden in tests.
      */
     public static TraceHelper INSTANCE = new TraceHelper();
 
     /**
-     * @return a token to pass into {@link #endSection(Object)}.
+     * @see Trace#beginSection(String)
      */
-    public Object beginSection(String sectionName) {
-        return beginSection(sectionName, 0);
-    }
-
-    public Object beginSection(String sectionName, int flags) {
+    public void beginSection(String sectionName) {
         Trace.beginSection(sectionName);
-        return null;
     }
 
     /**
-     * @param token the token returned from {@link #beginSection(String, int)}
+     * @see Trace#endSection()
      */
-    public void endSection(Object token) {
+    public void endSection() {
         Trace.endSection();
     }
 
     /**
-     * Similar to {@link #beginSection} but doesn't add a trace section.
+     * @see Trace#beginAsyncSection(String, int)
+     * @return a SafeCloseable that can be used to end the session
      */
-    public Object beginFlagsOverride(int flags) {
-        return null;
+    public SafeCloseable beginAsyncSection(String sectionName) {
+        int cookie = Random.Default.nextInt();
+        Trace.beginAsyncSection(sectionName, cookie);
+        return () -> Trace.endAsyncSection(sectionName, cookie);
     }
 
-    public void endFlagsOverride(Object token) { }
+    /**
+     * Returns a SafeCloseable to temporarily ignore blocking binder calls.
+     */
+    public SafeCloseable allowIpcs(String rpcName) {
+        int cookie = Random.Default.nextInt();
+        Trace.beginAsyncSection(rpcName, cookie);
+        return () -> Trace.endAsyncSection(rpcName, cookie);
+    }
 
     /**
      * Temporarily ignore blocking binder calls for the duration of this {@link Supplier}.
+     *
+     * Note, new features should be designed to not rely on mainThread RPCs.
      */
     @MainThread
     public static <T> T allowIpcs(String rpcName, Supplier<T> supplier) {
-        Object traceToken = INSTANCE.beginSection(rpcName, FLAG_IGNORE_BINDERS);
-        try {
+        try (SafeCloseable c = INSTANCE.allowIpcs(rpcName)) {
             return supplier.get();
-        } finally {
-            INSTANCE.endSection(traceToken);
         }
     }
 }
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index aebf752..55febc7 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -55,7 +55,6 @@
 import com.android.launcher3.shortcuts.DeepShortcutView;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
-import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.widget.picker.WidgetsFullSheet;
 
 import java.util.ArrayList;
@@ -190,14 +189,9 @@
      */
     public static ArrayList<OptionItem> getOptions(Launcher launcher) {
         ArrayList<OptionItem> options = new ArrayList<>();
-        boolean styleWallpaperExists = styleWallpapersExists(launcher);
-        int resString = styleWallpaperExists
-                ? R.string.styles_wallpaper_button_text : R.string.wallpaper_button_text;
-        int resDrawable = styleWallpaperExists
-                ? R.drawable.ic_palette : R.drawable.ic_wallpaper;
         options.add(new OptionItem(launcher,
-                resString,
-                resDrawable,
+                R.string.styles_wallpaper_button_text,
+                R.drawable.ic_palette,
                 IGNORE,
                 OptionsPopupView::startWallpaperPicker));
         if (!WidgetsModel.GO_DISABLE_WIDGETS) {
@@ -274,12 +268,8 @@
                 .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
                 .putExtra(EXTRA_WALLPAPER_OFFSET,
                         launcher.getWorkspace().getWallpaperOffsetForCenterPage())
-                .putExtra(EXTRA_WALLPAPER_LAUNCH_SOURCE, "app_launched_launcher");
-        if (!styleWallpapersExists(launcher)) {
-            intent.putExtra(EXTRA_WALLPAPER_FLAVOR, "wallpaper_only");
-        } else {
-            intent.putExtra(EXTRA_WALLPAPER_FLAVOR, "focus_wallpaper");
-        }
+                .putExtra(EXTRA_WALLPAPER_LAUNCH_SOURCE, "app_launched_launcher")
+                .putExtra(EXTRA_WALLPAPER_FLAVOR, "focus_wallpaper");
         String pickerPackage = launcher.getString(R.string.wallpaper_picker_package);
         if (!TextUtils.isEmpty(pickerPackage)) {
             intent.setPackage(pickerPackage);
@@ -322,9 +312,4 @@
             this.clickListener = clickListener;
         }
     }
-
-    private static boolean styleWallpapersExists(Context context) {
-        return context.getPackageManager().resolveActivity(
-                PackageManagerHelper.getStyleWallpapersIntent(context), 0) != null;
-    }
 }
diff --git a/tests/src/com/android/launcher3/util/RaceConditionReproducer.java b/tests/src/com/android/launcher3/util/RaceConditionReproducer.java
deleted file mode 100644
index ed2ec7b..0000000
--- a/tests/src/com/android/launcher3/util/RaceConditionReproducer.java
+++ /dev/null
@@ -1,500 +0,0 @@
-/*
- * Copyright (C) 2018 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.launcher3.util;
-
-import static com.android.launcher3.util.Executors.createAndStartNewLooper;
-
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.os.Handler;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Event processor for reliably reproducing multithreaded apps race conditions in tests.
- *
- * The app notifies us about “events” that happen in its threads. The race condition test runs the
- * test action multiple times (aka iterations), trying to generate all possible permutations of
- * these events. It keeps a set of all seen event sequences and steers the execution towards
- * executing events in previously unseen order. It does it by postponing execution of threads that
- * would lead to an already seen sequence.
- *
- * If an event A occurs before event B in the sequence, this is how execution order looks like:
- * Events: ... A ... B ...
- * Events and instructions, guaranteed order:
- * (instructions executed prior to A) A ... B (instructions executed after B)
- *
- * Each iteration has 3 parts (phases).
- * Phase 1. Picking a previously seen event subsequence that we believe can have previously unseen
- * continuations. Reproducing this sequence by pausing threads that would lead to other sequences.
- * Phase 2. Trying to generate previously unseen continuation of the sequence from Phase 1. We need
- * one new event after that sequence. All threads leading to seen continuations will be postponed
- * for some short period of time. The phase ends once the new event is registered, or after the
- * period of time ends (in which case we declare that the sequence can’t have new continuations).
- * Phase 3. Releasing all threads and letting the test iteration run till its end.
- *
- * The iterations end when all seen paths have been declared “uncontinuable”.
- *
- * When we register event XXX:enter, we hold all other events until we register XXX:exit.
- */
-public class RaceConditionReproducer {
-    private static final String TAG = "RaceConditionReproducer";
-
-    private static final boolean ENTER = true;
-    private static final boolean EXIT = false;
-    private static final String ENTER_POSTFIX = "enter";
-    private static final String EXIT_POSTFIX = "exit";
-
-    private static final long SHORT_TIMEOUT_MS = 2000;
-    private static final long LONG_TIMEOUT_MS = 60000;
-    // Handler used to resume postponed events.
-    private static final Handler POSTPONED_EVENT_RESUME_HANDLER =
-            new Handler(createAndStartNewLooper("RaceConditionEventResumer"));
-
-    public static String enterExitEvt(String eventName, boolean isEnter) {
-        return eventName + ":" + (isEnter ? ENTER_POSTFIX : EXIT_POSTFIX);
-    }
-
-    public static String enterEvt(String eventName) {
-        return enterExitEvt(eventName, ENTER);
-    }
-
-    public static String exitEvt(String eventName) {
-        return enterExitEvt(eventName, EXIT);
-    }
-
-    /**
-     * Event in a particular sequence of events. A node in the prefix tree of all seen event
-     * sequences.
-     */
-    private class EventNode {
-        // Events that were seen just after this event.
-        private final Map<String, EventNode> mNextEvents = new HashMap<>();
-        // Whether we believe that further iterations will not be able to add more events to
-        // mNextEvents.
-        private boolean mStoppedAddingChildren = true;
-
-        private void debugDump(StringBuilder sb, int indent, String name) {
-            for (int i = 0; i < indent; ++i) sb.append('.');
-            sb.append(!mStoppedAddingChildren ? "+" : "-");
-            sb.append(" : ");
-            sb.append(name);
-            if (mLastRegisteredEvent == this) sb.append(" <");
-            sb.append('\n');
-
-            for (String key : mNextEvents.keySet()) {
-                mNextEvents.get(key).debugDump(sb, indent + 2, key);
-            }
-        }
-
-        /** Number of leaves in the subtree with this node as a root. */
-        private int numberOfLeafNodes() {
-            if (mNextEvents.isEmpty()) return 1;
-
-            int leaves = 0;
-            for (String event : mNextEvents.keySet()) {
-                leaves += mNextEvents.get(event).numberOfLeafNodes();
-            }
-            return leaves;
-        }
-
-        /**
-         * Whether we believe that further iterations will not be able add nodes to the subtree with
-         * this node as a root.
-         */
-        private boolean stoppedAddingChildrenToTree() {
-            if (!mStoppedAddingChildren) return false;
-
-            for (String event : mNextEvents.keySet()) {
-                if (!mNextEvents.get(event).stoppedAddingChildrenToTree()) return false;
-            }
-            return true;
-        }
-
-        /**
-         * In the subtree with this node as a root, tries finding a node where we may have a
-         * chance to add new children.
-         * If succeeds, returns true and fills 'path' with the sequence of events to that node;
-         * otherwise returns false.
-         */
-        private boolean populatePathToGrowthPoint(List<String> path) {
-            for (String event : mNextEvents.keySet()) {
-                if (mNextEvents.get(event).populatePathToGrowthPoint(path)) {
-                    path.add(0, event);
-                    return true;
-                }
-            }
-            if (!mStoppedAddingChildren) {
-                // Mark that we have finished adding children. It will remain true if no new
-                // children are added, or will be set to false upon adding a new child.
-                mStoppedAddingChildren = true;
-                return true;
-            }
-            return false;
-        }
-    }
-
-    // Starting point of all event sequences; the root of the prefix tree representation all
-    // sequences generated by test iterations. A test iteration can add nodes int it.
-    private EventNode mRoot = new EventNode();
-    // During a test iteration, the last event that was registered.
-    private EventNode mLastRegisteredEvent;
-    // Length of the current sequence of registered events for the current test iteration.
-    private int mRegisteredEventCount = 0;
-    // During the first part of a test iteration, we go to a specific node under mRoot by
-    // 'playing back' mSequenceToFollow. During this part, all events that don't belong to this
-    // sequence get postponed.
-    private List<String> mSequenceToFollow = new ArrayList<>();
-    // Collection of events that got postponed, with corresponding wait objects used to let them go.
-    private Map<String, Semaphore> mPostponedEvents = new HashMap<>();
-    // Callback to run by POSTPONED_EVENT_RESUME_HANDLER, used to let go of all currently
-    // postponed events.
-    private Runnable mResumeAllEventsCallback;
-    // String representation of the sequence of events registered so far for the current test
-    // iteration. After registering any event, we output it to the log. The last output before
-    // the test failure can be later played back to reliable reproduce the exact sequence of
-    // events that broke the test.
-    // Format: EV1|EV2|...\EVN
-    private StringBuilder mCurrentSequence;
-    // When not null, we are in a repro mode. We run only one test iteration, and are trying to
-    // reproduce the event sequence represented by this string. The format is same as for
-    // mCurrentSequence.
-    private final String mReproString;
-
-    /* Constructor for a normal test. */
-    public RaceConditionReproducer() {
-        mReproString = null;
-    }
-
-    /**
-     * Constructor for reliably reproducing a race condition failure. The developer should find in
-     * the log the latest "Repro sequence:" record and locally modify the test by passing that
-     * string to the constructor. Running the test will have only one iteration that will reliably
-     * "play back" that sequence.
-     */
-    public RaceConditionReproducer(String reproString) {
-        mReproString = reproString;
-    }
-
-    public RaceConditionReproducer(String... reproSequence) {
-        this(String.join("|", reproSequence));
-    }
-
-    public synchronized String getCurrentSequenceString() {
-        return mCurrentSequence.toString();
-    }
-
-    /**
-     * Starts a new test iteration. Events reported via RaceConditionTracker.onEvent before this
-     * call will be ignored.
-     */
-    public synchronized void startIteration() {
-        mLastRegisteredEvent = mRoot;
-        mRegisteredEventCount = 0;
-        mCurrentSequence = new StringBuilder();
-        Log.d(TAG, "Repro sequence: " + mCurrentSequence);
-        mSequenceToFollow = mReproString != null ?
-                parseReproString(mReproString) : generateSequenceToFollowLocked();
-        Log.e(TAG, "---- Start of iteration; state:\n" + dumpStateLocked());
-        checkIfCompletedSequenceToFollowLocked();
-
-        TraceHelperForTest.setRaceConditionReproducer(this);
-    }
-
-    /**
-     * Ends a new test iteration. Events reported via RaceConditionTracker.onEvent after this call
-     * will be ignored.
-     * Returns whether we need more iterations.
-     */
-    public synchronized boolean finishIteration() {
-        TraceHelperForTest.setRaceConditionReproducer(null);
-
-        runResumeAllEventsCallbackLocked();
-        assertTrue("Non-empty postponed events", mPostponedEvents.isEmpty());
-        assertTrue("Last registered event is :enter", lastEventAsEnter() == null);
-
-        // No events came after mLastRegisteredEvent. It doesn't make sense to come to it again
-        // because we won't see new continuations.
-        mLastRegisteredEvent.mStoppedAddingChildren = true;
-        Log.e(TAG, "---- End of iteration; state:\n" + dumpStateLocked());
-        if (mReproString != null) {
-            assertTrue("Repro mode: failed to reproduce the sequence",
-                    mCurrentSequence.toString().startsWith(mReproString));
-        }
-        // If we are in a repro mode, we need only one iteration. Otherwise, continue if the tree
-        // has prospective growth points.
-        return mReproString == null && !mRoot.stoppedAddingChildrenToTree();
-    }
-
-    private static List<String> parseReproString(String reproString) {
-        return Arrays.asList(reproString.split("\\|"));
-    }
-
-    /**
-     * Called when the app issues an event.
-     */
-    public void onEvent(String event) {
-        final Semaphore waitObject = tryRegisterEvent(event);
-        if (waitObject != null) {
-            waitUntilCanRegister(event, waitObject);
-        }
-    }
-
-    /**
-     * Returns whether the last event was not an XXX:enter, or this event is a matching XXX:exit.
-     */
-    private boolean canRegisterEventNowLocked(String event) {
-        final String lastEventAsEnter = lastEventAsEnter();
-        final String thisEventAsExit = eventAsExit(event);
-
-        if (lastEventAsEnter != null) {
-            if (!lastEventAsEnter.equals(thisEventAsExit)) {
-                assertTrue("YYY:exit after XXX:enter", thisEventAsExit == null);
-                // Last event was :enter, but this event is not :exit.
-                return false;
-            }
-        } else {
-            // Previous event was not :enter.
-            assertTrue(":exit after a non-enter event", thisEventAsExit == null);
-        }
-        return true;
-    }
-
-    /**
-     * Registers an event issued by the app and returns null or decides that the event must be
-     * postponed, and returns an object to wait on.
-     */
-    private synchronized Semaphore tryRegisterEvent(String event) {
-        Log.d(TAG, "Event issued by the app: " + event);
-
-        if (!canRegisterEventNowLocked(event)) {
-            return createWaitObjectForPostponedEventLocked(event);
-        }
-
-        if (mRegisteredEventCount < mSequenceToFollow.size()) {
-            // We are in the first part of the iteration. We only register events that follow the
-            // mSequenceToFollow and postponing all other events.
-            if (event.equals(mSequenceToFollow.get(mRegisteredEventCount))) {
-                // The event is the next one expected in the sequence. Register it.
-                registerEventLocked(event);
-
-                // If there are postponed events that could continue the sequence, register them.
-                while (mRegisteredEventCount < mSequenceToFollow.size() &&
-                        mPostponedEvents.containsKey(
-                                mSequenceToFollow.get(mRegisteredEventCount))) {
-                    registerPostponedEventLocked(mSequenceToFollow.get(mRegisteredEventCount));
-                }
-
-                // Perhaps we just completed the required sequence...
-                checkIfCompletedSequenceToFollowLocked();
-            } else {
-                // The event is not the next one in the sequence. Postpone it.
-                return createWaitObjectForPostponedEventLocked(event);
-            }
-        } else if (mRegisteredEventCount == mSequenceToFollow.size()) {
-            // The second phase of the iteration. We have just registered the whole
-            // mSequenceToFollow, and want to add previously not seen continuations for the last
-            // node in the sequence aka 'growth point'.
-            if (!mLastRegisteredEvent.mNextEvents.containsKey(event) || mReproString != null) {
-                // The event was never seen as a continuation for the current node.
-                // Or we are in repro mode, in which case we are not in business of generating
-                // new sequences after we've played back the required sequence.
-                // Register it immediately.
-                registerEventLocked(event);
-            } else {
-                // The event was seen as a continuation for the current node. Postpone it, hoping
-                // that a new event will come from other threads.
-                return createWaitObjectForPostponedEventLocked(event);
-            }
-        } else {
-            // The third phase of the iteration. We are past the growth point and register
-            // everything that comes.
-            registerEventLocked(event);
-            // Register events that may have been postponed while waiting for an :exit event
-            // during the third phase. We don't do this if just registered event is :enter.
-            if (eventAsEnter(event) == null && mRegisteredEventCount > mSequenceToFollow.size()) {
-                registerPostponedEventsLocked(new HashSet<>(mPostponedEvents.keySet()));
-            }
-        }
-        return null;
-    }
-
-    /** Called when there are chances that we just have registered the whole mSequenceToFollow. */
-    private void checkIfCompletedSequenceToFollowLocked() {
-        if (mRegisteredEventCount == mSequenceToFollow.size()) {
-            // We just entered the second phase of the iteration. We have just registered the
-            // whole mSequenceToFollow, and want to add previously not seen continuations for the
-            // last node in the sequence aka 'growth point'. All seen continuations will be
-            // postponed for SHORT_TIMEOUT_MS. At the end of this time period, we'll let them go.
-            scheduleResumeAllEventsLocked();
-
-            // Among the events that were postponed during the first stage, there may be an event
-            // that wasn't seen after the current. If so, register it immediately because this
-            // creates a new sequence.
-            final Set<String> keys = new HashSet<>(mPostponedEvents.keySet());
-            keys.removeAll(mLastRegisteredEvent.mNextEvents.keySet());
-            if (!keys.isEmpty()) {
-                registerPostponedEventLocked(keys.iterator().next());
-            }
-        }
-    }
-
-    private Semaphore createWaitObjectForPostponedEventLocked(String event) {
-        final Semaphore waitObject = new Semaphore(0);
-        assertTrue("Event already postponed: " + event, !mPostponedEvents.containsKey(event));
-        mPostponedEvents.put(event, waitObject);
-        return waitObject;
-    }
-
-    private void waitUntilCanRegister(String event, Semaphore waitObject) {
-        try {
-            assertTrue("Never registered event: " + event,
-                    waitObject.tryAcquire(LONG_TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        } catch (InterruptedException e) {
-            fail("Wait was interrupted");
-        }
-    }
-
-    /** Schedules resuming all postponed events after SHORT_TIMEOUT_MS */
-    private void scheduleResumeAllEventsLocked() {
-        assertTrue(mResumeAllEventsCallback == null);
-        mResumeAllEventsCallback = this::allEventsResumeCallback;
-        POSTPONED_EVENT_RESUME_HANDLER.postDelayed(mResumeAllEventsCallback, SHORT_TIMEOUT_MS);
-    }
-
-    private synchronized void allEventsResumeCallback() {
-        assertTrue("In callback, but callback is not set", mResumeAllEventsCallback != null);
-        mResumeAllEventsCallback = null;
-        registerPostponedEventsLocked(new HashSet<>(mPostponedEvents.keySet()));
-    }
-
-    private void registerPostponedEventsLocked(Collection<String> events) {
-        for (String event : events) {
-            registerPostponedEventLocked(event);
-            if (eventAsEnter(event) != null) {
-                // Once :enter is registered, switch to waiting for :exit to come. Won't register
-                // other postponed events.
-                break;
-            }
-        }
-    }
-
-    private void registerPostponedEventLocked(String event) {
-        mPostponedEvents.remove(event).release();
-        registerEventLocked(event);
-    }
-
-    /**
-     * If the last registered event was XXX:enter, returns XXX, otherwise, null.
-     */
-    private String lastEventAsEnter() {
-        return eventAsEnter(mCurrentSequence.substring(mCurrentSequence.lastIndexOf("|") + 1));
-    }
-
-    /**
-     * If the event is XXX:postfix, returns XXX, otherwise, null.
-     */
-    private static String prefixFromPostfixedEvent(String event, String postfix) {
-        final int columnPos = event.indexOf(':');
-        if (columnPos != -1 && postfix.equals(event.substring(columnPos + 1))) {
-            return event.substring(0, columnPos);
-        }
-        return null;
-    }
-
-    /**
-     * If the event is XXX:enter, returns XXX, otherwise, null.
-     */
-    private static String eventAsEnter(String event) {
-        return prefixFromPostfixedEvent(event, ENTER_POSTFIX);
-    }
-
-    /**
-     * If the event is XXX:exit, returns XXX, otherwise, null.
-     */
-    private static String eventAsExit(String event) {
-        return prefixFromPostfixedEvent(event, EXIT_POSTFIX);
-    }
-
-    private void registerEventLocked(String event) {
-        assertTrue(canRegisterEventNowLocked(event));
-
-        Log.d(TAG, "Actually registering event: " + event);
-        EventNode next = mLastRegisteredEvent.mNextEvents.get(event);
-        if (next == null) {
-            // This event wasn't seen after mLastRegisteredEvent.
-            next = new EventNode();
-            mLastRegisteredEvent.mNextEvents.put(event, next);
-            // The fact that we've added a new event after the previous one means that the
-            // previous event is still a growth point, unless this event is :exit, which means
-            // that the previous event is :enter.
-            mLastRegisteredEvent.mStoppedAddingChildren = eventAsExit(event) != null;
-        }
-
-        mLastRegisteredEvent = next;
-        mRegisteredEventCount++;
-
-        if (mCurrentSequence.length() > 0) mCurrentSequence.append("|");
-        mCurrentSequence.append(event);
-        Log.d(TAG, "Repro sequence: " + mCurrentSequence);
-    }
-
-    private void runResumeAllEventsCallbackLocked() {
-        if (mResumeAllEventsCallback != null) {
-            POSTPONED_EVENT_RESUME_HANDLER.removeCallbacks(mResumeAllEventsCallback);
-            mResumeAllEventsCallback.run();
-        }
-    }
-
-    private CharSequence dumpStateLocked() {
-        StringBuilder sb = new StringBuilder();
-
-        sb.append("Sequence to follow: ");
-        for (String event : mSequenceToFollow) sb.append(" " + event);
-        sb.append(".\n");
-        sb.append("Registered event count: " + mRegisteredEventCount);
-
-        sb.append("\nPostponed events: ");
-        for (String event : mPostponedEvents.keySet()) sb.append(" " + event);
-        sb.append(".");
-
-        sb.append("\nNodes: \n");
-        mRoot.debugDump(sb, 0, "");
-        return sb;
-    }
-
-    public int numberOfLeafNodes() {
-        return mRoot.numberOfLeafNodes();
-    }
-
-    private List<String> generateSequenceToFollowLocked() {
-        ArrayList<String> sequence = new ArrayList<>();
-        mRoot.populatePathToGrowthPoint(sequence);
-        return sequence;
-    }
-}
diff --git a/tests/src/com/android/launcher3/util/RaceConditionReproducerTest.java b/tests/src/com/android/launcher3/util/RaceConditionReproducerTest.java
deleted file mode 100644
index 59f2173..0000000
--- a/tests/src/com/android/launcher3/util/RaceConditionReproducerTest.java
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (C) 2018 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.launcher3.util;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@LargeTest
-@RunWith(AndroidJUnit4.class)
-public class RaceConditionReproducerTest {
-    private final static String SOME_VALID_SEQUENCE_3_3 = "B1|A1|A2|B2|A3|B3";
-
-    private static int factorial(int n) {
-        int res = 1;
-        for (int i = 2; i <= n; ++i) res *= i;
-        return res;
-    }
-
-    RaceConditionReproducer eventProcessor;
-
-    @Before
-    public void setup() {
-        eventProcessor = new RaceConditionReproducer();
-    }
-
-    @After
-    public void tearDown() {
-        TraceHelperForTest.cleanup();
-    }
-
-    private void run3_3_TestAction() throws InterruptedException {
-        Thread tb = new Thread(() -> {
-            eventProcessor.onEvent("B1");
-            eventProcessor.onEvent("B2");
-            eventProcessor.onEvent("B3");
-        });
-        tb.start();
-
-        eventProcessor.onEvent("A1");
-        eventProcessor.onEvent("A2");
-        eventProcessor.onEvent("A3");
-
-        tb.join();
-    }
-
-    @Test
-    @Ignore // The test is too long for continuous testing.
-    // 2 threads, 3 events each.
-    public void test3_3() throws Exception {
-        boolean sawTheValidSequence = false;
-
-        for (; ; ) {
-            eventProcessor.startIteration();
-            run3_3_TestAction();
-            final boolean needMoreIterations = eventProcessor.finishIteration();
-
-            sawTheValidSequence = sawTheValidSequence ||
-                    SOME_VALID_SEQUENCE_3_3.equals(eventProcessor.getCurrentSequenceString());
-
-            if (!needMoreIterations) break;
-        }
-
-        assertEquals("Wrong number of leaf nodes",
-                factorial(3 + 3) / (factorial(3) * factorial(3)),
-                eventProcessor.numberOfLeafNodes());
-        assertTrue(sawTheValidSequence);
-    }
-
-    @Test
-    @Ignore // The test is too long for continuous testing.
-    // 2 threads, 3 events, including enter-exit pairs each.
-    public void test3_3_enter_exit() throws Exception {
-        boolean sawTheValidSequence = false;
-
-        for (; ; ) {
-            eventProcessor.startIteration();
-            Thread tb = new Thread(() -> {
-                eventProcessor.onEvent("B1:enter");
-                eventProcessor.onEvent("B1:exit");
-                eventProcessor.onEvent("B2");
-                eventProcessor.onEvent("B3:enter");
-                eventProcessor.onEvent("B3:exit");
-            });
-            tb.start();
-
-            eventProcessor.onEvent("A1");
-            eventProcessor.onEvent("A2:enter");
-            eventProcessor.onEvent("A2:exit");
-            eventProcessor.onEvent("A3:enter");
-            eventProcessor.onEvent("A3:exit");
-
-            tb.join();
-            final boolean needMoreIterations = eventProcessor.finishIteration();
-
-            sawTheValidSequence = sawTheValidSequence ||
-                    "B1:enter|B1:exit|A1|A2:enter|A2:exit|B2|A3:enter|A3:exit|B3:enter|B3:exit".
-                            equals(eventProcessor.getCurrentSequenceString());
-
-            if (!needMoreIterations) break;
-        }
-
-        assertEquals("Wrong number of leaf nodes",
-                factorial(3 + 3) / (factorial(3) * factorial(3)),
-                eventProcessor.numberOfLeafNodes());
-        assertTrue(sawTheValidSequence);
-    }
-
-    @Test
-    // 2 threads, 3 events each; reproducing a particular event sequence.
-    public void test3_3_ReproMode() throws Exception {
-        eventProcessor = new RaceConditionReproducer(SOME_VALID_SEQUENCE_3_3);
-        eventProcessor.startIteration();
-        run3_3_TestAction();
-        assertTrue(!eventProcessor.finishIteration());
-        assertEquals(SOME_VALID_SEQUENCE_3_3, eventProcessor.getCurrentSequenceString());
-
-        assertEquals("Wrong number of leaf nodes", 1, eventProcessor.numberOfLeafNodes());
-    }
-
-    @Test
-    @Ignore // The test is too long for continuous testing.
-    // 2 threads with 2 events; 1 thread with 1 event.
-    public void test2_1_2() throws Exception {
-        for (; ; ) {
-            eventProcessor.startIteration();
-            Thread tb = new Thread(() -> {
-                eventProcessor.onEvent("B1");
-                eventProcessor.onEvent("B2");
-            });
-            tb.start();
-
-            Thread tc = new Thread(() -> {
-                eventProcessor.onEvent("C1");
-            });
-            tc.start();
-
-            eventProcessor.onEvent("A1");
-            eventProcessor.onEvent("A2");
-
-            tb.join();
-            tc.join();
-
-            if (!eventProcessor.finishIteration()) break;
-        }
-
-        assertEquals("Wrong number of leaf nodes",
-                factorial(2 + 2 + 1) / (factorial(2) * factorial(2) * factorial(1)),
-                eventProcessor.numberOfLeafNodes());
-    }
-
-    @Test
-    @Ignore // The test is too long for continuous testing.
-    // 2 threads with 2 events; 1 thread with 1 event. Includes enter-exit pairs.
-    public void test2_1_2_enter_exit() throws Exception {
-        for (; ; ) {
-            eventProcessor.startIteration();
-            Thread tb = new Thread(() -> {
-                eventProcessor.onEvent("B1:enter");
-                eventProcessor.onEvent("B1:exit");
-                eventProcessor.onEvent("B2:enter");
-                eventProcessor.onEvent("B2:exit");
-            });
-            tb.start();
-
-            Thread tc = new Thread(() -> {
-                eventProcessor.onEvent("C1:enter");
-                eventProcessor.onEvent("C1:exit");
-            });
-            tc.start();
-
-            eventProcessor.onEvent("A1:enter");
-            eventProcessor.onEvent("A1:exit");
-            eventProcessor.onEvent("A2:enter");
-            eventProcessor.onEvent("A2:exit");
-
-            tb.join();
-            tc.join();
-
-            if (!eventProcessor.finishIteration()) break;
-        }
-
-        assertEquals("Wrong number of leaf nodes",
-                factorial(2 + 2 + 1) / (factorial(2) * factorial(2) * factorial(1)),
-                eventProcessor.numberOfLeafNodes());
-    }
-}
diff --git a/tests/src/com/android/launcher3/util/TraceHelperForTest.java b/tests/src/com/android/launcher3/util/TraceHelperForTest.java
deleted file mode 100644
index f1c8a67..0000000
--- a/tests/src/com/android/launcher3/util/TraceHelperForTest.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/**
- * Copyright (C) 2019 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.launcher3.util;
-
-import java.util.LinkedList;
-import java.util.function.IntConsumer;
-
-public class TraceHelperForTest extends TraceHelper {
-
-    private static final TraceHelperForTest INSTANCE_FOR_TEST = new TraceHelperForTest();
-
-    private final ThreadLocal<LinkedList<TraceInfo>> mStack =
-            ThreadLocal.withInitial(LinkedList::new);
-
-    private RaceConditionReproducer mRaceConditionReproducer;
-    private IntConsumer mFlagsChangeListener;
-
-    public static void setRaceConditionReproducer(RaceConditionReproducer reproducer) {
-        TraceHelper.INSTANCE = INSTANCE_FOR_TEST;
-        INSTANCE_FOR_TEST.mRaceConditionReproducer = reproducer;
-    }
-
-    public static void cleanup() {
-        INSTANCE_FOR_TEST.mRaceConditionReproducer = null;
-        INSTANCE_FOR_TEST.mFlagsChangeListener = null;
-    }
-
-    public static void setFlagsChangeListener(IntConsumer listener) {
-        TraceHelper.INSTANCE = INSTANCE_FOR_TEST;
-        INSTANCE_FOR_TEST.mFlagsChangeListener = listener;
-    }
-
-    private TraceHelperForTest() { }
-
-    @Override
-    public Object beginSection(String sectionName, int flags) {
-        LinkedList<TraceInfo> stack = mStack.get();
-        TraceInfo info = new TraceInfo(sectionName, flags);
-        stack.add(info);
-
-        if ((flags & TraceHelper.FLAG_CHECK_FOR_RACE_CONDITIONS) != 0
-                 && mRaceConditionReproducer != null) {
-            mRaceConditionReproducer.onEvent(RaceConditionReproducer.enterEvt(sectionName));
-        }
-        updateBinderTracking(stack);
-
-        super.beginSection(sectionName, flags);
-        return info;
-    }
-
-    @Override
-    public void endSection(Object token) {
-        LinkedList<TraceInfo> stack = mStack.get();
-        if (stack.size() == 0) {
-            new Throwable().printStackTrace();
-        }
-        TraceInfo info = (TraceInfo) token;
-        stack.remove(info);
-        if ((info.flags & TraceHelper.FLAG_CHECK_FOR_RACE_CONDITIONS) != 0
-                && mRaceConditionReproducer != null) {
-            mRaceConditionReproducer.onEvent(RaceConditionReproducer.exitEvt(info.sectionName));
-        }
-        updateBinderTracking(stack);
-
-        super.endSection(token);
-    }
-
-    @Override
-    public Object beginFlagsOverride(int flags) {
-        LinkedList<TraceInfo> stack = mStack.get();
-        TraceInfo info = new TraceInfo(null, flags);
-        stack.add(info);
-        updateBinderTracking(stack);
-        super.beginFlagsOverride(flags);
-        return info;
-    }
-
-    @Override
-    public void endFlagsOverride(Object token) {
-        super.endFlagsOverride(token);
-        LinkedList<TraceInfo> stack = mStack.get();
-        TraceInfo info = (TraceInfo) token;
-        stack.remove(info);
-        updateBinderTracking(stack);
-    }
-
-    private void updateBinderTracking(LinkedList<TraceInfo> stack) {
-        if (mFlagsChangeListener != null) {
-            mFlagsChangeListener.accept(stack.stream()
-                    .mapToInt(info -> info.flags).reduce(0, (a, b) -> a | b));
-        }
-    }
-
-    private static class TraceInfo {
-        public final String sectionName;
-        public final int flags;
-
-        TraceInfo(String sectionName, int flags) {
-            this.sectionName = sectionName;
-            this.flags = flags;
-        }
-    }
-}