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

Commit b5336601 authored by Shan Huang's avatar Shan Huang
Browse files

Avoid leaking Activity from OnBackInvokedCallback.

- Remove mTopCallback field
- Cleanup compat and default callbacks
- Remove the callback held by WindowState when the window is removed.

Bug: 218328707
Test: atest packages/apps/Launcher3/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
Test: atest frameworks/base/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
Change-Id: I38fd760a617500c874aef10bc8de165880837008
parent 56fc3f5e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -2668,6 +2668,7 @@ public class Activity extends ContextThemeWrapper

        if (mDefaultBackCallback != null) {
            getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(mDefaultBackCallback);
            mDefaultBackCallback = null;
        }
    }

+1 −0
Original line number Diff line number Diff line
@@ -465,6 +465,7 @@ public class Dialog implements DialogInterface, Window.Callback,
                }
            };
            getOnBackInvokedDispatcher().registerSystemOnBackInvokedCallback(mDefaultBackCallback);
            mDefaultBackCallback = null;
        }
    }

+1 −0
Original line number Diff line number Diff line
@@ -10838,6 +10838,7 @@ public final class ViewRootImpl implements ViewParent,
    private void unregisterCompatOnBackInvokedCallback() {
        if (mCompatOnBackInvokedCallback != null) {
            mOnBackInvokedDispatcher.unregisterOnBackInvokedCallback(mCompatOnBackInvokedCallback);
            mCompatOnBackInvokedCallback = null;
        }
    }

+39 −40
Original line number Diff line number Diff line
@@ -55,10 +55,6 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
    private static final boolean IS_BACK_PREDICTABILITY_ENABLED = SystemProperties
            .getInt(BACK_PREDICTABILITY_PROP, 0) > 0;

    /** The currently most prioritized callback. */
    @Nullable
    private OnBackInvokedCallbackWrapper mTopCallback;

    /** Convenience hashmap to quickly decide if a callback has been added. */
    private final HashMap<OnBackInvokedCallback, Integer> mAllCallbacks = new HashMap<>();
    /** Holds all callbacks by priorities. */
@@ -72,8 +68,8 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
    public void attachToWindow(@NonNull IWindowSession windowSession, @NonNull IWindow window) {
        mWindowSession = windowSession;
        mWindow = window;
        if (mTopCallback != null) {
            setTopOnBackInvokedCallback(mTopCallback);
        if (!mAllCallbacks.isEmpty()) {
            setTopOnBackInvokedCallback(getTopCallback());
        }
    }

@@ -81,6 +77,7 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
    public void detachFromWindow() {
        mWindow = null;
        mWindowSession = null;
        clear();
    }

    // TODO: Take an Executor for the callback to run on.
@@ -110,11 +107,13 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
            mOnBackInvokedCallbacks.get(prevPriority).remove(callback);
        }

        OnBackInvokedCallback previousTopCallback = getTopCallback();
        callbacks.add(callback);
        mAllCallbacks.put(callback, priority);
        if (mTopCallback == null || (mTopCallback.getCallback() != callback
                && mAllCallbacks.get(mTopCallback.getCallback()) <= priority)) {
            setTopOnBackInvokedCallback(new OnBackInvokedCallbackWrapper(callback, priority));
        if (previousTopCallback == null
                || (previousTopCallback != callback
                        && mAllCallbacks.get(previousTopCallback) <= priority)) {
            setTopOnBackInvokedCallback(callback);
        }
    }

@@ -126,11 +125,17 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
            }
            return;
        }
        OnBackInvokedCallback previousTopCallback = getTopCallback();
        Integer priority = mAllCallbacks.get(callback);
        mOnBackInvokedCallbacks.get(priority).remove(callback);
        ArrayList<OnBackInvokedCallback> callbacks = mOnBackInvokedCallbacks.get(priority);
        callbacks.remove(callback);
        if (callbacks.isEmpty()) {
            mOnBackInvokedCallbacks.remove(priority);
        }
        mAllCallbacks.remove(callback);
        if (mTopCallback != null && mTopCallback.getCallback() == callback) {
            findAndSetTopOnBackInvokedCallback();
        // Re-populate the top callback to WM if the removed callback was previously the top one.
        if (previousTopCallback == callback) {
            setTopOnBackInvokedCallback(getTopCallback());
        }
    }

@@ -141,41 +146,26 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {

    /** Clears all registered callbacks on the instance. */
    public void clear() {
        mAllCallbacks.clear();
        mTopCallback = null;
        mOnBackInvokedCallbacks.clear();
    }

    /**
     * Iterates through all callbacks to find the most prioritized one and pushes it to
     * window manager.
     */
    private void findAndSetTopOnBackInvokedCallback() {
        if (mAllCallbacks.isEmpty()) {
        if (!mAllCallbacks.isEmpty()) {
            // Clear binder references in WM.
            setTopOnBackInvokedCallback(null);
            return;
        }

        for (Integer priority : mOnBackInvokedCallbacks.descendingKeySet()) {
            ArrayList<OnBackInvokedCallback> callbacks = mOnBackInvokedCallbacks.get(priority);
            if (!callbacks.isEmpty()) {
                OnBackInvokedCallbackWrapper callback = new OnBackInvokedCallbackWrapper(
                        callbacks.get(callbacks.size() - 1), priority);
                setTopOnBackInvokedCallback(callback);
                return;
            }
        }
        setTopOnBackInvokedCallback(null);
        mAllCallbacks.clear();
        mOnBackInvokedCallbacks.clear();
    }

    // Pushes the top priority callback to window manager.
    private void setTopOnBackInvokedCallback(@Nullable OnBackInvokedCallbackWrapper callback) {
        mTopCallback = callback;
    private void setTopOnBackInvokedCallback(@Nullable OnBackInvokedCallback callback) {
        if (mWindowSession == null || mWindow == null) {
            return;
        }
        try {
            mWindowSession.setOnBackInvokedCallback(mWindow, mTopCallback);
            if (callback == null) {
                mWindowSession.setOnBackInvokedCallback(mWindow, null);
            } else {
                int priority = mAllCallbacks.get(callback);
                mWindowSession.setOnBackInvokedCallback(
                        mWindow, new OnBackInvokedCallbackWrapper(callback, priority));
            }
        } catch (RemoteException e) {
            Log.e(TAG, "Failed to set OnBackInvokedCallback to WM. Error: " + e);
        }
@@ -220,7 +210,16 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {

    @Override
    public OnBackInvokedCallback getTopCallback() {
        return mTopCallback == null ? null : mTopCallback.getCallback();
        if (mAllCallbacks.isEmpty()) {
            return null;
        }
        for (Integer priority : mOnBackInvokedCallbacks.descendingKeySet()) {
            ArrayList<OnBackInvokedCallback> callbacks = mOnBackInvokedCallbacks.get(priority);
            if (!callbacks.isEmpty()) {
                return callbacks.get(callbacks.size() - 1);
            }
        }
        return null;
    }

    /**
+2 −0
Original line number Diff line number Diff line
@@ -2385,6 +2385,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
        dc.getDisplayPolicy().removeWindowLw(this);

        disposeInputChannel();
        mOnBackInvokedCallback = null;

        mSession.windowRemovedLocked();
        try {
@@ -2438,6 +2439,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP

        try {
            disposeInputChannel();
            mOnBackInvokedCallback = null;

            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
                    "Remove %s: mSurfaceController=%s mAnimatingExit=%b mRemoveOnExit=%b "