Webview overlay support

The basic idea is to create a child surface control from the root surface control passed from ViewRootImpl to the render thread.

Transactions are sent back to the java layer to get merged.

In case of offscreen layers, SurfaceControl must be disabled.

This new feature is disabled for Vulkan at the moment, a new CL will be used to enable the support.

Bug: 173671170
Test: manual, webview apks
Change-Id: I119405d13eca3c59fd3ec78e50dc7739f78411d4
This commit is contained in:
Huihong Luo
2021-02-24 18:48:12 -08:00
parent c6df2ba06a
commit 054b8d3000
12 changed files with 210 additions and 8 deletions

View File

@@ -2595,6 +2595,16 @@ public final class SurfaceControl implements Parcelable {
= sRegistry.registerNativeAllocation(this, mNativeObject);
}
/**
* Create a transaction object that wraps a native peer.
* @hide
*/
Transaction(long nativeObject) {
mNativeObject = nativeObject;
mFreeNativeResources =
sRegistry.registerNativeAllocation(this, mNativeObject);
}
private Transaction(Parcel in) {
readFromParcel(in);
}

View File

@@ -1355,6 +1355,16 @@ public final class ViewRootImpl implements ViewParent,
}
}
private void addASurfaceTransactionCallback() {
HardwareRenderer.ASurfaceTransactionCallback callback = (nativeTransactionObj,
nativeSurfaceControlObj,
frameNr) -> {
Transaction t = new Transaction(nativeTransactionObj);
mergeWithNextTransaction(t, frameNr);
};
mAttachInfo.mThreadedRenderer.setASurfaceTransactionCallback(callback);
}
@UnsupportedAppUsage
private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
mAttachInfo.mHardwareAccelerated = false;
@@ -1391,6 +1401,7 @@ public final class ViewRootImpl implements ViewParent,
final boolean translucent = attrs.format != PixelFormat.OPAQUE || hasSurfaceInsets;
mAttachInfo.mThreadedRenderer = ThreadedRenderer.create(mContext, translucent,
attrs.getTitle().toString());
addASurfaceTransactionCallback();
mAttachInfo.mThreadedRenderer.setSurfaceControl(mSurfaceControl);
updateColorModeIfNeeded(attrs.getColorMode());
updateForceDarkMode();

View File

@@ -753,6 +753,11 @@ public class HardwareRenderer {
nCancelLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
}
/** @hide */
public void setASurfaceTransactionCallback(ASurfaceTransactionCallback callback) {
nSetASurfaceTransactionCallback(mNativeProxy, callback);
}
/** @hide */
public void setFrameCallback(FrameDrawingCallback callback) {
nSetFrameCallback(mNativeProxy, callback);
@@ -867,6 +872,23 @@ public class HardwareRenderer {
session.close();
}
/**
* Interface used to receive callbacks when a transaction needs to be merged.
*
* @hide
*/
public interface ASurfaceTransactionCallback {
/**
* Invoked during a frame drawing.
*
* @param aSurfaceTranactionNativeObj the ASurfaceTransaction native object handle
* @param aSurfaceControlNativeObj ASurfaceControl native object handle
* @param frame The id of the frame being drawn.
*/
void onMergeTransaction(long aSurfaceTranactionNativeObj,
long aSurfaceControlNativeObj, long frame);
}
/**
* Interface used to receive callbacks when a frame is being drawn.
*
@@ -1342,6 +1364,9 @@ public class HardwareRenderer {
private static native void nSetPictureCaptureCallback(long nativeProxy,
PictureCapturedCallback callback);
private static native void nSetASurfaceTransactionCallback(long nativeProxy,
ASurfaceTransactionCallback callback);
private static native void nSetFrameCallback(long nativeProxy, FrameDrawingCallback callback);
private static native void nSetFrameCompleteCallback(long nativeProxy,

View File

@@ -18,6 +18,7 @@
#include <private/hwui/WebViewFunctor.h>
#include "Properties.h"
#include "renderthread/CanvasContext.h"
#include "renderthread/RenderThread.h"
#include <log/log.h>
@@ -115,11 +116,20 @@ void WebViewFunctor::drawGl(const DrawGlInfo& drawInfo) {
ScopedCurrentFunctor currentFunctor(this);
WebViewOverlayData overlayParams = {
// TODO:
.overlaysMode = OverlaysMode::Disabled,
.getSurfaceControl = currentFunctor.getSurfaceControl,
.mergeTransaction = currentFunctor.mergeTransaction,
};
if (!drawInfo.isLayer) {
renderthread::CanvasContext* activeContext =
renderthread::CanvasContext::getActiveContext();
if (activeContext != nullptr) {
ASurfaceControl* rootSurfaceControl = activeContext->getSurfaceControl();
if (rootSurfaceControl) overlayParams.overlaysMode = OverlaysMode::Enabled;
}
}
mCallbacks.gles.draw(mFunctor, mData, drawInfo, overlayParams);
}
@@ -138,11 +148,12 @@ void WebViewFunctor::drawVk(const VkFunctorDrawParams& params) {
ScopedCurrentFunctor currentFunctor(this);
WebViewOverlayData overlayParams = {
// TODO
.overlaysMode = OverlaysMode::Disabled,
.getSurfaceControl = currentFunctor.getSurfaceControl,
.mergeTransaction = currentFunctor.mergeTransaction,
};
// TODO, enable surface control once offscreen mode figured out
mCallbacks.vk.draw(mFunctor, mData, params, overlayParams);
}
@@ -166,15 +177,43 @@ void WebViewFunctor::destroyContext() {
void WebViewFunctor::removeOverlays() {
ScopedCurrentFunctor currentFunctor(this);
mCallbacks.removeOverlays(mFunctor, mData, currentFunctor.mergeTransaction);
if (mSurfaceControl) {
auto funcs = renderthread::RenderThread::getInstance().getASurfaceControlFunctions();
funcs.releaseFunc(mSurfaceControl);
mSurfaceControl = nullptr;
}
}
ASurfaceControl* WebViewFunctor::getSurfaceControl() {
// TODO
return nullptr;
ATRACE_NAME("WebViewFunctor::getSurfaceControl");
if (mSurfaceControl != nullptr) return mSurfaceControl;
renderthread::CanvasContext* activeContext = renderthread::CanvasContext::getActiveContext();
LOG_ALWAYS_FATAL_IF(activeContext == nullptr, "Null active canvas context!");
ASurfaceControl* rootSurfaceControl = activeContext->getSurfaceControl();
LOG_ALWAYS_FATAL_IF(rootSurfaceControl == nullptr, "Null root surface control!");
auto funcs = renderthread::RenderThread::getInstance().getASurfaceControlFunctions();
mSurfaceControl = funcs.createFunc(rootSurfaceControl, "Webview Overlay SurfaceControl");
ASurfaceTransaction* transaction = funcs.transactionCreateFunc();
funcs.transactionSetVisibilityFunc(transaction, mSurfaceControl,
ASURFACE_TRANSACTION_VISIBILITY_SHOW);
funcs.transactionApplyFunc(transaction);
funcs.transactionDeleteFunc(transaction);
return mSurfaceControl;
}
void WebViewFunctor::mergeTransaction(ASurfaceTransaction* transaction) {
// TODO
ATRACE_NAME("WebViewFunctor::mergeTransaction");
if (transaction == nullptr) return;
renderthread::CanvasContext* activeContext = renderthread::CanvasContext::getActiveContext();
LOG_ALWAYS_FATAL_IF(activeContext == nullptr, "Null active canvas context!");
bool done = activeContext->mergeTransaction(transaction, mSurfaceControl);
if (!done) {
auto funcs = renderthread::RenderThread::getInstance().getASurfaceControlFunctions();
funcs.transactionApplyFunc(transaction);
}
}
WebViewFunctorManager& WebViewFunctorManager::instance() {

View File

@@ -91,6 +91,7 @@ private:
RenderMode mMode;
bool mHasContext = false;
bool mCreatedHandle = false;
ASurfaceControl* mSurfaceControl = nullptr;
};
class WebViewFunctorManager {

View File

@@ -63,6 +63,10 @@ struct {
jmethodID closeHintSession;
} gHardwareRenderer;
struct {
jmethodID onMergeTransaction;
} gASurfaceTransactionCallback;
struct {
jmethodID onFrameDraw;
} gFrameDrawingCallback;
@@ -509,6 +513,27 @@ static void android_view_ThreadedRenderer_setPictureCapturedCallbackJNI(JNIEnv*
}
}
static void android_view_ThreadedRenderer_setASurfaceTransactionCallback(
JNIEnv* env, jobject clazz, jlong proxyPtr, jobject aSurfaceTransactionCallback) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
if (!aSurfaceTransactionCallback) {
proxy->setASurfaceTransactionCallback(nullptr);
} else {
JavaVM* vm = nullptr;
LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Unable to get Java VM");
auto globalCallbackRef = std::make_shared<JGlobalRefHolder>(
vm, env->NewGlobalRef(aSurfaceTransactionCallback));
proxy->setASurfaceTransactionCallback(
[globalCallbackRef](int64_t transObj, int64_t scObj, int64_t frameNr) {
JNIEnv* env = getenv(globalCallbackRef->vm());
env->CallVoidMethod(globalCallbackRef->object(),
gASurfaceTransactionCallback.onMergeTransaction,
static_cast<jlong>(transObj), static_cast<jlong>(scObj),
static_cast<jlong>(frameNr));
});
}
}
static void android_view_ThreadedRenderer_setFrameCallback(JNIEnv* env,
jobject clazz, jlong proxyPtr, jobject frameCallback) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
@@ -762,8 +787,7 @@ static const JNINativeMethod gMethods[] = {
{"nSetName", "(JLjava/lang/String;)V", (void*)android_view_ThreadedRenderer_setName},
{"nSetSurface", "(JLandroid/view/Surface;Z)V",
(void*)android_view_ThreadedRenderer_setSurface},
{"nSetSurfaceControl", "(JJ)V",
(void*)android_view_ThreadedRenderer_setSurfaceControl},
{"nSetSurfaceControl", "(JJ)V", (void*)android_view_ThreadedRenderer_setSurfaceControl},
{"nPause", "(J)Z", (void*)android_view_ThreadedRenderer_pause},
{"nSetStopped", "(JZ)V", (void*)android_view_ThreadedRenderer_setStopped},
{"nSetLightAlpha", "(JFF)V", (void*)android_view_ThreadedRenderer_setLightAlpha},
@@ -804,6 +828,9 @@ static const JNINativeMethod gMethods[] = {
{"nSetPictureCaptureCallback",
"(JLandroid/graphics/HardwareRenderer$PictureCapturedCallback;)V",
(void*)android_view_ThreadedRenderer_setPictureCapturedCallbackJNI},
{"nSetASurfaceTransactionCallback",
"(JLandroid/graphics/HardwareRenderer$ASurfaceTransactionCallback;)V",
(void*)android_view_ThreadedRenderer_setASurfaceTransactionCallback},
{"nSetFrameCallback", "(JLandroid/graphics/HardwareRenderer$FrameDrawingCallback;)V",
(void*)android_view_ThreadedRenderer_setFrameCallback},
{"nSetFrameCompleteCallback",
@@ -866,6 +893,11 @@ int register_android_view_ThreadedRenderer(JNIEnv* env) {
GetStaticMethodIDOrDie(env, hardwareRenderer, "closeHintSession",
"(Landroid/os/PerformanceHintManager$Session;)V");
jclass aSurfaceTransactionCallbackClass =
FindClassOrDie(env, "android/graphics/HardwareRenderer$ASurfaceTransactionCallback");
gASurfaceTransactionCallback.onMergeTransaction =
GetMethodIDOrDie(env, aSurfaceTransactionCallbackClass, "onMergeTransaction", "(JJJ)V");
jclass frameCallbackClass = FindClassOrDie(env,
"android/graphics/HardwareRenderer$FrameDrawingCallback");
gFrameDrawingCallback.onFrameDraw = GetMethodIDOrDie(env, frameCallbackClass,

View File

@@ -56,6 +56,22 @@ namespace android {
namespace uirenderer {
namespace renderthread {
namespace {
class ScopedActiveContext {
public:
ScopedActiveContext(CanvasContext* context) { sActiveContext = context; }
~ScopedActiveContext() { sActiveContext = nullptr; }
static CanvasContext* getActiveContext() { return sActiveContext; }
private:
static CanvasContext* sActiveContext;
};
CanvasContext* ScopedActiveContext::sActiveContext = nullptr;
} /* namespace */
CanvasContext* CanvasContext::create(RenderThread& thread, bool translucent,
RenderNode* rootRenderNode, IContextFactory* contextFactory) {
auto renderType = Properties::getRenderPipelineType();
@@ -473,6 +489,7 @@ void CanvasContext::draw() {
return;
}
ScopedActiveContext activeContext(this);
mCurrentFrameInfo->set(FrameInfoIndex::FrameInterval) =
mRenderThread.timeLord().frameIntervalNanos();
@@ -880,6 +897,17 @@ SkRect CanvasContext::computeDirtyRect(const Frame& frame, SkRect* dirty) {
return windowDirty;
}
CanvasContext* CanvasContext::getActiveContext() {
return ScopedActiveContext::getActiveContext();
}
bool CanvasContext::mergeTransaction(ASurfaceTransaction* transaction, ASurfaceControl* control) {
if (!mASurfaceTransactionCallback) return false;
std::invoke(mASurfaceTransactionCallback, reinterpret_cast<int64_t>(transaction),
reinterpret_cast<int64_t>(control), getFrameNumber());
return true;
}
} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */

View File

@@ -109,6 +109,8 @@ public:
*/
GrDirectContext* getGrContext() const { return mRenderThread.getGrContext(); }
ASurfaceControl* getSurfaceControl() const { return mSurfaceControl; }
// Won't take effect until next EGLSurface creation
void setSwapBehavior(SwapBehavior swapBehavior);
@@ -201,6 +203,15 @@ public:
static void onSurfaceStatsAvailable(void* context, ASurfaceControl* control,
ASurfaceControlStats* stats);
void setASurfaceTransactionCallback(
const std::function<void(int64_t, int64_t, int64_t)>& callback) {
mASurfaceTransactionCallback = callback;
}
bool mergeTransaction(ASurfaceTransaction* transaction, ASurfaceControl* control);
static CanvasContext* getActiveContext();
private:
CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline);
@@ -296,6 +307,8 @@ private:
// If set to true, we expect that callbacks into onSurfaceStatsAvailable
bool mExpectSurfaceStats = false;
std::function<void(int64_t, int64_t, int64_t)> mASurfaceTransactionCallback;
};
} /* namespace renderthread */

View File

@@ -295,6 +295,12 @@ void RenderProxy::setPictureCapturedCallback(
[this, cb = callback]() { mContext->setPictureCapturedCallback(cb); });
}
void RenderProxy::setASurfaceTransactionCallback(
const std::function<void(int64_t, int64_t, int64_t)>& callback) {
mRenderThread.queue().post(
[this, cb = callback]() { mContext->setASurfaceTransactionCallback(cb); });
}
void RenderProxy::setFrameCallback(std::function<void(int64_t)>&& callback) {
mDrawFrameTask.setFrameCallback(std::move(callback));
}

View File

@@ -120,6 +120,8 @@ public:
void drawRenderNode(RenderNode* node);
void setContentDrawBounds(int left, int top, int right, int bottom);
void setPictureCapturedCallback(const std::function<void(sk_sp<SkPicture>&&)>& callback);
void setASurfaceTransactionCallback(
const std::function<void(int64_t, int64_t, int64_t)>& callback);
void setFrameCallback(std::function<void(int64_t)>&& callback);
void setFrameCompleteCallback(std::function<void(int64_t)>&& callback);

View File

@@ -54,6 +54,10 @@ static JVMAttachHook gOnStartHook = nullptr;
ASurfaceControlFunctions::ASurfaceControlFunctions() {
void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE);
createFunc = (ASC_create)dlsym(handle_, "ASurfaceControl_create");
LOG_ALWAYS_FATAL_IF(createFunc == nullptr,
"Failed to find required symbol ASurfaceControl_create!");
acquireFunc = (ASC_acquire) dlsym(handle_, "ASurfaceControl_acquire");
LOG_ALWAYS_FATAL_IF(acquireFunc == nullptr,
"Failed to find required symbol ASurfaceControl_acquire!");
@@ -81,6 +85,23 @@ ASurfaceControlFunctions::ASurfaceControlFunctions() {
"ASurfaceControlStats_getFrameNumber");
LOG_ALWAYS_FATAL_IF(getFrameNumberFunc == nullptr,
"Failed to find required symbol ASurfaceControlStats_getFrameNumber!");
transactionCreateFunc = (AST_create)dlsym(handle_, "ASurfaceTransaction_create");
LOG_ALWAYS_FATAL_IF(transactionCreateFunc == nullptr,
"Failed to find required symbol ASurfaceTransaction_create!");
transactionDeleteFunc = (AST_delete)dlsym(handle_, "ASurfaceTransaction_delete");
LOG_ALWAYS_FATAL_IF(transactionDeleteFunc == nullptr,
"Failed to find required symbol ASurfaceTransaction_delete!");
transactionApplyFunc = (AST_apply)dlsym(handle_, "ASurfaceTransaction_apply");
LOG_ALWAYS_FATAL_IF(transactionApplyFunc == nullptr,
"Failed to find required symbol ASurfaceTransaction_apply!");
transactionSetVisibilityFunc =
(AST_setVisibility)dlsym(handle_, "ASurfaceTransaction_setVisibility");
LOG_ALWAYS_FATAL_IF(transactionSetVisibilityFunc == nullptr,
"Failed to find required symbol ASurfaceTransaction_setVisibility!");
}
void RenderThread::frameCallback(int64_t frameTimeNanos, void* data) {

View File

@@ -79,25 +79,39 @@ struct VsyncSource {
virtual ~VsyncSource() {}
};
typedef ASurfaceControl* (*ASC_create)(ASurfaceControl* parent, const char* debug_name);
typedef void (*ASC_acquire)(ASurfaceControl* control);
typedef void (*ASC_release)(ASurfaceControl* control);
typedef void (*ASC_registerSurfaceStatsListener)(ASurfaceControl* control, void* context,
ASurfaceControl_SurfaceStatsListener func);
typedef void (*ASC_unregisterSurfaceStatsListener)(void* context,
ASurfaceControl_SurfaceStatsListener func);
ASurfaceControl_SurfaceStatsListener func);
typedef int64_t (*ASCStats_getAcquireTime)(ASurfaceControlStats* stats);
typedef uint64_t (*ASCStats_getFrameNumber)(ASurfaceControlStats* stats);
typedef ASurfaceTransaction* (*AST_create)();
typedef void (*AST_delete)(ASurfaceTransaction* transaction);
typedef void (*AST_apply)(ASurfaceTransaction* transaction);
typedef void (*AST_setVisibility)(ASurfaceTransaction* transaction,
ASurfaceControl* surface_control, int8_t visibility);
struct ASurfaceControlFunctions {
ASurfaceControlFunctions();
ASC_create createFunc;
ASC_acquire acquireFunc;
ASC_release releaseFunc;
ASC_registerSurfaceStatsListener registerListenerFunc;
ASC_unregisterSurfaceStatsListener unregisterListenerFunc;
ASCStats_getAcquireTime getAcquireTimeFunc;
ASCStats_getFrameNumber getFrameNumberFunc;
AST_create transactionCreateFunc;
AST_delete transactionDeleteFunc;
AST_apply transactionApplyFunc;
AST_setVisibility transactionSetVisibilityFunc;
};
class ChoreographerSource;