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

Commit 0ba298a7 authored by John Reck's avatar John Reck
Browse files

Move WebView overlay support off of NewWeakGlobalRef

Test: ?
Bug: 194893628
Change-Id: Idab4dbdfa958b383754db703b76503a63a8b9d26
parent 594724fc
Loading
Loading
Loading
Loading
+121 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.BLASTBufferQueue;
import android.graphics.FrameInfo;
import android.graphics.HardwareRenderer;
import android.graphics.Picture;
@@ -257,6 +258,76 @@ public final class ThreadedRenderer extends HardwareRenderer {
    private boolean mEnabled;
    private boolean mRequested = true;

    /**
     * This child class exists to break ownership cycles. ViewRootImpl owns a ThreadedRenderer
     * which owns a WebViewOverlayProvider. WebViewOverlayProvider will in turn be set as
     * the listener for HardwareRenderer callbacks. By keeping this a child class, there are
     * no cycles in the chain. The ThreadedRenderer will remain GC-able if any callbacks are
     * still outstanding, which will in turn release any JNI references to WebViewOverlayProvider.
     */
    private static final class WebViewOverlayProvider implements
            PrepareSurfaceControlForWebviewCallback, ASurfaceTransactionCallback {
        private static final boolean sOverlaysAreEnabled =
                HardwareRenderer.isWebViewOverlaysEnabled();
        private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
        private boolean mHasWebViewOverlays = false;
        private BLASTBufferQueue mBLASTBufferQueue;
        private SurfaceControl mSurfaceControl;

        public boolean setSurfaceControlOpaque(boolean opaque) {
            synchronized (this) {
                if (mHasWebViewOverlays) return false;
                mTransaction.setOpaque(mSurfaceControl, opaque).apply();
            }
            return opaque;
        }

        public boolean shouldEnableOverlaySupport() {
            return sOverlaysAreEnabled && mSurfaceControl != null && mBLASTBufferQueue != null;
        }

        public void setSurfaceControl(SurfaceControl surfaceControl) {
            synchronized (this) {
                mSurfaceControl = surfaceControl;
                if (mSurfaceControl != null && mHasWebViewOverlays) {
                    mTransaction.setOpaque(surfaceControl, false).apply();
                }
            }
        }

        public void setBLASTBufferQueue(BLASTBufferQueue bufferQueue) {
            synchronized (this) {
                mBLASTBufferQueue = bufferQueue;
            }
        }

        @Override
        public void prepare() {
            synchronized (this) {
                mHasWebViewOverlays = true;
                if (mSurfaceControl != null) {
                    mTransaction.setOpaque(mSurfaceControl, false).apply();
                }
            }
        }

        @Override
        public boolean onMergeTransaction(long nativeTransactionObj,
                long aSurfaceControlNativeObj, long frameNr) {
            synchronized (this) {
                if (mBLASTBufferQueue == null) {
                    return false;
                } else {
                    mBLASTBufferQueue.mergeWithNextTransaction(nativeTransactionObj, frameNr);
                    return true;
                }
            }
        }
    }

    private final WebViewOverlayProvider mWebViewOverlayProvider = new WebViewOverlayProvider();
    private boolean mWebViewOverlaysEnabled = false;

    @Nullable
    private ArrayList<FrameDrawingCallback> mNextRtFrameCallbacks;

@@ -454,6 +525,56 @@ public final class ThreadedRenderer extends HardwareRenderer {
        setLightCenter(attachInfo);
    }

    /**
     * Whether or not the renderer owns the SurfaceControl's opacity. If true, use
     * {@link #setSurfaceControlOpaque(boolean)} to update the opacity
     */
    public boolean rendererOwnsSurfaceControlOpacity() {
        return mWebViewOverlayProvider.mSurfaceControl != null;
    }

    /**
     * Sets the SurfaceControl's opacity that this HardwareRenderer is rendering onto. The renderer
     * may opt to override the opacity, and will return the value that is ultimately set
     *
     * @return true if the surface is opaque, false otherwise
     *
     * @hide
     */
    public boolean setSurfaceControlOpaque(boolean opaque) {
        return mWebViewOverlayProvider.setSurfaceControlOpaque(opaque);
    }

    private void updateWebViewOverlayCallbacks() {
        boolean shouldEnable = mWebViewOverlayProvider.shouldEnableOverlaySupport();
        if (shouldEnable != mWebViewOverlaysEnabled) {
            mWebViewOverlaysEnabled = shouldEnable;
            if (shouldEnable) {
                setASurfaceTransactionCallback(mWebViewOverlayProvider);
                setPrepareSurfaceControlForWebviewCallback(mWebViewOverlayProvider);
            } else {
                setASurfaceTransactionCallback(null);
                setPrepareSurfaceControlForWebviewCallback(null);
            }
        }
    }

    @Override
    public void setSurfaceControl(@Nullable SurfaceControl surfaceControl) {
        super.setSurfaceControl(surfaceControl);
        mWebViewOverlayProvider.setSurfaceControl(surfaceControl);
        updateWebViewOverlayCallbacks();
    }

    /**
     * Sets the BLASTBufferQueue being used for rendering. This is required to be specified
     * for WebView overlay support
     */
    public void setBlastBufferQueue(@Nullable BLASTBufferQueue blastBufferQueue) {
        mWebViewOverlayProvider.setBLASTBufferQueue(blastBufferQueue);
        updateWebViewOverlayCallbacks();
    }

    /**
     * Updates the light position based on the position of the window.
     *
+7 −52
Original line number Diff line number Diff line
@@ -485,9 +485,6 @@ public final class ViewRootImpl implements ViewParent,
    protected final ViewFrameInfo mViewFrameInfo = new ViewFrameInfo();
    private final InputEventAssigner mInputEventAssigner = new InputEventAssigner();

    // Set to true if mSurfaceControl is used for Webview Overlay
    private boolean mIsForWebviewOverlay;

    /**
     * Update the Choreographer's FrameInfo object with the timing information for the current
     * ViewRootImpl instance. Erase the data in the current ViewFrameInfo to prepare for the next
@@ -1386,42 +1383,6 @@ public final class ViewRootImpl implements ViewParent,
        }
    }

    /**
     * Register a callback to be executed when Webview overlay needs to merge a transaction.
     * This callback will be executed on RenderThread worker thread, and released inside native code
     * when CanvasContext is destroyed.
     */
    private void addASurfaceTransactionCallback() {
        HardwareRenderer.ASurfaceTransactionCallback callback = (nativeTransactionObj,
                                                                 nativeSurfaceControlObj,
                                                                 frameNr) -> {
            if (mBlastBufferQueue == null) {
                return false;
            } else {
                mBlastBufferQueue.mergeWithNextTransaction(nativeTransactionObj, frameNr);
                return true;
            }
        };
        mAttachInfo.mThreadedRenderer.setASurfaceTransactionCallback(callback);
    }

    /**
     * Register a callback to be executed when Webview overlay needs a surface control.
     * This callback will be executed on RenderThread worker thread, and released inside native code
     * when CanvasContext is destroyed.
     */
    private void addPrepareSurfaceControlForWebviewCallback() {
        HardwareRenderer.PrepareSurfaceControlForWebviewCallback callback = () -> {
            // make mSurfaceControl transparent, so child surface controls are visible
            if (mIsForWebviewOverlay) return;
            synchronized (ViewRootImpl.this) {
                mIsForWebviewOverlay = true;
            }
            mTransaction.setOpaque(mSurfaceControl, false).apply();
        };
        mAttachInfo.mThreadedRenderer.setPrepareSurfaceControlForWebviewCallback(callback);
    }

    @UnsupportedAppUsage
    private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
        mAttachInfo.mHardwareAccelerated = false;
@@ -1466,11 +1427,8 @@ public final class ViewRootImpl implements ViewParent,
                    if (mHardwareRendererObserver != null) {
                        mAttachInfo.mThreadedRenderer.addObserver(mHardwareRendererObserver);
                    }
                    if (HardwareRenderer.isWebViewOverlaysEnabled()) {
                        addPrepareSurfaceControlForWebviewCallback();
                        addASurfaceTransactionCallback();
                    }
                    mAttachInfo.mThreadedRenderer.setSurfaceControl(mSurfaceControl);
                    mAttachInfo.mThreadedRenderer.setBlastBufferQueue(mBlastBufferQueue);
                }
            }
        }
@@ -2041,6 +1999,7 @@ public final class ViewRootImpl implements ViewParent,

        if (mAttachInfo.mThreadedRenderer != null) {
            mAttachInfo.mThreadedRenderer.setSurfaceControl(null);
            mAttachInfo.mThreadedRenderer.setBlastBufferQueue(null);
        }
    }

@@ -7823,11 +7782,8 @@ public final class ViewRootImpl implements ViewParent,
                }
            }
            if (mAttachInfo.mThreadedRenderer != null) {
                if (HardwareRenderer.isWebViewOverlaysEnabled()) {
                    addPrepareSurfaceControlForWebviewCallback();
                    addASurfaceTransactionCallback();
                }
                mAttachInfo.mThreadedRenderer.setSurfaceControl(mSurfaceControl);
                mAttachInfo.mThreadedRenderer.setBlastBufferQueue(mBlastBufferQueue);
            }
        } else {
            destroySurface();
@@ -7873,11 +7829,10 @@ public final class ViewRootImpl implements ViewParent,
            return;
        }

        synchronized (this) {
            if (mIsForWebviewOverlay) {
                mIsSurfaceOpaque = false;
                return;
            }
        final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer;
        if (renderer != null && renderer.rendererOwnsSurfaceControlOpacity()) {
            opaque = renderer.setSurfaceControlOpaque(opaque);
        } else {
            mTransaction.setOpaque(mSurfaceControl, opaque).apply();
        }

+3 −11
Original line number Diff line number Diff line
@@ -752,22 +752,14 @@ public class HardwareRenderer {
        nCancelLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
    }

    private ASurfaceTransactionCallback mASurfaceTransactionCallback;

    /** @hide */
    public void setASurfaceTransactionCallback(ASurfaceTransactionCallback callback) {
        // ensure callback is kept alive on the java side since weak ref is used in native code
        mASurfaceTransactionCallback = callback;
    protected void setASurfaceTransactionCallback(ASurfaceTransactionCallback callback) {
        nSetASurfaceTransactionCallback(mNativeProxy, callback);
    }

    private PrepareSurfaceControlForWebviewCallback mAPrepareSurfaceControlForWebviewCallback;

    /** @hide */
    public void setPrepareSurfaceControlForWebviewCallback(
    protected void setPrepareSurfaceControlForWebviewCallback(
            PrepareSurfaceControlForWebviewCallback callback) {
        // ensure callback is kept alive on the java side since weak ref is used in native code
        mAPrepareSurfaceControlForWebviewCallback = callback;
        nSetPrepareSurfaceControlForWebviewCallback(mNativeProxy, callback);
    }

@@ -1299,7 +1291,7 @@ public class HardwareRenderer {
    /**
     * @hide
     */
    public static native boolean isWebViewOverlaysEnabled();
    protected static native boolean isWebViewOverlaysEnabled();

    /** @hide */
    protected static native void setupShadersDiskCache(String cacheFile, String skiaCacheFile);
+7 −37
Original line number Diff line number Diff line
@@ -423,28 +423,6 @@ private:
    jobject mObject;
};

class JWeakGlobalRefHolder {
public:
    JWeakGlobalRefHolder(JavaVM* vm, jobject object) : mVm(vm) {
        mWeakRef = getenv(vm)->NewWeakGlobalRef(object);
    }

    virtual ~JWeakGlobalRefHolder() {
        if (mWeakRef != nullptr) getenv(mVm)->DeleteWeakGlobalRef(mWeakRef);
        mWeakRef = nullptr;
    }

    jobject ref() { return mWeakRef; }
    JavaVM* vm() { return mVm; }

private:
    JWeakGlobalRefHolder(const JWeakGlobalRefHolder&) = delete;
    void operator=(const JWeakGlobalRefHolder&) = delete;

    JavaVM* mVm;
    jobject mWeakRef;
};

using TextureMap = std::unordered_map<uint32_t, sk_sp<SkImage>>;

struct PictureCaptureState {
@@ -578,20 +556,16 @@ static void android_view_ThreadedRenderer_setASurfaceTransactionCallback(
    } else {
        JavaVM* vm = nullptr;
        LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Unable to get Java VM");
        auto globalCallbackRef =
                std::make_shared<JWeakGlobalRefHolder>(vm, aSurfaceTransactionCallback);
        auto globalCallbackRef = std::make_shared<JGlobalRefHolder>(
                vm, env->NewGlobalRef(aSurfaceTransactionCallback));
        proxy->setASurfaceTransactionCallback(
                [globalCallbackRef](int64_t transObj, int64_t scObj, int64_t frameNr) -> bool {
                    JNIEnv* env = getenv(globalCallbackRef->vm());
                    jobject localref = env->NewLocalRef(globalCallbackRef->ref());
                    if (CC_UNLIKELY(!localref)) {
                        return false;
                    }
                    jboolean ret = env->CallBooleanMethod(
                            localref, gASurfaceTransactionCallback.onMergeTransaction,
                            globalCallbackRef->object(),
                            gASurfaceTransactionCallback.onMergeTransaction,
                            static_cast<jlong>(transObj), static_cast<jlong>(scObj),
                            static_cast<jlong>(frameNr));
                    env->DeleteLocalRef(localref);
                    return ret;
                });
    }
@@ -606,15 +580,11 @@ static void android_view_ThreadedRenderer_setPrepareSurfaceControlForWebviewCall
        JavaVM* vm = nullptr;
        LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Unable to get Java VM");
        auto globalCallbackRef =
                std::make_shared<JWeakGlobalRefHolder>(vm, callback);
                std::make_shared<JGlobalRefHolder>(vm, env->NewGlobalRef(callback));
        proxy->setPrepareSurfaceControlForWebviewCallback([globalCallbackRef]() {
            JNIEnv* env = getenv(globalCallbackRef->vm());
            jobject localref = env->NewLocalRef(globalCallbackRef->ref());
            if (CC_UNLIKELY(!localref)) {
                return;
            }
            env->CallVoidMethod(localref, gPrepareSurfaceControlForWebviewCallback.prepare);
            env->DeleteLocalRef(localref);
            env->CallVoidMethod(globalCallbackRef->object(),
                                gPrepareSurfaceControlForWebviewCallback.prepare);
        });
    }
}