Move WebView overlay support off of NewWeakGlobalRef

Test: ?
Bug: 194893628
Change-Id: Idab4dbdfa958b383754db703b76503a63a8b9d26
This commit is contained in:
John Reck
2021-08-11 16:37:59 -04:00
parent 594724fc28
commit 0ba298a7e4
4 changed files with 138 additions and 100 deletions

View File

@@ -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.
*

View File

@@ -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();
}

View File

@@ -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);

View File

@@ -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);
});
}
}