Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e180de6b authored by Fengjiang Li's avatar Fengjiang Li
Browse files

Fix memory leak of Launcher activityfrom QuickstepTransitionManager and...

Fix memory leak of Launcher activityfrom QuickstepTransitionManager and LauncherBackAnimationController

We should also avoid using non-static inner class that extends IOnBackInvokedCallback.Stub and IRemoteAnimationRunner.Stub inside LauncherBackAnimationController, which references the entire LauncherBackAnimationController object.

1. When launcher is created, a Runnable is posted to ShellExecutor to call BackAnimationController#registerAnimation
2. When launcher is later destroyed, another Runnable is posted to same ShellExecturo to call BackAnimationController#unregisterAnimation
3. If the execturo queued the 1st runnable, then we have leaked LauncherBackAnimationController object, including Launcher activity.

This CL fixes the leak by making the Stub static inner classes, and use weak reference hold reference to launcher activity.

Bug: 297806573
Test: Grab a heap dump and this reference no longer exist
Flag: N/A
Change-Id: I78853e900a98399b02682ba2d9179e544a4030d5
parent b0b8e3a5
Loading
Loading
Loading
Loading
+22 −20
Original line number Original line Diff line number Diff line
@@ -159,6 +159,7 @@ import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
import com.android.wm.shell.startingsurface.IStartingWindowListener;
import com.android.wm.shell.startingsurface.IStartingWindowListener;


import java.io.PrintWriter;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.List;
@@ -225,7 +226,8 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
    private final float mClosingWindowTransY;
    private final float mClosingWindowTransY;
    private final float mMaxShadowRadius;
    private final float mMaxShadowRadius;


    private final StartingWindowListener mStartingWindowListener = new StartingWindowListener();
    private final StartingWindowListener mStartingWindowListener =
            new StartingWindowListener(this);


    private DeviceProfile mDeviceProfile;
    private DeviceProfile mDeviceProfile;


@@ -278,7 +280,6 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
                }
                }
            };
            };


            mStartingWindowListener.setTransitionManager(this);
            SystemUiProxy.INSTANCE.get(mLauncher).setStartingWindowListener(
            SystemUiProxy.INSTANCE.get(mLauncher).setStartingWindowListener(
                    mStartingWindowListener);
                    mStartingWindowListener);
        }
        }
@@ -310,8 +311,8 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
        mAppLaunchRunner = new AppLaunchAnimationRunner(v, onEndCallback);
        mAppLaunchRunner = new AppLaunchAnimationRunner(v, onEndCallback);
        ItemInfo tag = (ItemInfo) v.getTag();
        ItemInfo tag = (ItemInfo) v.getTag();
        if (tag != null && tag.shouldUseBackgroundAnimation()) {
        if (tag != null && tag.shouldUseBackgroundAnimation()) {
            ContainerAnimationRunner containerAnimationRunner =
            ContainerAnimationRunner containerAnimationRunner = ContainerAnimationRunner.from(
                    ContainerAnimationRunner.from(v, mStartingWindowListener, onEndCallback);
                            v, mLauncher, mStartingWindowListener, onEndCallback);
            if (containerAnimationRunner != null) {
            if (containerAnimationRunner != null) {
                mAppLaunchRunner = containerAnimationRunner;
                mAppLaunchRunner = containerAnimationRunner;
            }
            }
@@ -1152,7 +1153,6 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
    public void onActivityDestroyed() {
    public void onActivityDestroyed() {
        unregisterRemoteAnimations();
        unregisterRemoteAnimations();
        unregisterRemoteTransitions();
        unregisterRemoteTransitions();
        mStartingWindowListener.setTransitionManager(null);
        SystemUiProxy.INSTANCE.get(mLauncher).setStartingWindowListener(null);
        SystemUiProxy.INSTANCE.get(mLauncher).setStartingWindowListener(null);
    }
    }


@@ -1775,8 +1775,8 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
        }
        }


        @Nullable
        @Nullable
        private static ContainerAnimationRunner from(
        private static ContainerAnimationRunner from(View v, Launcher launcher,
                View v, StartingWindowListener startingWindowListener, RunnableList onEndCallback) {
                StartingWindowListener startingWindowListener, RunnableList onEndCallback) {
            View viewToUse = findViewWithBackground(v);
            View viewToUse = findViewWithBackground(v);
            if (viewToUse == null) {
            if (viewToUse == null) {
                viewToUse = v;
                viewToUse = v;
@@ -1801,8 +1801,13 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
                        }
                        }
                    };
                    };


            ActivityLaunchAnimator.Callback callback = task -> ColorUtils.setAlphaComponent(
            ActivityLaunchAnimator.Callback callback = task -> {
                    startingWindowListener.getBackgroundColor(), 255);
                final int backgroundColor =
                        startingWindowListener.mBackgroundColor == Color.TRANSPARENT
                                ? launcher.getScrimView().getBackgroundColor()
                                : startingWindowListener.mBackgroundColor;
                return ColorUtils.setAlphaComponent(backgroundColor, 255);
            };


            ActivityLaunchAnimator.Listener listener = new ActivityLaunchAnimator.Listener() {
            ActivityLaunchAnimator.Listener listener = new ActivityLaunchAnimator.Listener() {
                @Override
                @Override
@@ -1912,24 +1917,21 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
        }
        }
    }
    }


    private class StartingWindowListener extends IStartingWindowListener.Stub {
    private static class StartingWindowListener extends IStartingWindowListener.Stub {
        private QuickstepTransitionManager mTransitionManager;
        private final WeakReference<QuickstepTransitionManager> mTransitionManagerRef;
        private int mBackgroundColor;
        private int mBackgroundColor;


        public void setTransitionManager(QuickstepTransitionManager transitionManager) {
        private StartingWindowListener(QuickstepTransitionManager transitionManager) {
            mTransitionManager = transitionManager;
            mTransitionManagerRef = new WeakReference<>(transitionManager);
        }
        }


        @Override
        @Override
        public void onTaskLaunching(int taskId, int supportedType, int color) {
        public void onTaskLaunching(int taskId, int supportedType, int color) {
            mTransitionManager.mTaskStartParams.put(taskId, Pair.create(supportedType, color));
            QuickstepTransitionManager transitionManager = mTransitionManagerRef.get();
            mBackgroundColor = color;
            if (transitionManager != null) {
                transitionManager.mTaskStartParams.put(taskId, Pair.create(supportedType, color));
            }
            }

            mBackgroundColor = color;
        public int getBackgroundColor() {
            return mBackgroundColor == Color.TRANSPARENT
                    ? mLauncher.getScrimView().getBackgroundColor()
                    : mBackgroundColor;
        }
        }
    }
    }


+90 −49
Original line number Original line Diff line number Diff line
@@ -58,6 +58,8 @@ import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.QuickStepContract;


import java.lang.ref.WeakReference;

/**
/**
 * Controls the animation of swiping back and returning to launcher.
 * Controls the animation of swiping back and returning to launcher.
 *
 *
@@ -105,7 +107,7 @@ public class LauncherBackAnimationController {
    private boolean mAnimatorSetInProgress = false;
    private boolean mAnimatorSetInProgress = false;
    private float mBackProgress = 0;
    private float mBackProgress = 0;
    private boolean mBackInProgress = false;
    private boolean mBackInProgress = false;
    private IOnBackInvokedCallback mBackCallback;
    private OnBackInvokedCallbackStub mBackCallback;
    private IRemoteAnimationFinishedCallback mAnimationFinishedCallback;
    private IRemoteAnimationFinishedCallback mAnimationFinishedCallback;
    private BackProgressAnimator mProgressAnimator = new BackProgressAnimator();
    private BackProgressAnimator mProgressAnimator = new BackProgressAnimator();
    private SurfaceControl mScrimLayer;
    private SurfaceControl mScrimLayer;
@@ -137,65 +139,104 @@ public class LauncherBackAnimationController {
     * @param handler Handler to the thread to run the animations on.
     * @param handler Handler to the thread to run the animations on.
     */
     */
    public void registerBackCallbacks(Handler handler) {
    public void registerBackCallbacks(Handler handler) {
        mBackCallback = new IOnBackInvokedCallback.Stub() {
        mBackCallback = new OnBackInvokedCallbackStub(handler, mProgressAnimator, this);
        SystemUiProxy.INSTANCE.get(mLauncher).setBackToLauncherCallback(mBackCallback,
                new RemoteAnimationRunnerStub(this));
    }

    private static class OnBackInvokedCallbackStub extends IOnBackInvokedCallback.Stub {
        private Handler mHandler;
        private BackProgressAnimator mProgressAnimator;
        // LauncherBackAnimationController has strong reference to Launcher activity, the binder
        // callback should not hold strong reference to it to avoid memory leak.
        private WeakReference<LauncherBackAnimationController> mControllerRef;

        private OnBackInvokedCallbackStub(
                Handler handler,
                BackProgressAnimator progressAnimator,
                LauncherBackAnimationController controller) {
            mHandler = handler;
            mProgressAnimator = progressAnimator;
            mControllerRef = new WeakReference<>(controller);
        }

        @Override
        @Override
        public void onBackCancelled() {
        public void onBackCancelled() {
                handler.post(() -> {
            mHandler.post(() -> {
                LauncherBackAnimationController controller = mControllerRef.get();
                if (controller != null) {
                    mProgressAnimator.onBackCancelled(
                    mProgressAnimator.onBackCancelled(
                            LauncherBackAnimationController.this::resetPositionAnimated);
                            controller::resetPositionAnimated);
                }
            });
            });
        }
        }


        @Override
        @Override
        public void onBackInvoked() {
        public void onBackInvoked() {
                handler.post(() -> {
            mHandler.post(() -> {
                    startTransition();
                LauncherBackAnimationController controller = mControllerRef.get();
                if (controller != null) {
                    controller.startTransition();
                }
                mProgressAnimator.reset();
                mProgressAnimator.reset();
            });
            });
        }
        }


        @Override
        @Override
            public void onBackProgressed(BackMotionEvent backEvent) {
        public void onBackProgressed(BackMotionEvent backMotionEvent) {
                handler.post(() -> {
            mHandler.post(() -> {
                    mProgressAnimator.onBackProgressed(backEvent);
                mProgressAnimator.onBackProgressed(backMotionEvent);
            });
            });
        }
        }


        @Override
        @Override
        public void onBackStarted(BackMotionEvent backEvent) {
        public void onBackStarted(BackMotionEvent backEvent) {
                handler.post(() -> {
            mHandler.post(() -> {
                    startBack(backEvent);
                LauncherBackAnimationController controller = mControllerRef.get();
                if (controller != null) {
                    controller.startBack(backEvent);
                    mProgressAnimator.onBackStarted(backEvent, event -> {
                    mProgressAnimator.onBackStarted(backEvent, event -> {
                        mBackProgress = event.getProgress();
                        float backProgress = event.getProgress();
                        // TODO: Update once the interpolation curve spec is finalized.
                        // TODO: Update once the interpolation curve spec is finalized.
                        mBackProgress =
                        controller.mBackProgress =
                                1 - (1 - mBackProgress) * (1 - mBackProgress) * (1
                                1 - (1 - backProgress) * (1 - backProgress) * (1
                                        - mBackProgress);
                                        - backProgress);
                        updateBackProgress(mBackProgress, event);
                        controller.updateBackProgress(controller.mBackProgress, event);
                    });
                    });
                }
            });
            });
        }
        }
        };
    }

    private static class RemoteAnimationRunnerStub extends IRemoteAnimationRunner.Stub {

        // LauncherBackAnimationController has strong reference to Launcher activity, the binder
        // callback should not hold strong reference to it to avoid memory leak.
        private WeakReference<LauncherBackAnimationController> mControllerRef;

        private RemoteAnimationRunnerStub(LauncherBackAnimationController controller) {
            mControllerRef = new WeakReference<>(controller);
        }


        final IRemoteAnimationRunner runner = new IRemoteAnimationRunner.Stub() {
        @Override
        @Override
        public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
        public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
                RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
                RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
                IRemoteAnimationFinishedCallback finishedCallback) {
                IRemoteAnimationFinishedCallback finishedCallback) {
            LauncherBackAnimationController controller = mControllerRef.get();
            if (controller == null) {
                return;
            }
            for (final RemoteAnimationTarget target : apps) {
            for (final RemoteAnimationTarget target : apps) {
                if (MODE_CLOSING == target.mode) {
                if (MODE_CLOSING == target.mode) {
                        mBackTarget = target;
                    controller.mBackTarget = target;
                    break;
                    break;
                }
                }
            }
            }
                mAnimationFinishedCallback = finishedCallback;
            controller.mAnimationFinishedCallback = finishedCallback;
        }
        }


        @Override
        @Override
        public void onAnimationCancelled() {}
        public void onAnimationCancelled() {}
        };

        SystemUiProxy.INSTANCE.get(mLauncher).setBackToLauncherCallback(mBackCallback, runner);
    }
    }


    private void resetPositionAnimated() {
    private void resetPositionAnimated() {