Unifying various tracing calls
Change-Id: Iedf6662ad1d7281b850bdc43b3a1e373ce535ac6
This commit is contained in:
+6
-5
@@ -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 =
|
||||
|
||||
+12
-15
@@ -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<T extends BaseDraggingActivity>
|
||||
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<T extends BaseDraggingActivity>
|
||||
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<T extends BaseDraggingActivity>
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-10
@@ -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
|
||||
|
||||
+2
-2
@@ -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<Launcher> implements StateL
|
||||
|
||||
@Override
|
||||
public boolean shouldUseMultiWindowTaskSizeStrategy() {
|
||||
return DejankBinderTracker.whitelistIpcs(() -> mActivity.isInMultiWindowMode());
|
||||
return TraceHelper.whitelistIpcs("isInMultiWindowMode", mActivity::isInMultiWindowMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<Parcelable>
|
||||
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() {
|
||||
|
||||
@@ -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<LauncherActivityInfo> 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<ComponentWithLabel> 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() {
|
||||
|
||||
@@ -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<T> {
|
||||
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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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<String, MutableLong> 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> T whitelistIpcs(String rpcName, Supplier<T> supplier) {
|
||||
INSTANCE.beginSection(rpcName, FLAG_IGNORE_BINDERS);
|
||||
try {
|
||||
return supplier.get();
|
||||
} finally {
|
||||
INSTANCE.endSection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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> T whitelistIpcs(Supplier<T> supplier) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void allowBinderTrackingInTests() {}
|
||||
|
||||
public static void disallowBinderTrackingInTests() {}
|
||||
|
||||
public DejankBinderTracker(BiConsumer<String, Integer> 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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<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 setFlagsChangeListener(IntConsumer listener) {
|
||||
TraceHelper.INSTANCE = INSTANCE_FOR_TEST;
|
||||
INSTANCE_FOR_TEST.mFlagsChangeListener = listener;
|
||||
}
|
||||
|
||||
private TraceHelperForTest() { }
|
||||
|
||||
@Override
|
||||
public void beginSection(String sectionName, int flags) {
|
||||
LinkedList<TraceInfo> 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<TraceInfo> 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<TraceInfo> 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<TraceInfo> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user