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

Commit fbd99f24 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add WindowContextCleaner" into main

parents 227a2c6a ac2d530e
Loading
Loading
Loading
Loading
+14 −5
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.StrictMode.vmIncorrectContextUseEnabled;
import static android.permission.flags.Flags.shouldRegisterAttributionSource;
import static android.view.WindowManager.LayoutParams.WindowType;
import static android.window.WindowContext.registerCleaner;

import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
@@ -3429,12 +3430,17 @@ class ContextImpl extends Context {
        // WindowContainer. We should detach from WindowContainer when the Context is finalized
        // if this Context is not a WindowContext. WindowContext finalization is handled in
        // WindowContext class.
        if (mToken instanceof WindowTokenClient && mOwnsToken) {
            WindowTokenClientController.getInstance().detachIfNeeded(
                    (WindowTokenClient) mToken);
        try {
            if (!(com.android.window.flags.Flags.cleanUpWindowContextWithCleaner()
                    || com.android.window.flags.Flags.trackSystemUiContextBeforeWms())
                    && mToken instanceof WindowTokenClient && mOwnsToken) {
                WindowTokenClientController.getInstance()
                        .detachIfNeeded((WindowTokenClient) mToken);
            }
        } finally {
            super.finalize();
        }
    }

    @UnsupportedAppUsage
    static ContextImpl createSystemContext(ActivityThread mainThread) {
@@ -3476,7 +3482,10 @@ class ContextImpl extends Context {
        WindowTokenClientController.getInstance().attachToDisplayContent(token, displayId);
        context.mContextType = CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI;
        context.mOwnsToken = true;

        if (!com.android.window.flags.Flags.trackSystemUiContextBeforeWms()) {
            // #registerCleaner only support SystemUiContext or WindowContext.
            registerCleaner(systemUiContext);
        }
        return systemUiContext;
    }

+1 −1
Original line number Diff line number Diff line
@@ -999,7 +999,7 @@ interface IWindowManager
     *
     * @param clientToken the window context's token
     */
    void detachWindowContext(IBinder clientToken);
    oneway void detachWindowContext(IBinder clientToken);

    /**
     * Reparents the {@link android.window.WindowContext} to the
+56 −6
Original line number Diff line number Diff line
@@ -42,6 +42,8 @@ import com.android.window.flags.Flags;

import java.lang.ref.Reference;

import sun.misc.Cleaner;

/**
 * {@link WindowContext} is a context for non-activity windows such as
 * {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY} windows or system
@@ -92,9 +94,9 @@ public class WindowContext extends ContextWrapper implements WindowProvider,
        mType = type;
        mOptions = options;
        mWindowManager = createWindowContextWindowManager(this);
        WindowTokenClient token = (WindowTokenClient) getWindowContextToken();
        mController = new WindowContextController(requireNonNull(token));

        WindowTokenClient token = (WindowTokenClient) requireNonNull(getWindowContextToken());
        mController = new WindowContextController(token);
        registerCleaner(this);
        Reference.reachabilityFence(this);
    }

@@ -134,9 +136,14 @@ public class WindowContext extends ContextWrapper implements WindowProvider,

    @Override
    protected void finalize() throws Throwable {
        try {
            if (!Flags.cleanUpWindowContextWithCleaner()) {
                release();
            }
        } finally {
            super.finalize();
        }
    }

    /** Used for test to invoke because we can't invoke finalize directly. */
    @VisibleForTesting
@@ -287,4 +294,47 @@ public class WindowContext extends ContextWrapper implements WindowProvider,
            return mDecorView;
        }
    }

    /**
     * Registers a {@link WindowContext} or a {@link SystemUiContext} with a cleaner.
     *
     * @throws IllegalArgumentException if the context is not a {@link WindowContext} or
     * {@link SystemUiContext}.
     */
    public static void registerCleaner(@NonNull Context context) {
        if (!Flags.cleanUpWindowContextWithCleaner()) {
            return;
        }

        if (!(context instanceof WindowContext) && !(context instanceof SystemUiContext)) {
            throw new IllegalArgumentException("The context must be either WindowContext or"
                    + " SystemUiContext.");
        }
        final ContextWrapper wrapper = (ContextWrapper) context;
        Cleaner.create(context, new WindowContextCleaner(wrapper));
    }

    /**
     * A {@link WindowContext} cleaner that applies when the {@link WindowContext} is going to be
     * garbage-collected.
     */
    private static class WindowContextCleaner implements Runnable {

        @NonNull
        private final Context mBaseContext;

        WindowContextCleaner(@NonNull ContextWrapper wrapper) {
            // Cache the base Context to prevent hold the reference of WindowContext. The cleaner
            // will work only if all strong references of WindowContext are gone.
            mBaseContext = requireNonNull(wrapper.getBaseContext());
        }

        @Override
        public void run() {
            final WindowTokenClient token =
                    (WindowTokenClient) requireNonNull(mBaseContext.getWindowContextToken());
            WindowTokenClientController.getInstance().detachIfNeeded(token);
            mBaseContext.destroy();
        }
    }
}
+11 −0
Original line number Diff line number Diff line
@@ -232,3 +232,14 @@ flag {
        purpose: PURPOSE_BUGFIX
    }
}

flag {
    namespace: "windowing_sdk"
    name: "clean_up_window_context_with_cleaner"
    description: "Using Cleaner to clean up WindowContext instead of overriding finalize"
    bug: "339727951"
    is_fixed_read_only: true
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}
+21 −0
Original line number Diff line number Diff line
@@ -53,9 +53,11 @@ import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.platform.test.flag.junit.SetFlagsRule;
import android.util.PollingCheck;
import android.view.Display;
import android.view.IWindowManager;
import android.view.View;
@@ -71,6 +73,7 @@ import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;

import com.android.frameworks.coretests.R;
import com.android.internal.util.GcUtils;
import com.android.window.flags.Flags;

import org.junit.After;
@@ -515,6 +518,24 @@ public class WindowContextTest {
        return (WindowContext) instContext.createWindowContext(display, type,  null /* options */);
    }

    @Test
    public void testWindowContextCleanup() {
        final WindowContext windowContext = createWindowContext();

        windowContext.getSystemService(WindowManager.class).getCurrentWindowMetrics();

        GcUtils.runGcAndFinalizersSync();

        PollingCheck.waitFor(() -> {
            try {
                return !mWms.isWindowToken(windowContext.getWindowContextToken());
            } catch (RemoteException e) {
                fail("Fail due to " + e);
            }
            return false;
        });
    }

    private static class ConfigurationListener implements ComponentCallbacks {
        private Configuration mConfiguration;
        private CountDownLatch mLatch = new CountDownLatch(1);