9107a62bb4
When WebViewFunctor is destroyed, overlays needs to be removed. Bug: 194393522 Test: toggle fullscreen during video playing, and run "adb shell dumpsys SurfaceFlinger | grep Webview", it should only show onlyi one surface control Change-Id: I40d0e503c4f5b25c59886820485e7734716ac859 (cherry picked from commit 9c5158f7a2f3bff0ccfc8e071143aac7b5c95049)
351 lines
12 KiB
C++
351 lines
12 KiB
C++
/*
|
|
* Copyright (C) 2018 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "WebViewFunctorManager.h"
|
|
|
|
#include <private/hwui/WebViewFunctor.h>
|
|
#include "Properties.h"
|
|
#include "renderthread/CanvasContext.h"
|
|
#include "renderthread/RenderThread.h"
|
|
|
|
#include <log/log.h>
|
|
#include <utils/Trace.h>
|
|
#include <atomic>
|
|
|
|
namespace android::uirenderer {
|
|
|
|
namespace {
|
|
class ScopedCurrentFunctor {
|
|
public:
|
|
ScopedCurrentFunctor(WebViewFunctor* functor) {
|
|
ALOG_ASSERT(!sCurrentFunctor);
|
|
ALOG_ASSERT(functor);
|
|
sCurrentFunctor = functor;
|
|
}
|
|
~ScopedCurrentFunctor() {
|
|
ALOG_ASSERT(sCurrentFunctor);
|
|
sCurrentFunctor = nullptr;
|
|
}
|
|
|
|
static ASurfaceControl* getSurfaceControl() {
|
|
ALOG_ASSERT(sCurrentFunctor);
|
|
return sCurrentFunctor->getSurfaceControl();
|
|
}
|
|
static void mergeTransaction(ASurfaceTransaction* transaction) {
|
|
ALOG_ASSERT(sCurrentFunctor);
|
|
sCurrentFunctor->mergeTransaction(transaction);
|
|
}
|
|
|
|
private:
|
|
static WebViewFunctor* sCurrentFunctor;
|
|
};
|
|
|
|
WebViewFunctor* ScopedCurrentFunctor::sCurrentFunctor = nullptr;
|
|
} // namespace
|
|
|
|
RenderMode WebViewFunctor_queryPlatformRenderMode() {
|
|
auto pipelineType = Properties::getRenderPipelineType();
|
|
switch (pipelineType) {
|
|
case RenderPipelineType::SkiaGL:
|
|
return RenderMode::OpenGL_ES;
|
|
case RenderPipelineType::SkiaVulkan:
|
|
return RenderMode::Vulkan;
|
|
default:
|
|
LOG_ALWAYS_FATAL("Unknown render pipeline type: %d", (int)pipelineType);
|
|
}
|
|
}
|
|
|
|
int WebViewFunctor_create(void* data, const WebViewFunctorCallbacks& prototype,
|
|
RenderMode functorMode) {
|
|
if (functorMode != RenderMode::OpenGL_ES && functorMode != RenderMode::Vulkan) {
|
|
ALOGW("Unknown rendermode %d", (int)functorMode);
|
|
return -1;
|
|
}
|
|
if (functorMode == RenderMode::Vulkan &&
|
|
WebViewFunctor_queryPlatformRenderMode() != RenderMode::Vulkan) {
|
|
ALOGW("Unable to map from GLES platform to a vulkan functor");
|
|
return -1;
|
|
}
|
|
return WebViewFunctorManager::instance().createFunctor(data, prototype, functorMode);
|
|
}
|
|
|
|
void WebViewFunctor_release(int functor) {
|
|
WebViewFunctorManager::instance().releaseFunctor(functor);
|
|
}
|
|
|
|
static std::atomic_int sNextId{1};
|
|
|
|
WebViewFunctor::WebViewFunctor(void* data, const WebViewFunctorCallbacks& callbacks,
|
|
RenderMode functorMode)
|
|
: mData(data) {
|
|
mFunctor = sNextId++;
|
|
mCallbacks = callbacks;
|
|
mMode = functorMode;
|
|
}
|
|
|
|
WebViewFunctor::~WebViewFunctor() {
|
|
destroyContext();
|
|
|
|
ATRACE_NAME("WebViewFunctor::onDestroy");
|
|
if (mSurfaceControl) {
|
|
removeOverlays();
|
|
}
|
|
mCallbacks.onDestroyed(mFunctor, mData);
|
|
}
|
|
|
|
void WebViewFunctor::sync(const WebViewSyncData& syncData) const {
|
|
ATRACE_NAME("WebViewFunctor::sync");
|
|
mCallbacks.onSync(mFunctor, mData, syncData);
|
|
}
|
|
|
|
void WebViewFunctor::onRemovedFromTree() {
|
|
ATRACE_NAME("WebViewFunctor::onRemovedFromTree");
|
|
if (mSurfaceControl) {
|
|
removeOverlays();
|
|
}
|
|
}
|
|
|
|
void WebViewFunctor::drawGl(const DrawGlInfo& drawInfo) {
|
|
ATRACE_NAME("WebViewFunctor::drawGl");
|
|
if (!mHasContext) {
|
|
mHasContext = true;
|
|
}
|
|
ScopedCurrentFunctor currentFunctor(this);
|
|
|
|
WebViewOverlayData overlayParams = {
|
|
.overlaysMode = OverlaysMode::Disabled,
|
|
.getSurfaceControl = currentFunctor.getSurfaceControl,
|
|
.mergeTransaction = currentFunctor.mergeTransaction,
|
|
};
|
|
|
|
if (Properties::enableWebViewOverlays && !drawInfo.isLayer) {
|
|
renderthread::CanvasContext* activeContext =
|
|
renderthread::CanvasContext::getActiveContext();
|
|
if (activeContext != nullptr) {
|
|
ASurfaceControl* rootSurfaceControl = activeContext->getSurfaceControl();
|
|
if (rootSurfaceControl) {
|
|
overlayParams.overlaysMode = OverlaysMode::Enabled;
|
|
int32_t rgid = activeContext->getSurfaceControlGenerationId();
|
|
if (mParentSurfaceControlGenerationId != rgid) {
|
|
reparentSurfaceControl(rootSurfaceControl);
|
|
mParentSurfaceControlGenerationId = rgid;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
mCallbacks.gles.draw(mFunctor, mData, drawInfo, overlayParams);
|
|
}
|
|
|
|
void WebViewFunctor::initVk(const VkFunctorInitParams& params) {
|
|
ATRACE_NAME("WebViewFunctor::initVk");
|
|
if (!mHasContext) {
|
|
mHasContext = true;
|
|
} else {
|
|
return;
|
|
}
|
|
mCallbacks.vk.initialize(mFunctor, mData, params);
|
|
}
|
|
|
|
void WebViewFunctor::drawVk(const VkFunctorDrawParams& params) {
|
|
ATRACE_NAME("WebViewFunctor::drawVk");
|
|
ScopedCurrentFunctor currentFunctor(this);
|
|
|
|
WebViewOverlayData overlayParams = {
|
|
.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);
|
|
}
|
|
|
|
void WebViewFunctor::postDrawVk() {
|
|
ATRACE_NAME("WebViewFunctor::postDrawVk");
|
|
mCallbacks.vk.postDraw(mFunctor, mData);
|
|
}
|
|
|
|
void WebViewFunctor::destroyContext() {
|
|
if (mHasContext) {
|
|
mHasContext = false;
|
|
ATRACE_NAME("WebViewFunctor::onContextDestroyed");
|
|
mCallbacks.onContextDestroyed(mFunctor, mData);
|
|
|
|
// grContext may be null in unit tests.
|
|
auto* grContext = renderthread::RenderThread::getInstance().getGrContext();
|
|
if (grContext) grContext->resetContext();
|
|
}
|
|
}
|
|
|
|
void WebViewFunctor::removeOverlays() {
|
|
ScopedCurrentFunctor currentFunctor(this);
|
|
mCallbacks.removeOverlays(mFunctor, mData, currentFunctor.mergeTransaction);
|
|
if (mSurfaceControl) {
|
|
reparentSurfaceControl(nullptr);
|
|
auto funcs = renderthread::RenderThread::getInstance().getASurfaceControlFunctions();
|
|
funcs.releaseFunc(mSurfaceControl);
|
|
mSurfaceControl = nullptr;
|
|
}
|
|
}
|
|
|
|
ASurfaceControl* WebViewFunctor::getSurfaceControl() {
|
|
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();
|
|
mParentSurfaceControlGenerationId = activeContext->getSurfaceControlGenerationId();
|
|
mSurfaceControl = funcs.createFunc(rootSurfaceControl, "Webview Overlay SurfaceControl");
|
|
ASurfaceTransaction* transaction = funcs.transactionCreateFunc();
|
|
activeContext->prepareSurfaceControlForWebview();
|
|
funcs.transactionSetZOrderFunc(transaction, mSurfaceControl, -1);
|
|
funcs.transactionSetVisibilityFunc(transaction, mSurfaceControl,
|
|
ASURFACE_TRANSACTION_VISIBILITY_SHOW);
|
|
funcs.transactionApplyFunc(transaction);
|
|
funcs.transactionDeleteFunc(transaction);
|
|
return mSurfaceControl;
|
|
}
|
|
|
|
void WebViewFunctor::mergeTransaction(ASurfaceTransaction* transaction) {
|
|
ATRACE_NAME("WebViewFunctor::mergeTransaction");
|
|
if (transaction == nullptr) return;
|
|
bool done = false;
|
|
renderthread::CanvasContext* activeContext = renderthread::CanvasContext::getActiveContext();
|
|
// activeContext might be null when called from mCallbacks.removeOverlays()
|
|
if (activeContext != nullptr) {
|
|
done = activeContext->mergeTransaction(transaction, mSurfaceControl);
|
|
}
|
|
if (!done) {
|
|
auto funcs = renderthread::RenderThread::getInstance().getASurfaceControlFunctions();
|
|
funcs.transactionApplyFunc(transaction);
|
|
}
|
|
}
|
|
|
|
void WebViewFunctor::reparentSurfaceControl(ASurfaceControl* parent) {
|
|
ATRACE_NAME("WebViewFunctor::reparentSurfaceControl");
|
|
if (mSurfaceControl == nullptr) return;
|
|
|
|
auto funcs = renderthread::RenderThread::getInstance().getASurfaceControlFunctions();
|
|
ASurfaceTransaction* transaction = funcs.transactionCreateFunc();
|
|
funcs.transactionReparentFunc(transaction, mSurfaceControl, parent);
|
|
mergeTransaction(transaction);
|
|
funcs.transactionDeleteFunc(transaction);
|
|
}
|
|
|
|
WebViewFunctorManager& WebViewFunctorManager::instance() {
|
|
static WebViewFunctorManager sInstance;
|
|
return sInstance;
|
|
}
|
|
|
|
static void validateCallbacks(const WebViewFunctorCallbacks& callbacks) {
|
|
// TODO: Should we do a stack peek to see if this is really webview?
|
|
LOG_ALWAYS_FATAL_IF(callbacks.onSync == nullptr, "onSync is null");
|
|
LOG_ALWAYS_FATAL_IF(callbacks.onContextDestroyed == nullptr, "onContextDestroyed is null");
|
|
LOG_ALWAYS_FATAL_IF(callbacks.onDestroyed == nullptr, "onDestroyed is null");
|
|
LOG_ALWAYS_FATAL_IF(callbacks.removeOverlays == nullptr, "removeOverlays is null");
|
|
switch (auto mode = WebViewFunctor_queryPlatformRenderMode()) {
|
|
case RenderMode::OpenGL_ES:
|
|
LOG_ALWAYS_FATAL_IF(callbacks.gles.draw == nullptr, "gles.draw is null");
|
|
break;
|
|
case RenderMode::Vulkan:
|
|
LOG_ALWAYS_FATAL_IF(callbacks.vk.initialize == nullptr, "vk.initialize is null");
|
|
LOG_ALWAYS_FATAL_IF(callbacks.vk.draw == nullptr, "vk.draw is null");
|
|
LOG_ALWAYS_FATAL_IF(callbacks.vk.postDraw == nullptr, "vk.postDraw is null");
|
|
break;
|
|
default:
|
|
LOG_ALWAYS_FATAL("unknown platform mode? %d", (int)mode);
|
|
break;
|
|
}
|
|
}
|
|
|
|
int WebViewFunctorManager::createFunctor(void* data, const WebViewFunctorCallbacks& callbacks,
|
|
RenderMode functorMode) {
|
|
validateCallbacks(callbacks);
|
|
auto object = std::make_unique<WebViewFunctor>(data, callbacks, functorMode);
|
|
int id = object->id();
|
|
auto handle = object->createHandle();
|
|
{
|
|
std::lock_guard _lock{mLock};
|
|
mActiveFunctors.push_back(std::move(handle));
|
|
mFunctors.push_back(std::move(object));
|
|
}
|
|
return id;
|
|
}
|
|
|
|
void WebViewFunctorManager::releaseFunctor(int functor) {
|
|
sp<WebViewFunctor::Handle> toRelease;
|
|
{
|
|
std::lock_guard _lock{mLock};
|
|
for (auto iter = mActiveFunctors.begin(); iter != mActiveFunctors.end(); iter++) {
|
|
if ((*iter)->id() == functor) {
|
|
toRelease = std::move(*iter);
|
|
mActiveFunctors.erase(iter);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void WebViewFunctorManager::onContextDestroyed() {
|
|
// WARNING: SKETCHY
|
|
// Because we know that we always remove from mFunctors on RenderThread, the same
|
|
// thread that always invokes onContextDestroyed, we know that the functor pointers
|
|
// will remain valid without the lock held.
|
|
// However, we won't block new functors from being added in the meantime.
|
|
mLock.lock();
|
|
const size_t size = mFunctors.size();
|
|
WebViewFunctor* toDestroyContext[size];
|
|
for (size_t i = 0; i < size; i++) {
|
|
toDestroyContext[i] = mFunctors[i].get();
|
|
}
|
|
mLock.unlock();
|
|
for (size_t i = 0; i < size; i++) {
|
|
toDestroyContext[i]->destroyContext();
|
|
}
|
|
}
|
|
|
|
void WebViewFunctorManager::destroyFunctor(int functor) {
|
|
std::unique_ptr<WebViewFunctor> toRelease;
|
|
{
|
|
std::lock_guard _lock{mLock};
|
|
for (auto iter = mFunctors.begin(); iter != mFunctors.end(); iter++) {
|
|
if ((*iter)->id() == functor) {
|
|
toRelease = std::move(*iter);
|
|
mFunctors.erase(iter);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
sp<WebViewFunctor::Handle> WebViewFunctorManager::handleFor(int functor) {
|
|
std::lock_guard _lock{mLock};
|
|
for (auto& iter : mActiveFunctors) {
|
|
if (iter->id() == functor) {
|
|
return iter;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
} // namespace android::uirenderer
|