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

Commit 8bda907a authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Move WebView overlay support off of NewWeakGlobalRef"

parents 24beb0a3 0ba298a7
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);
        });
    }
}