diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java index 4b7ae6f426..d4e59c23d8 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -60,7 +60,7 @@ import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.model.AppLaunchTracker; import com.android.launcher3.provider.RestoreDbTask; import com.android.launcher3.testing.TestProtocol; -import com.android.launcher3.uioverrides.DejankBinderTracker; +import com.android.launcher3.util.TraceHelper; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener; import com.android.quickstep.inputconsumers.AccessibilityInputConsumer; @@ -401,7 +401,6 @@ public class TouchInteractionService extends Service implements } private void onInputEvent(InputEvent ev) { - DejankBinderTracker.allowBinderTrackingInTests(); if (TestProtocol.sDebugTracing) { Log.d(TestProtocol.NO_BACKGROUND_TO_OVERVIEW_TAG, "onInputEvent " + ev); } @@ -410,6 +409,7 @@ public class TouchInteractionService extends Service implements return; } + TraceHelper.INSTANCE.beginFlagsOverride(TraceHelper.FLAG_ALLOW_BINDER_TRACKING); MotionEvent event = (MotionEvent) ev; if (event.getAction() == ACTION_DOWN) { GestureState newGestureState = new GestureState( @@ -438,7 +438,7 @@ public class TouchInteractionService extends Service implements ActiveGestureLog.INSTANCE.addLog("onMotionEvent", event.getActionMasked()); mUncheckedConsumer.onMotionEvent(event); - DejankBinderTracker.disallowBinderTrackingInTests(); + TraceHelper.INSTANCE.endFlagsOverride(); } private InputConsumer newConsumer(GestureState gestureState, boolean useSharedState, @@ -490,7 +490,7 @@ public class TouchInteractionService extends Service implements private InputConsumer newBaseConsumer(GestureState gestureState, boolean useSharedState, MotionEvent event) { - RunningTaskInfo runningTaskInfo = DejankBinderTracker.whitelistIpcs( + RunningTaskInfo runningTaskInfo = TraceHelper.whitelistIpcs("getRunningTask.0", () -> mAM.getRunningTask(0)); if (!useSharedState) { sSwipeSharedState.clearAllState(false /* finishAnimation */); @@ -504,7 +504,8 @@ public class TouchInteractionService extends Service implements if (isExcludedAssistant(runningTaskInfo)) { // In the case where we are in the excluded assistant state, ignore it and treat the // running activity as the task behind the assistant - runningTaskInfo = DejankBinderTracker.whitelistIpcs( + + runningTaskInfo = TraceHelper.whitelistIpcs("getRunningTask.assistant", () -> mAM.getRunningTask(ACTIVITY_TYPE_ASSISTANT)); if (!ActivityManagerWrapper.isHomeTask(runningTaskInfo)) { final ComponentName homeComponent = diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java index e3b12cb79c..8dd1fffe96 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -23,8 +23,6 @@ import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2; import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS; import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs; -import static com.android.launcher3.util.RaceConditionTracker.ENTER; -import static com.android.launcher3.util.RaceConditionTracker.EXIT; import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW; import static com.android.quickstep.BaseActivityInterface.AnimationFactory.ShelfAnimState.HIDE; import static com.android.quickstep.BaseActivityInterface.AnimationFactory.ShelfAnimState.PEEK; @@ -65,11 +63,9 @@ import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.logging.UserEventDispatcher; -import com.android.launcher3.uioverrides.DejankBinderTracker; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; -import com.android.launcher3.util.RaceConditionTracker; import com.android.launcher3.util.TraceHelper; import com.android.quickstep.BaseActivityInterface.AnimationFactory; import com.android.quickstep.BaseActivityInterface.AnimationFactory.ShelfAnimState; @@ -371,13 +367,13 @@ public class WindowTransformSwipeHandler if (mWasLauncherAlreadyVisible) { mStateCallback.setState(STATE_LAUNCHER_DRAWN); } else { - TraceHelper.beginSection("WTS-init"); + TraceHelper.INSTANCE.beginSection("WTS-init"); View dragLayer = activity.getDragLayer(); dragLayer.getViewTreeObserver().addOnDrawListener(new OnDrawListener() { @Override public void onDraw() { - TraceHelper.endSection("WTS-init", "Launcher frame is drawn"); + TraceHelper.INSTANCE.endSection(); dragLayer.post(() -> dragLayer.getViewTreeObserver().removeOnDrawListener(this)); if (activity != mActivity) { @@ -420,13 +416,13 @@ public class WindowTransformSwipeHandler private void initializeLauncherAnimationController() { buildAnimationController(); - DejankBinderTracker.whitelistIpcs(() -> { - // Only used in debug builds - if (LatencyTrackerCompat.isEnabled(mContext)) { - LatencyTrackerCompat.logToggleRecents( - (int) (mLauncherFrameDrawnTime - mTouchTimeMs)); - } - }); + TraceHelper.INSTANCE.beginSection("logToggleRecents", TraceHelper.FLAG_IGNORE_BINDERS); + // Only used in debug builds + if (LatencyTrackerCompat.isEnabled(mContext)) { + LatencyTrackerCompat.logToggleRecents( + (int) (mLauncherFrameDrawnTime - mTouchTimeMs)); + } + TraceHelper.INSTANCE.endSection(); // 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 @@ -1148,9 +1144,10 @@ public class WindowTransformSwipeHandler } if (!finishTransitionPosted) { // If we haven't posted a draw callback, set the state immediately. - RaceConditionTracker.onEvent(SCREENSHOT_CAPTURED_EVT, ENTER); + TraceHelper.INSTANCE.beginSection(SCREENSHOT_CAPTURED_EVT, + TraceHelper.FLAG_CHECK_FOR_RACE_CONDITIONS); setStateOnUiThread(STATE_SCREENSHOT_CAPTURED); - RaceConditionTracker.onEvent(SCREENSHOT_CAPTURED_EVT, EXIT); + TraceHelper.INSTANCE.endSection(); } } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java index fbedc0f812..d231d51be3 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java @@ -25,8 +25,7 @@ import static android.view.MotionEvent.INVALID_POINTER_ID; import static com.android.launcher3.Utilities.EDGE_NAV_BAR; import static com.android.launcher3.Utilities.squaredHypot; -import static com.android.launcher3.util.RaceConditionTracker.ENTER; -import static com.android.launcher3.util.RaceConditionTracker.EXIT; +import static com.android.launcher3.util.TraceHelper.FLAG_CHECK_FOR_RACE_CONDITIONS; import static com.android.quickstep.TouchInteractionService.startRecentsActivityAsync; import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; @@ -48,13 +47,13 @@ import androidx.annotation.UiThread; import com.android.launcher3.R; import com.android.launcher3.util.Preconditions; -import com.android.launcher3.util.RaceConditionTracker; import com.android.launcher3.util.TraceHelper; import com.android.quickstep.BaseActivityInterface; import com.android.quickstep.BaseSwipeUpHandler; import com.android.quickstep.BaseSwipeUpHandler.Factory; import com.android.quickstep.GestureState; import com.android.quickstep.InputConsumer; +import com.android.quickstep.RecentsAnimationCallbacks; import com.android.quickstep.RecentsAnimationDeviceState; import com.android.quickstep.SwipeSharedState; import com.android.quickstep.SysUINavigationMode; @@ -63,7 +62,6 @@ import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.CachedEventDispatcher; import com.android.quickstep.util.MotionPauseDetector; import com.android.quickstep.util.NavBarPosition; -import com.android.quickstep.RecentsAnimationCallbacks; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.InputMonitorCompat; @@ -200,8 +198,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC switch (ev.getActionMasked()) { case ACTION_DOWN: { - RaceConditionTracker.onEvent(DOWN_EVT, ENTER); - TraceHelper.beginSection("TouchInt"); + TraceHelper.INSTANCE.beginSection(DOWN_EVT, FLAG_CHECK_FOR_RACE_CONDITIONS); mActivePointerId = ev.getPointerId(0); mDownPos.set(ev.getX(), ev.getY()); mLastPos.set(mDownPos); @@ -212,7 +209,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC startTouchTrackingForWindowAnimation(ev.getEventTime(), false); } - RaceConditionTracker.onEvent(DOWN_EVT, EXIT); + TraceHelper.INSTANCE.endSection(); break; } case ACTION_POINTER_DOWN: { @@ -358,8 +355,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC * the animation can still be running. */ private void finishTouchTracking(MotionEvent ev) { - RaceConditionTracker.onEvent(UP_EVT, ENTER); - TraceHelper.endSection("TouchInt"); + TraceHelper.INSTANCE.beginSection(UP_EVT, FLAG_CHECK_FOR_RACE_CONDITIONS); if (mPassedWindowMoveSlop && mInteractionHandler != null) { if (ev.getActionMasked() == ACTION_CANCEL) { @@ -393,7 +389,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC mVelocityTracker.recycle(); mVelocityTracker = null; mMotionPauseDetector.clear(); - RaceConditionTracker.onEvent(UP_EVT, EXIT); + TraceHelper.INSTANCE.endSection(); } @Override diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java index 1545ec5110..0655c733ba 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java @@ -46,8 +46,8 @@ import com.android.launcher3.R; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.appprediction.PredictionUiStateManager; import com.android.launcher3.appprediction.PredictionUiStateManager.Client; -import com.android.launcher3.uioverrides.DejankBinderTracker; import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper; +import com.android.launcher3.util.TraceHelper; import com.android.launcher3.views.ScrimView; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.util.AppWindowAnimationHelper; @@ -221,7 +221,7 @@ public class LauncherRecentsView extends RecentsView implements StateL @Override public boolean shouldUseMultiWindowTaskSizeStrategy() { - return DejankBinderTracker.whitelistIpcs(() -> mActivity.isInMultiWindowMode()); + return TraceHelper.whitelistIpcs("isInMultiWindowMode", mActivity::isInMultiWindowMode); } @Override 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 d8aa235823..0000000000 --- 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 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 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 whitelistIpcs(Supplier 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 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/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java index 2111e2ca27..1d920f96c8 100644 --- a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java +++ b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java @@ -16,8 +16,8 @@ package com.android.quickstep; -import static com.android.launcher3.util.RaceConditionTracker.enterEvt; -import static com.android.launcher3.util.RaceConditionTracker.exitEvt; +import static com.android.launcher3.util.RaceConditionReproducer.enterEvt; +import static com.android.launcher3.util.RaceConditionReproducer.exitEvt; import android.content.Intent; diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java index 00a06ae633..d24de8e30c 100644 --- a/src/com/android/launcher3/BaseDraggingActivity.java +++ b/src/com/android/launcher3/BaseDraggingActivity.java @@ -36,11 +36,11 @@ import androidx.annotation.Nullable; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.model.AppLaunchTracker; import com.android.launcher3.shortcuts.DeepShortcutManager; -import com.android.launcher3.uioverrides.DejankBinderTracker; import com.android.launcher3.uioverrides.DisplayRotationListener; import com.android.launcher3.uioverrides.WallpaperColorInfo; import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.Themes; +import com.android.launcher3.util.TraceHelper; /** * Extension of BaseActivity allowing support for drag-n-drop @@ -66,8 +66,10 @@ public abstract class BaseDraggingActivity extends BaseActivity @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mIsSafeModeEnabled = DejankBinderTracker.whitelistIpcs(() -> - getPackageManager().isSafeMode()); + + + mIsSafeModeEnabled = TraceHelper.whitelistIpcs("isSafeMode", + () -> getPackageManager().isSafeMode()); mRotationListener = new DisplayRotationListener(this, this::onDeviceRotationChanged); // Update theme diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index c92d917155..a19ba21a48 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -32,8 +32,6 @@ import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_LAUNCHER_LOA import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; import static com.android.launcher3.logging.LoggerUtils.newTarget; import static com.android.launcher3.states.RotationHelper.REQUEST_NONE; -import static com.android.launcher3.util.RaceConditionTracker.ENTER; -import static com.android.launcher3.util.RaceConditionTracker.EXIT; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -115,7 +113,6 @@ import com.android.launcher3.popup.PopupDataProvider; import com.android.launcher3.qsb.QsbContainerView; import com.android.launcher3.states.RotationHelper; import com.android.launcher3.touch.ItemClickHandler; -import com.android.launcher3.uioverrides.DejankBinderTracker; import com.android.launcher3.uioverrides.UiFactory; import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper; import com.android.launcher3.userevent.nano.LauncherLogProto; @@ -132,7 +129,6 @@ import com.android.launcher3.util.MultiValueAlpha.AlphaProperty; import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.PendingRequestArgs; -import com.android.launcher3.util.RaceConditionTracker; import com.android.launcher3.util.ShortcutUtil; import com.android.launcher3.util.SystemUiController; import com.android.launcher3.util.Themes; @@ -214,9 +210,11 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, private static final String RUNTIME_STATE_PENDING_ACTIVITY_RESULT = "launcher.activity_result"; // Type: SparseArray private static final String RUNTIME_STATE_WIDGET_PANEL = "launcher.widget_panel"; + public static final String ON_CREATE_EVT = "Launcher.onCreate"; - private static final String ON_START_EVT = "Launcher.onStart"; - private static final String ON_RESUME_EVT = "Launcher.onResume"; + public static final String ON_START_EVT = "Launcher.onStart"; + public static final String ON_RESUME_EVT = "Launcher.onResume"; + public static final String ON_NEW_INTENT_EVT = "Launcher.onNewIntent"; private LauncherStateManager mStateManager; @@ -313,8 +311,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, @Override protected void onCreate(Bundle savedInstanceState) { - DejankBinderTracker.allowBinderTrackingInTests(); - RaceConditionTracker.onEvent(ON_CREATE_EVT, ENTER); + TraceHelper.INSTANCE.beginSection(ON_CREATE_EVT, TraceHelper.FLAG_UI_EVENT); if (DEBUG_STRICT_MODE) { StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() .detectDiskReads() @@ -329,10 +326,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, .penaltyDeath() .build()); } - TraceHelper.beginSection("Launcher-onCreate"); super.onCreate(savedInstanceState); - TraceHelper.partitionSection("Launcher-onCreate", "super call"); LauncherAppState app = LauncherAppState.getInstance(this); mOldConfig = new Configuration(getResources().getConfiguration()); @@ -414,8 +409,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, mRotationHelper.initialize(); - TraceHelper.endSection("Launcher-onCreate"); - RaceConditionTracker.onEvent(ON_CREATE_EVT, EXIT); mStateManager.addStateListener(new LauncherStateManager.StateListener() { @Override public void onStateTransitionStart(LauncherState toState) { @@ -435,7 +428,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, } } }); - DejankBinderTracker.disallowBinderTrackingInTests(); + + TraceHelper.INSTANCE.endSection(); } protected LauncherOverlayManager getDefaultOverlay() { @@ -940,16 +934,14 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, @Override protected void onStart() { - DejankBinderTracker.allowBinderTrackingInTests(); - RaceConditionTracker.onEvent(ON_START_EVT, ENTER); + TraceHelper.INSTANCE.beginSection(ON_START_EVT, TraceHelper.FLAG_UI_EVENT); super.onStart(); if (!mDeferOverlayCallbacks) { mOverlayManager.onActivityStarted(this); } mAppWidgetHost.setListenIfResumed(true); - RaceConditionTracker.onEvent(ON_START_EVT, EXIT); - DejankBinderTracker.disallowBinderTrackingInTests(); + TraceHelper.INSTANCE.endSection(); } private void handleDeferredResume() { @@ -1044,11 +1036,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, @Override protected void onResume() { - DejankBinderTracker.allowBinderTrackingInTests(); - RaceConditionTracker.onEvent(ON_RESUME_EVT, ENTER); - TraceHelper.beginSection("ON_RESUME"); + TraceHelper.INSTANCE.beginSection(ON_RESUME_EVT, TraceHelper.FLAG_UI_EVENT); super.onResume(); - TraceHelper.partitionSection("ON_RESUME", "superCall"); mHandler.removeCallbacks(mHandleDeferredResume); Utilities.postAsyncCallback(mHandler, mHandleDeferredResume); @@ -1068,9 +1057,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, mOverlayManager.onActivityResumed(this); } - TraceHelper.endSection("ON_RESUME"); - RaceConditionTracker.onEvent(ON_RESUME_EVT, EXIT); - DejankBinderTracker.disallowBinderTrackingInTests(); + TraceHelper.INSTANCE.endSection(); } @Override @@ -1429,7 +1416,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, @Override protected void onNewIntent(Intent intent) { - TraceHelper.beginSection("NEW_INTENT"); + TraceHelper.INSTANCE.beginSection(ON_NEW_INTENT_EVT); super.onNewIntent(intent); boolean alreadyOnHome = hasWindowFocus() && ((intent.getFlags() & @@ -1481,7 +1468,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, mOverlayManager.hideOverlay(isStarted() && !isForceInvisible()); } - TraceHelper.endSection("NEW_INTENT"); + TraceHelper.INSTANCE.endSection(); } @Override @@ -1984,7 +1971,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, * Implementation of the method from LauncherModel.Callbacks. */ public void startBinding() { - TraceHelper.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. @@ -2002,7 +1989,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, if (mHotseat != null) { mHotseat.resetLayout(getWallpaperDeviceProfile().isVerticalBarLayout()); } - TraceHelper.endSection("startBinding"); + TraceHelper.INSTANCE.endSection(); } @Override @@ -2195,112 +2182,113 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, return null; } } - + final AppWidgetHostView view; if (mIsSafeModeEnabled) { - PendingAppWidgetHostView view = - new PendingAppWidgetHostView(this, item, mIconCache, true); + view = new PendingAppWidgetHostView(this, item, mIconCache, true); prepareAppWidget(view, item); return view; } - TraceHelper.beginSection("BIND_WIDGET"); + TraceHelper.INSTANCE.beginSection("BIND_WIDGET_id=" + item.appWidgetId); - final LauncherAppWidgetProviderInfo appWidgetInfo; + try { + final LauncherAppWidgetProviderInfo appWidgetInfo; - if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)) { - // If the provider is not ready, bind as a pending widget. - appWidgetInfo = null; - } else if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) { - // The widget id is not valid. Try to find the widget based on the provider info. - appWidgetInfo = mAppWidgetManager.findProvider(item.providerName, item.user); - } else { - appWidgetInfo = mAppWidgetManager.getLauncherAppWidgetInfo(item.appWidgetId); - } - - // If the provider is ready, but the width is not yet restored, try to restore it. - if (!item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) && - (item.restoreStatus != LauncherAppWidgetInfo.RESTORE_COMPLETED)) { - if (appWidgetInfo == null) { - Log.d(TAG, "Removing restored widget: id=" + item.appWidgetId - + " belongs to component " + item.providerName - + ", as the provider is null"); - getModelWriter().deleteItemFromDatabase(item); - return null; + if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)) { + // If the provider is not ready, bind as a pending widget. + appWidgetInfo = null; + } else if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) { + // The widget id is not valid. Try to find the widget based on the provider info. + appWidgetInfo = mAppWidgetManager.findProvider(item.providerName, item.user); + } else { + appWidgetInfo = mAppWidgetManager.getLauncherAppWidgetInfo(item.appWidgetId); } - // If we do not have a valid id, try to bind an id. - if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) { - if (!item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_ALLOCATED)) { - // Id has not been allocated yet. Allocate a new id. - item.appWidgetId = mAppWidgetHost.allocateAppWidgetId(); - item.restoreStatus |= LauncherAppWidgetInfo.FLAG_ID_ALLOCATED; + // If the provider is ready, but the width is not yet restored, try to restore it. + if (!item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) + && (item.restoreStatus != LauncherAppWidgetInfo.RESTORE_COMPLETED)) { + if (appWidgetInfo == null) { + Log.d(TAG, "Removing restored widget: id=" + item.appWidgetId + + " belongs to component " + item.providerName + + ", as the provider is null"); + getModelWriter().deleteItemFromDatabase(item); + return null; + } - // Also try to bind the widget. If the bind fails, the user will be shown - // a click to setup UI, which will ask for the bind permission. - PendingAddWidgetInfo pendingInfo = new PendingAddWidgetInfo(appWidgetInfo); - pendingInfo.spanX = item.spanX; - pendingInfo.spanY = item.spanY; - pendingInfo.minSpanX = item.minSpanX; - pendingInfo.minSpanY = item.minSpanY; - Bundle options = WidgetHostViewLoader.getDefaultOptionsForWidget(this, - pendingInfo); + // If we do not have a valid id, try to bind an id. + if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) { + if (!item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_ALLOCATED)) { + // Id has not been allocated yet. Allocate a new id. + item.appWidgetId = mAppWidgetHost.allocateAppWidgetId(); + item.restoreStatus |= LauncherAppWidgetInfo.FLAG_ID_ALLOCATED; - boolean isDirectConfig = - item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG); - if (isDirectConfig && item.bindOptions != null) { - Bundle newOptions = item.bindOptions.getExtras(); - if (options != null) { - newOptions.putAll(options); + // Also try to bind the widget. If the bind fails, the user will be shown + // a click to setup UI, which will ask for the bind permission. + PendingAddWidgetInfo pendingInfo = new PendingAddWidgetInfo(appWidgetInfo); + pendingInfo.spanX = item.spanX; + pendingInfo.spanY = item.spanY; + pendingInfo.minSpanX = item.minSpanX; + pendingInfo.minSpanY = item.minSpanY; + Bundle options = WidgetHostViewLoader.getDefaultOptionsForWidget(this, + pendingInfo); + + boolean isDirectConfig = + item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG); + if (isDirectConfig && item.bindOptions != null) { + Bundle newOptions = item.bindOptions.getExtras(); + if (options != null) { + newOptions.putAll(options); + } + options = newOptions; } - options = newOptions; + boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed( + item.appWidgetId, appWidgetInfo, options); + + // We tried to bind once. If we were not able to bind, we would need to + // go through the permission dialog, which means we cannot skip the config + // activity. + item.bindOptions = null; + item.restoreStatus &= ~LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG; + + // Bind succeeded + if (success) { + // If the widget has a configure activity, it is still needs to set it + // up, otherwise the widget is ready to go. + item.restoreStatus = (appWidgetInfo.configure == null) || isDirectConfig + ? LauncherAppWidgetInfo.RESTORE_COMPLETED + : LauncherAppWidgetInfo.FLAG_UI_NOT_READY; + } + + getModelWriter().updateItemInDatabase(item); } - boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed( - item.appWidgetId, appWidgetInfo, options); - - // We tried to bind once. If we were not able to bind, we would need to - // go through the permission dialog, which means we cannot skip the config - // activity. - item.bindOptions = null; - item.restoreStatus &= ~LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG; - - // Bind succeeded - if (success) { - // If the widget has a configure activity, it is still needs to set it up, - // otherwise the widget is ready to go. - item.restoreStatus = (appWidgetInfo.configure == null) || isDirectConfig - ? LauncherAppWidgetInfo.RESTORE_COMPLETED - : LauncherAppWidgetInfo.FLAG_UI_NOT_READY; - } - + } else if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_UI_NOT_READY) + && (appWidgetInfo.configure == null)) { + // The widget was marked as UI not ready, but there is no configure activity to + // update the UI. + item.restoreStatus = LauncherAppWidgetInfo.RESTORE_COMPLETED; getModelWriter().updateItemInDatabase(item); } - } else if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_UI_NOT_READY) - && (appWidgetInfo.configure == null)) { - // The widget was marked as UI not ready, but there is no configure activity to - // update the UI. - item.restoreStatus = LauncherAppWidgetInfo.RESTORE_COMPLETED; - getModelWriter().updateItemInDatabase(item); - } - } - - final AppWidgetHostView view; - if (item.restoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED) { - // Verify that we own the widget - if (appWidgetInfo == null) { - FileLog.e(TAG, "Removing invalid widget: id=" + item.appWidgetId); - getModelWriter().deleteWidgetInfo(item, getAppWidgetHost()); - return null; } - item.minSpanX = appWidgetInfo.minSpanX; - item.minSpanY = appWidgetInfo.minSpanY; - view = mAppWidgetHost.createView(this, item.appWidgetId, appWidgetInfo); - } else { - view = new PendingAppWidgetHostView(this, item, mIconCache, false); - } - prepareAppWidget(view, item); + if (item.restoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED) { + // Verify that we own the widget + if (appWidgetInfo == null) { + FileLog.e(TAG, "Removing invalid widget: id=" + item.appWidgetId); + getModelWriter().deleteWidgetInfo(item, getAppWidgetHost()); + return null; + } + + item.minSpanX = appWidgetInfo.minSpanX; + item.minSpanY = appWidgetInfo.minSpanY; + view = mAppWidgetHost.createView(this, item.appWidgetId, appWidgetInfo); + } else { + view = new PendingAppWidgetHostView(this, item, mIconCache, false); + } + prepareAppWidget(view, item); + } finally { + TraceHelper.INSTANCE.endSection(); + } - TraceHelper.endSection("BIND_WIDGET", "id=" + item.appWidgetId); return view; } @@ -2378,7 +2366,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, * Implementation of the method from LauncherModel.Callbacks. */ public void finishBindingItems(int pageBoundFirst) { - TraceHelper.beginSection("finishBindingItems"); + TraceHelper.INSTANCE.beginSection("finishBindingItems"); mWorkspace.restoreInstanceStateForRemainingPages(); setWorkspaceLoading(false); @@ -2402,7 +2390,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, mDeviceProfile.inv.numFolderColumns * mDeviceProfile.inv.numFolderRows); getViewCache().setCacheSize(R.layout.folder_page, 2); - TraceHelper.endSection("finishBindingItems"); + TraceHelper.INSTANCE.endSection(); } private boolean canRunNewAppsAnimation() { diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index a29b7e1370..2d4a816338 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -40,6 +40,7 @@ import android.text.TextUtils; import android.util.Log; import android.util.LongSparseArray; import android.util.MutableInt; +import android.util.TimingLogger; import com.android.launcher3.AppInfo; import com.android.launcher3.FolderInfo; @@ -169,82 +170,84 @@ public class LoaderTask implements Runnable { } } - TraceHelper.beginSection(TAG); + TraceHelper.INSTANCE.beginSection(TAG); + TimingLogger logger = new TimingLogger(TAG, "run"); try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) { - TraceHelper.partitionSection(TAG, "step 1.1: loading workspace"); loadWorkspace(); + logger.addSplit("loadWorkspace"); verifyNotStopped(); - TraceHelper.partitionSection(TAG, "step 1.2: bind workspace workspace"); mResults.bindWorkspace(); + logger.addSplit("bindWorkspace"); // Notify the installer packages of packages with active installs on the first screen. - TraceHelper.partitionSection(TAG, "step 1.3: send first screen broadcast"); sendFirstScreenActiveInstallsBroadcast(); + logger.addSplit("sendFirstScreenActiveInstallsBroadcast"); // Take a break - TraceHelper.partitionSection(TAG, "step 1 completed, wait for idle"); waitForIdle(); + logger.addSplit("step 1 complete"); verifyNotStopped(); // second step - TraceHelper.partitionSection(TAG, "step 2.1: loading all apps"); List allActivityList = loadAllApps(); + logger.addSplit("loadAllApps"); - TraceHelper.partitionSection(TAG, "step 2.2: Binding all apps"); verifyNotStopped(); mResults.bindAllApps(); + logger.addSplit("bindAllApps"); verifyNotStopped(); - TraceHelper.partitionSection(TAG, "step 2.3: Update icon cache"); IconCacheUpdateHandler updateHandler = mIconCache.getUpdateHandler(); setIgnorePackages(updateHandler); updateHandler.updateIcons(allActivityList, LauncherActivityCachingLogic.newInstance(mApp.getContext()), mApp.getModel()::onPackageIconsUpdated); + logger.addSplit("update icon cache"); // Take a break - TraceHelper.partitionSection(TAG, "step 2 completed, wait for idle"); waitForIdle(); + logger.addSplit("step 2 complete"); verifyNotStopped(); // third step - TraceHelper.partitionSection(TAG, "step 3.1: loading deep shortcuts"); loadDeepShortcuts(); + logger.addSplit("loadDeepShortcuts"); verifyNotStopped(); - TraceHelper.partitionSection(TAG, "step 3.2: bind deep shortcuts"); mResults.bindDeepShortcuts(); + logger.addSplit("bindDeepShortcuts"); // Take a break - TraceHelper.partitionSection(TAG, "step 3 completed, wait for idle"); waitForIdle(); + logger.addSplit("step 3 complete"); verifyNotStopped(); // fourth step - TraceHelper.partitionSection(TAG, "step 4.1: loading widgets"); List allWidgetsList = mBgDataModel.widgetsModel.update(mApp, null); + logger.addSplit("load widgets"); verifyNotStopped(); - TraceHelper.partitionSection(TAG, "step 4.2: Binding widgets"); mResults.bindWidgets(); - + logger.addSplit("bindWidgets"); verifyNotStopped(); - TraceHelper.partitionSection(TAG, "step 4.3: save widgets in icon cache"); updateHandler.updateIcons(allWidgetsList, new ComponentCachingLogic( mApp.getContext(), true), mApp.getModel()::onWidgetLabelsUpdated); + logger.addSplit("save widgets in icon cache"); verifyNotStopped(); - TraceHelper.partitionSection(TAG, "step 5: Finish icon cache update"); updateHandler.finish(); + logger.addSplit("finish icon update"); transaction.commit(); } catch (CancellationException e) { // Loader stopped, ignore - TraceHelper.partitionSection(TAG, "Cancelled"); + logger.addSplit("Cancelled"); + } finally { + logger.dumpToLog(); } - TraceHelper.endSection(TAG); + TraceHelper.INSTANCE.endSection(); } public synchronized void stopLocked() { diff --git a/src/com/android/launcher3/util/MainThreadInitializedObject.java b/src/com/android/launcher3/util/MainThreadInitializedObject.java index cf4e8c796b..520a9edd57 100644 --- a/src/com/android/launcher3/util/MainThreadInitializedObject.java +++ b/src/com/android/launcher3/util/MainThreadInitializedObject.java @@ -22,7 +22,6 @@ import android.os.Looper; import androidx.annotation.VisibleForTesting; -import com.android.launcher3.uioverrides.DejankBinderTracker; import com.android.launcher3.util.ResourceBasedOverride.Overrides; import java.util.concurrent.ExecutionException; @@ -42,8 +41,8 @@ public class MainThreadInitializedObject { public T get(Context context) { if (mValue == null) { if (Looper.myLooper() == Looper.getMainLooper()) { - mValue = DejankBinderTracker.whitelistIpcs(() -> - mProvider.get(context.getApplicationContext())); + mValue = TraceHelper.whitelistIpcs("main.thread.object", + () -> mProvider.get(context.getApplicationContext())); } else { try { return MAIN_EXECUTOR.submit(() -> get(context)).get(); diff --git a/src/com/android/launcher3/util/RaceConditionTracker.java b/src/com/android/launcher3/util/RaceConditionTracker.java deleted file mode 100644 index 6954d0e27f..0000000000 --- a/src/com/android/launcher3/util/RaceConditionTracker.java +++ /dev/null @@ -1,61 +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; - -/** - * Event tracker for reliably reproducing race conditions in tests. - * The app should call onEvent() for events that the test will try to reproduce in all possible - * orders. - */ -public class RaceConditionTracker { - public final static boolean ENTER = true; - public final static boolean EXIT = false; - static final String ENTER_POSTFIX = "enter"; - static final String EXIT_POSTFIX = "exit"; - - public interface EventProcessor { - void onEvent(String eventName); - } - - private static EventProcessor sEventProcessor; - - static void setEventProcessor(EventProcessor eventProcessor) { - sEventProcessor = eventProcessor; - } - - public static void onEvent(String eventName) { - if (sEventProcessor != null) sEventProcessor.onEvent(eventName); - } - - public static void onEvent(String eventName, boolean isEnter) { - if (sEventProcessor != null) { - sEventProcessor.onEvent(enterExitEvt(eventName, isEnter)); - } - } - - 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); - } -} diff --git a/src/com/android/launcher3/util/TraceHelper.java b/src/com/android/launcher3/util/TraceHelper.java index c24bb67813..073fb6a61d 100644 --- a/src/com/android/launcher3/util/TraceHelper.java +++ b/src/com/android/launcher3/util/TraceHelper.java @@ -15,19 +15,14 @@ */ package com.android.launcher3.util; -import static android.util.Log.VERBOSE; -import static android.util.Log.isLoggable; - -import android.os.SystemClock; import android.os.Trace; -import android.util.ArrayMap; -import android.util.Log; -import android.util.MutableLong; -import com.android.launcher3.config.FeatureFlags; +import androidx.annotation.MainThread; + +import java.util.function.Supplier; /** - * A wrapper around {@link Trace} with some utility information. + * A wrapper around {@link Trace} to allow better testing. * * To enable any tracing log, execute the following command: * $ adb shell setprop log.tag.LAUNCHER_TRACE VERBOSE @@ -35,65 +30,51 @@ import com.android.launcher3.config.FeatureFlags; */ public class TraceHelper { - private static final boolean ENABLED = isLoggable("LAUNCHER_TRACE", VERBOSE); + // Track binder class for this trace + public static final int FLAG_ALLOW_BINDER_TRACKING = 1 << 0; - private static final boolean SYSTEM_TRACE = ENABLED; - private static final ArrayMap sUpTimes = ENABLED ? new ArrayMap<>() : null; + // Temporarily ignore blocking binder calls for this trace. + public static final int FLAG_IGNORE_BINDERS = 1 << 1; - public static void beginSection(String sectionName) { - if (ENABLED) { - synchronized (sUpTimes) { - MutableLong time = sUpTimes.get(sectionName); - if (time == null) { - time = new MutableLong(isLoggable(sectionName, VERBOSE) ? 0 : -1); - sUpTimes.put(sectionName, time); - } - if (time.value >= 0) { - if (SYSTEM_TRACE) { - Trace.beginSection(sectionName); - } - time.value = SystemClock.uptimeMillis(); - } - } - } + 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(); + + public void beginSection(String sectionName) { + beginSection(sectionName, 0); } - public static void partitionSection(String sectionName, String partition) { - if (ENABLED) { - synchronized (sUpTimes) { - MutableLong time = sUpTimes.get(sectionName); - if (time != null && time.value >= 0) { - - if (SYSTEM_TRACE) { - Trace.endSection(); - Trace.beginSection(sectionName); - } - - long now = SystemClock.uptimeMillis(); - Log.d(sectionName, partition + " : " + (now - time.value)); - time.value = now; - } - } - } + public void beginSection(String sectionName, int flags) { + Trace.beginSection(sectionName); } - public static void endSection(String sectionName) { - if (ENABLED) { - endSection(sectionName, "End"); - } + public void endSection() { + Trace.endSection(); } - public static void endSection(String sectionName, String msg) { - if (ENABLED) { - synchronized (sUpTimes) { - MutableLong time = sUpTimes.get(sectionName); - if (time != null && time.value >= 0) { - if (SYSTEM_TRACE) { - Trace.endSection(); - } - Log.d(sectionName, msg + " : " + (SystemClock.uptimeMillis() - time.value)); - } - } + /** + * Similar to {@link #beginSection} but doesn't add a trace section. + */ + public void beginFlagsOverride(int flags) { } + + public void endFlagsOverride() { } + + /** + * Temporarily ignore blocking binder calls for the duration of this {@link Supplier}. + */ + @MainThread + public static T whitelistIpcs(String rpcName, Supplier supplier) { + INSTANCE.beginSection(rpcName, FLAG_IGNORE_BINDERS); + try { + return supplier.get(); + } finally { + INSTANCE.endSection(); } } } diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/DejankBinderTracker.java b/src_ui_overrides/com/android/launcher3/uioverrides/DejankBinderTracker.java deleted file mode 100644 index 47f6ac6f75..0000000000 --- a/src_ui_overrides/com/android/launcher3/uioverrides/DejankBinderTracker.java +++ /dev/null @@ -1,57 +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 android.os.IBinder; - -import java.util.function.BiConsumer; -import java.util.function.Supplier; - -/** - * A binder proxy transaction listener for tracking non-whitelisted binder calls. - */ -public class DejankBinderTracker { - public static void whitelistIpcs(Runnable runnable) {} - - public static T whitelistIpcs(Supplier supplier) { - return null; - } - - public static void allowBinderTrackingInTests() {} - - public static void disallowBinderTrackingInTests() {} - - public DejankBinderTracker(BiConsumer unexpectedTransactionCallback) { } - - public void startTracking() {} - - public void stopTracking() {} - - public Object onTransactStarted(IBinder binder, int transactionCode, int flags) { - return null; - } - - public Object onTransactStarted(IBinder binder, int transactionCode) { - return null; - } - - public void onTransactEnded(Object session) {} - - public static boolean isMainThread() { - return true; - } -} diff --git a/tests/Android.mk b/tests/Android.mk index b5c1dae612..31a996084c 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -30,7 +30,6 @@ else LOCAL_STATIC_JAVA_LIBRARIES += SystemUISharedLib LOCAL_SRC_FILES := $(call all-java-files-under, tapl) \ - ../quickstep/src/com/android/launcher3/uioverrides/DejankBinderTracker.java \ ../src/com/android/launcher3/ResourceUtils.java \ ../src/com/android/launcher3/util/SecureSettingsObserver.java \ ../src/com/android/launcher3/testing/TestProtocol.java diff --git a/tests/src/com/android/launcher3/util/RaceConditionReproducer.java b/tests/src/com/android/launcher3/util/RaceConditionReproducer.java index 8f89173203..ed2ec7b40a 100644 --- a/tests/src/com/android/launcher3/util/RaceConditionReproducer.java +++ b/tests/src/com/android/launcher3/util/RaceConditionReproducer.java @@ -17,8 +17,6 @@ package com.android.launcher3.util; import static com.android.launcher3.util.Executors.createAndStartNewLooper; -import static com.android.launcher3.util.RaceConditionTracker.ENTER_POSTFIX; -import static com.android.launcher3.util.RaceConditionTracker.EXIT_POSTFIX; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -64,15 +62,30 @@ import java.util.concurrent.TimeUnit; * * When we register event XXX:enter, we hold all other events until we register XXX:exit. */ -public class RaceConditionReproducer implements RaceConditionTracker.EventProcessor { +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 = createEventResumeHandler(); + private static final Handler POSTPONED_EVENT_RESUME_HANDLER = + new Handler(createAndStartNewLooper("RaceConditionEventResumer")); - private static Handler createEventResumeHandler() { - return 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); } /** @@ -209,7 +222,8 @@ public class RaceConditionReproducer implements RaceConditionTracker.EventProces parseReproString(mReproString) : generateSequenceToFollowLocked(); Log.e(TAG, "---- Start of iteration; state:\n" + dumpStateLocked()); checkIfCompletedSequenceToFollowLocked(); - RaceConditionTracker.setEventProcessor(this); + + TraceHelperForTest.setRaceConditionReproducer(this); } /** @@ -218,7 +232,8 @@ public class RaceConditionReproducer implements RaceConditionTracker.EventProces * Returns whether we need more iterations. */ public synchronized boolean finishIteration() { - RaceConditionTracker.setEventProcessor(null); + TraceHelperForTest.setRaceConditionReproducer(null); + runResumeAllEventsCallbackLocked(); assertTrue("Non-empty postponed events", mPostponedEvents.isEmpty()); assertTrue("Last registered event is :enter", lastEventAsEnter() == null); @@ -243,7 +258,6 @@ public class RaceConditionReproducer implements RaceConditionTracker.EventProces /** * Called when the app issues an event. */ - @Override public void onEvent(String event) { final Semaphore waitObject = tryRegisterEvent(event); if (waitObject != null) { diff --git a/tests/src/com/android/launcher3/util/RaceConditionReproducerTest.java b/tests/src/com/android/launcher3/util/RaceConditionReproducerTest.java index 3fc268e60b..d156d1f017 100644 --- a/tests/src/com/android/launcher3/util/RaceConditionReproducerTest.java +++ b/tests/src/com/android/launcher3/util/RaceConditionReproducerTest.java @@ -22,6 +22,7 @@ import static org.junit.Assert.assertTrue; import androidx.test.filters.LargeTest; import androidx.test.runner.AndroidJUnit4; +import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -37,17 +38,24 @@ public class RaceConditionReproducerTest { return res; } - private static void run3_3_TestAction() throws InterruptedException { + RaceConditionReproducer eventProcessor; + + @Before + public void setup() { + eventProcessor = new RaceConditionReproducer(); + } + + private void run3_3_TestAction() throws InterruptedException { Thread tb = new Thread(() -> { - RaceConditionTracker.onEvent("B1"); - RaceConditionTracker.onEvent("B2"); - RaceConditionTracker.onEvent("B3"); + eventProcessor.onEvent("B1"); + eventProcessor.onEvent("B2"); + eventProcessor.onEvent("B3"); }); tb.start(); - RaceConditionTracker.onEvent("A1"); - RaceConditionTracker.onEvent("A2"); - RaceConditionTracker.onEvent("A3"); + eventProcessor.onEvent("A1"); + eventProcessor.onEvent("A2"); + eventProcessor.onEvent("A3"); tb.join(); } @@ -56,7 +64,6 @@ public class RaceConditionReproducerTest { @Ignore // The test is too long for continuous testing. // 2 threads, 3 events each. public void test3_3() throws Exception { - final RaceConditionReproducer eventProcessor = new RaceConditionReproducer(); boolean sawTheValidSequence = false; for (; ; ) { @@ -80,25 +87,24 @@ public class RaceConditionReproducerTest { @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 { - final RaceConditionReproducer eventProcessor = new RaceConditionReproducer(); boolean sawTheValidSequence = false; for (; ; ) { eventProcessor.startIteration(); Thread tb = new Thread(() -> { - RaceConditionTracker.onEvent("B1:enter"); - RaceConditionTracker.onEvent("B1:exit"); - RaceConditionTracker.onEvent("B2"); - RaceConditionTracker.onEvent("B3:enter"); - RaceConditionTracker.onEvent("B3:exit"); + eventProcessor.onEvent("B1:enter"); + eventProcessor.onEvent("B1:exit"); + eventProcessor.onEvent("B2"); + eventProcessor.onEvent("B3:enter"); + eventProcessor.onEvent("B3:exit"); }); tb.start(); - RaceConditionTracker.onEvent("A1"); - RaceConditionTracker.onEvent("A2:enter"); - RaceConditionTracker.onEvent("A2:exit"); - RaceConditionTracker.onEvent("A3:enter"); - RaceConditionTracker.onEvent("A3:exit"); + 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(); @@ -134,23 +140,21 @@ public class RaceConditionReproducerTest { @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 { - final RaceConditionReproducer eventProcessor = new RaceConditionReproducer(); - for (; ; ) { eventProcessor.startIteration(); Thread tb = new Thread(() -> { - RaceConditionTracker.onEvent("B1"); - RaceConditionTracker.onEvent("B2"); + eventProcessor.onEvent("B1"); + eventProcessor.onEvent("B2"); }); tb.start(); Thread tc = new Thread(() -> { - RaceConditionTracker.onEvent("C1"); + eventProcessor.onEvent("C1"); }); tc.start(); - RaceConditionTracker.onEvent("A1"); - RaceConditionTracker.onEvent("A2"); + eventProcessor.onEvent("A1"); + eventProcessor.onEvent("A2"); tb.join(); tc.join(); @@ -167,28 +171,26 @@ public class RaceConditionReproducerTest { @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 { - final RaceConditionReproducer eventProcessor = new RaceConditionReproducer(); - for (; ; ) { eventProcessor.startIteration(); Thread tb = new Thread(() -> { - RaceConditionTracker.onEvent("B1:enter"); - RaceConditionTracker.onEvent("B1:exit"); - RaceConditionTracker.onEvent("B2:enter"); - RaceConditionTracker.onEvent("B2:exit"); + eventProcessor.onEvent("B1:enter"); + eventProcessor.onEvent("B1:exit"); + eventProcessor.onEvent("B2:enter"); + eventProcessor.onEvent("B2:exit"); }); tb.start(); Thread tc = new Thread(() -> { - RaceConditionTracker.onEvent("C1:enter"); - RaceConditionTracker.onEvent("C1:exit"); + eventProcessor.onEvent("C1:enter"); + eventProcessor.onEvent("C1:exit"); }); tc.start(); - RaceConditionTracker.onEvent("A1:enter"); - RaceConditionTracker.onEvent("A1:exit"); - RaceConditionTracker.onEvent("A2:enter"); - RaceConditionTracker.onEvent("A2:exit"); + eventProcessor.onEvent("A1:enter"); + eventProcessor.onEvent("A1:exit"); + eventProcessor.onEvent("A2:enter"); + eventProcessor.onEvent("A2:exit"); tb.join(); tc.join(); diff --git a/tests/src/com/android/launcher3/util/TraceHelperForTest.java b/tests/src/com/android/launcher3/util/TraceHelperForTest.java new file mode 100644 index 0000000000..9125f5fc35 --- /dev/null +++ b/tests/src/com/android/launcher3/util/TraceHelperForTest.java @@ -0,0 +1,100 @@ +/** + * 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> 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 setFlagsChangeListener(IntConsumer listener) { + TraceHelper.INSTANCE = INSTANCE_FOR_TEST; + INSTANCE_FOR_TEST.mFlagsChangeListener = listener; + } + + private TraceHelperForTest() { } + + @Override + public void beginSection(String sectionName, int flags) { + LinkedList stack = mStack.get(); + stack.add(new TraceInfo(sectionName, flags)); + + if ((flags & TraceHelper.FLAG_CHECK_FOR_RACE_CONDITIONS) != 0 + && mRaceConditionReproducer != null) { + mRaceConditionReproducer.onEvent(RaceConditionReproducer.enterEvt(sectionName)); + } + updateBinderTracking(stack); + + super.beginSection(sectionName, flags); + } + + @Override + public void endSection() { + LinkedList stack = mStack.get(); + TraceInfo info = stack.pollLast(); + if ((info.flags & TraceHelper.FLAG_CHECK_FOR_RACE_CONDITIONS) != 0 + && mRaceConditionReproducer != null) { + mRaceConditionReproducer.onEvent(RaceConditionReproducer.exitEvt(info.sectionName)); + } + updateBinderTracking(stack); + + super.endSection(); + } + + @Override + public void beginFlagsOverride(int flags) { + LinkedList stack = mStack.get(); + stack.push(new TraceInfo(null, flags)); + updateBinderTracking(stack); + super.beginFlagsOverride(flags); + } + + @Override + public void endFlagsOverride() { + super.endFlagsOverride(); + updateBinderTracking(mStack.get()); + } + + private void updateBinderTracking(LinkedList stack) { + if (mFlagsChangeListener != null) { + mFlagsChangeListener.accept(stack.stream() + .mapToInt(s -> s.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; + } + } +}