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

Commit 9cfa90a5 authored by Patrick Williams's avatar Patrick Williams
Browse files

Fix temporary leak of SurfaceView when using SCVH

Bug: 358047278
Flag: EXEMPT bugfix
Test: manually verify LeakCanary doesn't detect leaks in test app with a remote SCVH
Change-Id: Ib06518d1b20ba7b075cc88877c1463d387c61054
parent bbfda47b
Loading
Loading
Loading
Loading
+94 −48
Original line number Diff line number Diff line
@@ -325,17 +325,62 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall

    private String mTag = TAG;

    private final ISurfaceControlViewHostParent mSurfaceControlViewHostParent =
            new ISurfaceControlViewHostParent.Stub() {
    private static class SurfaceControlViewHostParent extends ISurfaceControlViewHostParent.Stub {

        /**
         * mSurfaceView is set in {@link #attach} and cleared in {@link #detach} to prevent
         * temporary memory leaks. The remote process's ISurfaceControlViewHostParent binder
         * reference extends this object's lifetime. If mSurfaceView is not cleared in
         * {@link #detach}, then the SurfaceView and anything it references will not be promptly
         * garbage collected.
         */
        @Nullable
        private SurfaceView mSurfaceView;

        void attach(SurfaceView sv) {
            synchronized (this) {
                try {
                    sv.mSurfacePackage.getRemoteInterface().attachParentInterface(this);
                    mSurfaceView = sv;
                } catch (RemoteException e) {
                    Log.d(TAG, "Failed to attach parent interface to SCVH. Likely SCVH is alraedy "
                            + "dead.");
                }
            }
        }

        void detach() {
            synchronized (this) {
                if (mSurfaceView == null) {
                    return;
                }
                try {
                    mSurfaceView.mSurfacePackage.getRemoteInterface().attachParentInterface(null);
                } catch (RemoteException e) {
                    Log.d(TAG, "Failed to remove parent interface from SCVH. Likely SCVH is "
                            + "already dead");
                }
                mSurfaceView = null;
            }
        }

        @Override
        public void updateParams(WindowManager.LayoutParams[] childAttrs) {
            mEmbeddedWindowParams.clear();
            mEmbeddedWindowParams.addAll(Arrays.asList(childAttrs));
            SurfaceView sv;
            synchronized (this) {
                sv = mSurfaceView;
            }
            if (sv == null) {
                return;
            }

            sv.mEmbeddedWindowParams.clear();
            sv.mEmbeddedWindowParams.addAll(Arrays.asList(childAttrs));

            if (isAttachedToWindow()) {
                runOnUiThread(() -> {
                    if (mParent != null) {
                        mParent.recomputeViewAttributes(SurfaceView.this);
            if (sv.isAttachedToWindow()) {
                sv.runOnUiThread(() -> {
                    if (sv.mParent != null) {
                        sv.mParent.recomputeViewAttributes(sv);
                    }
                });
            }
@@ -343,15 +388,23 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall

        @Override
        public void forwardBackKeyToParent(@NonNull KeyEvent keyEvent) {
                runOnUiThread(() -> {
                    if (!isAttachedToWindow() || keyEvent.getKeyCode() != KeyEvent.KEYCODE_BACK) {
            SurfaceView sv;
            synchronized (this) {
                sv = mSurfaceView;
            }
            if (sv == null) {
                return;
            }
                    final ViewRootImpl vri = getViewRootImpl();

            sv.runOnUiThread(() -> {
                if (!sv.isAttachedToWindow() || keyEvent.getKeyCode() != KeyEvent.KEYCODE_BACK) {
                    return;
                }
                final ViewRootImpl vri = sv.getViewRootImpl();
                if (vri == null) {
                    return;
                }
                    final InputManager inputManager = mContext.getSystemService(InputManager.class);
                final InputManager inputManager = sv.mContext.getSystemService(InputManager.class);
                if (inputManager == null) {
                    return;
                }
@@ -370,7 +423,10 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
                        true /* processImmediately */);
            });
        }
    };
    }

    private final SurfaceControlViewHostParent mSurfaceControlViewHostParent =
            new SurfaceControlViewHostParent();

    private final boolean mRtDrivenClipping = Flags.clipSurfaceviews();

@@ -930,13 +986,8 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
            }

            if (mSurfacePackage != null) {
                try {
                    mSurfacePackage.getRemoteInterface().attachParentInterface(null);
                mSurfaceControlViewHostParent.detach();
                mEmbeddedWindowParams.clear();
                } catch (RemoteException e) {
                    Log.d(TAG, "Failed to remove parent interface from SCVH. Likely SCVH is "
                            + "already dead");
                }
                if (releaseSurfacePackage) {
                    mSurfacePackage.release();
                    mSurfacePackage = null;
@@ -2067,12 +2118,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
            applyTransactionOnVriDraw(transaction);
        }
        mSurfacePackage = p;
        try {
            mSurfacePackage.getRemoteInterface().attachParentInterface(
                    mSurfaceControlViewHostParent);
        } catch (RemoteException e) {
            Log.d(TAG, "Failed to attach parent interface to SCVH. Likely SCVH is already dead.");
        }
        mSurfaceControlViewHostParent.attach(this);

        if (isFocused()) {
            requestEmbeddedFocus(true);