diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 43c16555b8d4e..65314763e5e61 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -5292,7 +5292,7 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (this) { mWindowManager.cancelRecentsAnimation(restoreHomeStackPosition ? REORDER_MOVE_TO_ORIGINAL_POSITION - : REORDER_KEEP_IN_PLACE); + : REORDER_KEEP_IN_PLACE, "cancelRecentsAnimation"); } } finally { Binder.restoreCallingIdentity(origId); diff --git a/services/core/java/com/android/server/am/RecentsAnimation.java b/services/core/java/com/android/server/am/RecentsAnimation.java index 17eeb5b2f4f56..06b5e20de972c 100644 --- a/services/core/java/com/android/server/am/RecentsAnimation.java +++ b/services/core/java/com/android/server/am/RecentsAnimation.java @@ -46,6 +46,8 @@ import com.android.server.wm.WindowManagerService; */ class RecentsAnimation implements RecentsAnimationCallbacks { private static final String TAG = RecentsAnimation.class.getSimpleName(); + // TODO (b/73188263): Reset debugging flags + private static final boolean DEBUG = true; private final ActivityManagerService mService; private final ActivityStackSupervisor mStackSupervisor; @@ -74,10 +76,13 @@ class RecentsAnimation implements RecentsAnimationCallbacks { void startRecentsActivity(Intent intent, IRecentsAnimationRunner recentsAnimationRunner, ComponentName recentsComponent, int recentsUid) { + if (DEBUG) Slog.d(TAG, "startRecentsActivity(): intent=" + intent); Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "RecentsAnimation#startRecentsActivity"); if (!mWindowManager.canStartRecentsAnimation()) { notifyAnimationCancelBeforeStart(recentsAnimationRunner); + if (DEBUG) Slog.d(TAG, "Can't start recents animation, nextAppTransition=" + + mWindowManager.getPendingAppTransition()); return; } @@ -97,6 +102,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks { mRestoreTargetBehindStack = display.getStackAbove(targetStack); if (mRestoreTargetBehindStack == null) { notifyAnimationCancelBeforeStart(recentsAnimationRunner); + if (DEBUG) Slog.d(TAG, "No stack above target stack=" + targetStack); return; } } @@ -119,6 +125,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks { // Move the recents activity into place for the animation if it is not top most display = targetActivity.getDisplay(); display.moveStackBehindBottomMostVisibleStack(targetStack); + if (DEBUG) Slog.d(TAG, "Moved stack=" + targetStack + " behind stack=" + + display.getStackAbove(targetStack)); } else { // No recents activity ActivityOptions options = ActivityOptions.makeBasic(); @@ -140,6 +148,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks { display = targetActivity.getDisplay(); // TODO: Maybe wait for app to draw in this particular case? + + if (DEBUG) Slog.d(TAG, "Started intent=" + intent); } // Mark the target activity as launch-behind to bump its visibility for the @@ -148,7 +158,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks { // Fetch all the surface controls and pass them to the client to get the animation // started - mWindowManager.cancelRecentsAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION); + mWindowManager.cancelRecentsAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, + "startRecentsActivity"); mWindowManager.initializeRecentsAnimation(mTargetActivityType, recentsAnimationRunner, this, display.mDisplayId, mStackSupervisor.mRecentTasks.getRecentTaskIds()); @@ -158,6 +169,9 @@ class RecentsAnimation implements RecentsAnimationCallbacks { mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunched(START_TASK_TO_FRONT, targetActivity); + } catch (Exception e) { + Slog.e(TAG, "Failed to start recents activity", e); + throw e; } finally { mWindowManager.continueSurfaceLayout(); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); @@ -167,6 +181,9 @@ class RecentsAnimation implements RecentsAnimationCallbacks { @Override public void onAnimationFinished(@RecentsAnimationController.ReorderMode int reorderMode) { synchronized (mService) { + if (DEBUG) Slog.d(TAG, "onAnimationFinished(): controller=" + + mWindowManager.getRecentsAnimationController() + + " reorderMode=" + reorderMode); if (mWindowManager.getRecentsAnimationController() == null) return; // Just to be sure end the launch hint in case the target activity was never launched. @@ -187,6 +204,9 @@ class RecentsAnimation implements RecentsAnimationCallbacks { final ActivityStack targetStack = mDefaultDisplay.getStack( WINDOWING_MODE_UNDEFINED, mTargetActivityType); final ActivityRecord targetActivity = targetStack.getTopActivity(); + if (DEBUG) Slog.d(TAG, "onAnimationFinished(): targetStack=" + targetStack + + " targetActivity=" + targetActivity + + " mRestoreTargetBehindStack=" + mRestoreTargetBehindStack); if (targetActivity == null) { return; } @@ -198,10 +218,27 @@ class RecentsAnimation implements RecentsAnimationCallbacks { // Bring the target stack to the front mStackSupervisor.mNoAnimActivities.add(targetActivity); targetStack.moveToFront("RecentsAnimation.onAnimationFinished()"); + if (DEBUG) { + final ActivityStack topStack = getTopNonAlwaysOnTopStack(); + if (topStack != targetStack) { + Slog.w(TAG, "Expected target stack=" + targetStack + + " to be top most but found stack=" + topStack); + } + } } else if (reorderMode == REORDER_MOVE_TO_ORIGINAL_POSITION){ // Restore the target stack to its previous position final ActivityDisplay display = targetActivity.getDisplay(); display.moveStackBehindStack(targetStack, mRestoreTargetBehindStack); + if (DEBUG) { + final ActivityStack aboveTargetStack = + mDefaultDisplay.getStackAbove(targetStack); + if (mRestoreTargetBehindStack != null + && aboveTargetStack != mRestoreTargetBehindStack) { + Slog.w(TAG, "Expected target stack=" + targetStack + + " to restored behind stack=" + mRestoreTargetBehindStack + + " but it is behind stack=" + aboveTargetStack); + } + } } else { // Keep target stack in place, nothing changes, so ignore the transition // logic below @@ -221,6 +258,9 @@ class RecentsAnimation implements RecentsAnimationCallbacks { // split-screen), or we will have returned to the app, and the minimized state // should be reset mWindowManager.checkSplitScreenMinimizedChanged(true /* animate */); + } catch (Exception e) { + Slog.e(TAG, "Failed to clean up recents activity", e); + throw e; } finally { mWindowManager.continueSurfaceLayout(); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); @@ -239,4 +279,18 @@ class RecentsAnimation implements RecentsAnimationCallbacks { Slog.e(TAG, "Failed to cancel recents animation before start", e); } } + + /** + * @return The top stack that is not always-on-top. + */ + private ActivityStack getTopNonAlwaysOnTopStack() { + for (int i = mDefaultDisplay.getChildCount() - 1; i >= 0; i--) { + final ActivityStack s = mDefaultDisplay.getChildAt(i); + if (s.getWindowConfiguration().isAlwaysOnTop()) { + continue; + } + return s; + } + return null; + } } diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index bae93f38625a5..1ee642a58e839 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -17,19 +17,16 @@ package com.android.server.wm; import static android.app.ActivityManagerInternal.APP_TRANSITION_RECENTS_ANIM; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.RemoteAnimationTarget.MODE_CLOSING; import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; -import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; -import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; -import static com.android.server.wm.WindowManagerService.H.NOTIFY_APP_TRANSITION_STARTING; -import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET; import static com.android.server.wm.AnimationAdapterProto.REMOTE; +import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS; +import static com.android.server.wm.WindowManagerService.H.NOTIFY_APP_TRANSITION_STARTING; import android.annotation.IntDef; import android.app.ActivityManager.TaskSnapshot; @@ -41,24 +38,22 @@ import android.os.IBinder.DeathRecipient; import android.os.RemoteException; import android.os.SystemClock; import android.util.ArraySet; -import android.util.Log; -import android.util.Slog;import android.util.proto.ProtoOutputStream; +import android.util.Slog; import android.util.SparseBooleanArray; import android.util.SparseIntArray; +import android.util.proto.ProtoOutputStream; import android.view.IRecentsAnimationController; import android.view.IRecentsAnimationRunner; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; - import com.android.internal.annotations.VisibleForTesting; -import com.google.android.collect.Sets; - import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; import com.android.server.wm.utils.InsetUtils; - +import com.google.android.collect.Sets; import java.io.PrintWriter; import java.util.ArrayList; + /** * Controls a single instance of the remote driven recents animation. In particular, this allows * the calling SystemUI to animate the visible task windows as a part of the transition. The remote @@ -67,8 +62,7 @@ import java.util.ArrayList; * app if it requires the animation to be canceled at any time (ie. due to timeout, etc.) */ public class RecentsAnimationController implements DeathRecipient { - private static final String TAG = TAG_WITH_CLASS_NAME ? "RecentsAnimationController" : TAG_WM; - private static final boolean DEBUG = false; + private static final String TAG = RecentsAnimationController.class.getSimpleName(); private static final long FAILSAFE_DELAY = 1000; public static final int REORDER_KEEP_IN_PLACE = 0; @@ -88,7 +82,7 @@ public class RecentsAnimationController implements DeathRecipient { private final ArrayList mPendingAnimations = new ArrayList<>(); private final int mDisplayId; private final Runnable mFailsafeRunnable = () -> { - cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION); + cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "failSafeRunnable"); }; // The recents component app token that is shown behind the visibile tasks @@ -124,7 +118,8 @@ public class RecentsAnimationController implements DeathRecipient { @Override public TaskSnapshot screenshotTask(int taskId) { - if (DEBUG) Log.d(TAG, "screenshotTask(" + taskId + "): mCanceled=" + mCanceled); + if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "screenshotTask(" + taskId + "):" + + " mCanceled=" + mCanceled); final long token = Binder.clearCallingIdentity(); try { synchronized (mService.getWindowManagerLock()) { @@ -153,7 +148,8 @@ public class RecentsAnimationController implements DeathRecipient { @Override public void finish(boolean moveHomeToTop) { - if (DEBUG) Log.d(TAG, "finish(" + moveHomeToTop + "): mCanceled=" + mCanceled); + if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "finish(" + moveHomeToTop + "):" + + " mCanceled=" + mCanceled); final long token = Binder.clearCallingIdentity(); try { synchronized (mService.getWindowManagerLock()) { @@ -190,8 +186,8 @@ public class RecentsAnimationController implements DeathRecipient { @Override public void setInputConsumerEnabled(boolean enabled) { - if (DEBUG) Log.d(TAG, "setInputConsumerEnabled(" + enabled + "): mCanceled=" - + mCanceled); + if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "setInputConsumerEnabled(" + enabled + "):" + + " mCanceled=" + mCanceled); final long token = Binder.clearCallingIdentity(); try { synchronized (mService.getWindowManagerLock()) { @@ -264,14 +260,14 @@ public class RecentsAnimationController implements DeathRecipient { // Skip the animation if there is nothing to animate if (mPendingAnimations.isEmpty()) { - cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION); + cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "initialize-noVisibleTasks"); return; } try { linkToDeathOfRunner(); } catch (RemoteException e) { - cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION); + cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "initialize-failedToLinkToDeath"); return; } @@ -279,7 +275,8 @@ public class RecentsAnimationController implements DeathRecipient { final AppWindowToken recentsComponentAppToken = dc.getStack(WINDOWING_MODE_UNDEFINED, targetActivityType).getTopChild().getTopFullscreenAppToken(); if (recentsComponentAppToken != null) { - if (DEBUG) Log.d(TAG, "setHomeApp(" + recentsComponentAppToken.getName() + ")"); + if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "setHomeApp(" + + recentsComponentAppToken.getName() + ")"); mTargetAppToken = recentsComponentAppToken; if (recentsComponentAppToken.windowsCanBeWallpaperTarget()) { dc.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; @@ -295,7 +292,7 @@ public class RecentsAnimationController implements DeathRecipient { @VisibleForTesting AnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible) { - if (DEBUG) Log.d(TAG, "addAnimation(" + task.getName() + ")"); + if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "addAnimation(" + task.getName() + ")"); // TODO: Refactor this to use the task's animator final SurfaceAnimator anim = new SurfaceAnimator(task, null /* animationFinishedCallback */, mService); @@ -309,14 +306,15 @@ public class RecentsAnimationController implements DeathRecipient { @VisibleForTesting void removeAnimation(TaskAnimationAdapter taskAdapter) { - if (DEBUG) Log.d(TAG, "removeAnimation(" + taskAdapter.mTask.getName() + ")"); + if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "removeAnimation(" + + taskAdapter.mTask.mTaskId + ")"); taskAdapter.mTask.setCanAffectSystemUiFlags(true); taskAdapter.mCapturedFinishCallback.onAnimationFinished(taskAdapter); mPendingAnimations.remove(taskAdapter); } void startAnimation() { - if (DEBUG) Log.d(TAG, "startAnimation(): mPendingStart=" + mPendingStart + if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "startAnimation(): mPendingStart=" + mPendingStart + " mCanceled=" + mCanceled); if (!mPendingStart || mCanceled) { // Skip starting if we've already started or canceled the animation @@ -336,7 +334,7 @@ public class RecentsAnimationController implements DeathRecipient { // Skip the animation if there is nothing to animate if (appAnimations.isEmpty()) { - cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION); + cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "startAnimation-noAppWindows"); return; } @@ -354,6 +352,13 @@ public class RecentsAnimationController implements DeathRecipient { : null; mRunner.onAnimationStart_New(mController, appTargets, contentInsets, minimizedHomeBounds); + if (DEBUG_RECENTS_ANIMATIONS) { + Slog.d(TAG, "startAnimation(): Notify animation start:"); + for (int i = 0; i < mPendingAnimations.size(); i++) { + final Task task = mPendingAnimations.get(i).mTask; + Slog.d(TAG, "\t" + task.mTaskId); + } + } } catch (RemoteException e) { Slog.e(TAG, "Failed to start recents animation", e); } @@ -363,8 +368,8 @@ public class RecentsAnimationController implements DeathRecipient { reasons).sendToTarget(); } - void cancelAnimation(@ReorderMode int reorderMode) { - if (DEBUG) Log.d(TAG, "cancelAnimation()"); + void cancelAnimation(@ReorderMode int reorderMode, String reason) { + if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "cancelAnimation()"); synchronized (mService.getWindowManagerLock()) { if (mCanceled) { // We've already canceled the animation @@ -385,8 +390,9 @@ public class RecentsAnimationController implements DeathRecipient { } void cleanupAnimation(@ReorderMode int reorderMode) { - if (DEBUG) Log.d(TAG, "cleanupAnimation(): mPendingAnimations=" - + mPendingAnimations.size()); + if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, + "cleanupAnimation(): Notify animation finished mPendingAnimations=" + + mPendingAnimations.size() + " reorderMode=" + reorderMode); for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i); if (reorderMode == REORDER_MOVE_TO_TOP || reorderMode == REORDER_KEEP_IN_PLACE) { @@ -421,7 +427,7 @@ public class RecentsAnimationController implements DeathRecipient { @Override public void binderDied() { - cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION); + cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "binderDied"); } void checkAnimationReady(WallpaperController wallpaperController) { @@ -550,7 +556,7 @@ public class RecentsAnimationController implements DeathRecipient { @Override public void onAnimationCancelled(SurfaceControl animationLeash) { - cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION); + cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "taskAnimationAdapterCanceled"); } @Override @@ -572,6 +578,10 @@ public class RecentsAnimationController implements DeathRecipient { } else { pw.print(prefix); pw.println("Target: null"); } + pw.println("mIsRecentTaskInvisible=" + mIsRecentTaskInvisible); + pw.println("mPosition=" + mPosition); + pw.println("mBounds=" + mBounds); + pw.println("mIsRecentTaskInvisible=" + mIsRecentTaskInvisible); } @Override @@ -588,6 +598,10 @@ public class RecentsAnimationController implements DeathRecipient { final String innerPrefix = prefix + " "; pw.print(prefix); pw.println(RecentsAnimationController.class.getSimpleName() + ":"); pw.print(innerPrefix); pw.println("mPendingStart=" + mPendingStart); + pw.print(innerPrefix); pw.println("mCanceled=" + mCanceled); + pw.print(innerPrefix); pw.println("mInputConsumerEnabled=" + mInputConsumerEnabled); + pw.print(innerPrefix); pw.println("mSplitScreenMinimized=" + mSplitScreenMinimized); pw.print(innerPrefix); pw.println("mTargetAppToken=" + mTargetAppToken); + pw.print(innerPrefix); pw.println("isTargetOverWallpaper=" + isTargetOverWallpaper()); } } diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java index 16f4cd0d50ed8..1b06b2fe1e7ea 100644 --- a/services/core/java/com/android/server/wm/RemoteAnimationController.java +++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java @@ -19,6 +19,7 @@ package com.android.server.wm; import static com.android.server.wm.AnimationAdapterProto.REMOTE; import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_REMOTE_ANIMATIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -49,7 +50,9 @@ import java.util.ArrayList; * Helper class to run app animations in a remote process. */ class RemoteAnimationController implements DeathRecipient { - private static final String TAG = TAG_WITH_CLASS_NAME ? "RemoteAnimationController" : TAG_WM; + private static final String TAG = TAG_WITH_CLASS_NAME + || (DEBUG_REMOTE_ANIMATIONS && !DEBUG_APP_TRANSITIONS) + ? "RemoteAnimationController" : TAG_WM; private static final long TIMEOUT_MS = 2000; private final WindowManagerService mService; @@ -57,7 +60,7 @@ class RemoteAnimationController implements DeathRecipient { private final ArrayList mPendingAnimations = new ArrayList<>(); private final Rect mTmpRect = new Rect(); private final Handler mHandler; - private final Runnable mTimeoutRunnable = this::cancelAnimation; + private final Runnable mTimeoutRunnable = () -> cancelAnimation("timeoutRunnable"); private FinishedCallback mFinishedCallback; private boolean mCanceled; @@ -80,6 +83,7 @@ class RemoteAnimationController implements DeathRecipient { */ AnimationAdapter createAnimationAdapter(AppWindowToken appWindowToken, Point position, Rect stackBounds) { + if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "createAnimationAdapter(): token=" + appWindowToken); final RemoteAnimationAdapterWrapper adapter = new RemoteAnimationAdapterWrapper( appWindowToken, position, stackBounds); mPendingAnimations.add(adapter); @@ -90,7 +94,10 @@ class RemoteAnimationController implements DeathRecipient { * Called when the transition is ready to be started, and all leashes have been set up. */ void goodToGo() { + if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "goodToGo()"); if (mPendingAnimations.isEmpty() || mCanceled) { + if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "goodToGo(): Animation finished before good to go, canceled=" + + mCanceled + " mPendingAnimations=" + mPendingAnimations.size()); onAnimationFinished(); return; } @@ -102,6 +109,7 @@ class RemoteAnimationController implements DeathRecipient { final RemoteAnimationTarget[] animations = createAnimations(); if (animations.length == 0) { + if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "goodToGo(): No apps to animate"); onAnimationFinished(); return; } @@ -113,14 +121,20 @@ class RemoteAnimationController implements DeathRecipient { Slog.e(TAG, "Failed to start remote animation", e); onAnimationFinished(); } + if (DEBUG_REMOTE_ANIMATIONS) { + Slog.d(TAG, "startAnimation(): Notify animation start:"); + for (int i = 0; i < mPendingAnimations.size(); i++) { + Slog.d(TAG, "\t" + mPendingAnimations.get(i).mAppWindowToken); + } + } else if (DEBUG_APP_TRANSITIONS) { + writeStartDebugStatement(); + } }); sendRunningRemoteAnimation(true); - if (DEBUG_APP_TRANSITIONS) { - writeStartDebugStatement(); - } } - private void cancelAnimation() { + private void cancelAnimation(String reason) { + if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "cancelAnimation(): reason=" + reason); synchronized (mService.getWindowManagerLock()) { if (mCanceled) { return; @@ -143,14 +157,16 @@ class RemoteAnimationController implements DeathRecipient { } private RemoteAnimationTarget[] createAnimations() { + if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "createAnimations()"); final ArrayList targets = new ArrayList<>(); for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { final RemoteAnimationAdapterWrapper wrapper = mPendingAnimations.get(i); - final RemoteAnimationTarget target = - mPendingAnimations.get(i).createRemoteAppAnimation(); + final RemoteAnimationTarget target = wrapper.createRemoteAppAnimation(); if (target != null) { + if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "\tAdd token=" + wrapper.mAppWindowToken); targets.add(target); } else { + if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "\tRemove token=" + wrapper.mAppWindowToken); // We can't really start an animation but we still need to make sure to finish the // pending animation that was started by SurfaceAnimator @@ -164,22 +180,29 @@ class RemoteAnimationController implements DeathRecipient { } private void onAnimationFinished() { + if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "onAnimationFinished(): mPendingAnimations=" + + mPendingAnimations.size()); mHandler.removeCallbacks(mTimeoutRunnable); synchronized (mService.mWindowMap) { unlinkToDeathOfRunner(); releaseFinishedCallback(); mService.openSurfaceTransaction(); try { + if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "onAnimationFinished(): Notify animation finished:"); for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { final RemoteAnimationAdapterWrapper adapter = mPendingAnimations.get(i); adapter.mCapturedFinishCallback.onAnimationFinished(adapter); + if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "\t" + adapter.mAppWindowToken); } + } catch (Exception e) { + Slog.e(TAG, "Failed to finish remote animation", e); + throw e; } finally { mService.closeSurfaceTransaction("RemoteAnimationController#finished"); } } sendRunningRemoteAnimation(false); - if (DEBUG_APP_TRANSITIONS) Slog.i(TAG, "Finishing remote animation"); + if (DEBUG_REMOTE_ANIMATIONS) Slog.i(TAG, "Finishing remote animation"); } private void invokeAnimationCancelled() { @@ -221,7 +244,7 @@ class RemoteAnimationController implements DeathRecipient { @Override public void binderDied() { - cancelAnimation(); + cancelAnimation("binderDied"); } private static final class FinishedCallback extends IRemoteAnimationFinishedCallback.Stub { @@ -234,6 +257,7 @@ class RemoteAnimationController implements DeathRecipient { @Override public void onAnimationFinished() throws RemoteException { + if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "app-onAnimationFinished(): mOuter=" + mOuter); final long token = Binder.clearCallingIdentity(); try { if (mOuter != null) { @@ -253,6 +277,7 @@ class RemoteAnimationController implements DeathRecipient { * to prevent memory leak. */ void release() { + if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "app-release(): mOuter=" + mOuter); mOuter = null; } }; @@ -316,6 +341,7 @@ class RemoteAnimationController implements DeathRecipient { @Override public void startAnimation(SurfaceControl animationLeash, Transaction t, OnAnimationFinishedCallback finishCallback) { + if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "startAnimation"); // Restore z-layering, position and stack crop until client has a chance to modify it. t.setLayer(animationLeash, mAppWindowToken.getPrefixOrderIndex()); diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java index 7eaca5d42bb11..c63da77d4a476 100644 --- a/services/core/java/com/android/server/wm/WallpaperController.java +++ b/services/core/java/com/android/server/wm/WallpaperController.java @@ -620,7 +620,7 @@ class WallpaperController { // If there was a recents animation in progress, cancel that animation if (mService.getRecentsAnimationController() != null) { mService.getRecentsAnimationController().cancelAnimation( - REORDER_MOVE_TO_ORIGINAL_POSITION); + REORDER_MOVE_TO_ORIGINAL_POSITION, "wallpaperDrawPendingTimeout"); } return true; } diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java index 9d9805abb0bbe..990eb97e88c86 100644 --- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java +++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java @@ -74,6 +74,9 @@ public class WindowManagerDebugConfig { static final boolean SHOW_STACK_CRAWLS = false; static final boolean DEBUG_WINDOW_CROP = false; static final boolean DEBUG_UNKNOWN_APP_VISIBILITY = false; + // TODO (b/73188263): Reset debugging flags + static final boolean DEBUG_RECENTS_ANIMATIONS = true; + static final boolean DEBUG_REMOTE_ANIMATIONS = DEBUG_APP_TRANSITIONS || true; static final String TAG_KEEP_SCREEN_ON = "DebugKeepScreenOn"; static final boolean DEBUG_KEEP_SCREEN_ON = false; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 2b5620c1bbb03..768fa5edd70e7 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2729,13 +2729,19 @@ public class WindowManagerService extends IWindowManager.Stub } } - public void cancelRecentsAnimation(@RecentsAnimationController.ReorderMode int reorderMode) { + /** + * Cancels any running recents animation. The caller should NOT hold the WM lock while calling + * this method, as it can call back into AM, and locking will be done in the animation + * controller itself. + */ + public void cancelRecentsAnimation(@RecentsAnimationController.ReorderMode int reorderMode, + String reason) { // Note: Do not hold the WM lock, this will lock appropriately in the call which also // calls through to AM/RecentsAnimation.onAnimationFinished() if (mRecentsAnimationController != null) { // This call will call through to cleanupAnimation() below after the animation is // canceled - mRecentsAnimationController.cancelAnimation(reorderMode); + mRecentsAnimationController.cancelAnimation(reorderMode, reason); } }