fune/widget/android/AndroidCompositorWidget.cpp
Jamie Nicol 6511f3c4e5 Bug 1797055 - Force crash early if compositor is resumed with abandoned Surface. r=geckoview-reviewers,m_kato
In bug 1772839 we were seeing a large number of crashes due to
encountering a webrender error after exhausting all fallback
configurations. At least in some cases, this was due to the compositor
being resumed with an Android Surface that was already in an abandoned
state, meaning we can never succeed in creating an EGL Surface.

We added a check for this condition, and a workaround, to the
GeckoView java code. However, we are still seeing crash reports
matching this signature. To help determine whether these are also due
to the Surface being abandoned, or due to some other reason, this
patch adds a deliberate crash much earlier in the pipeline if we
detect an abandoned Surface.

Differential Revision: https://phabricator.services.mozilla.com/D160042
2022-10-27 08:01:28 +00:00

113 lines
3.5 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=2 et tw=80 : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "AndroidCompositorWidget.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/widget/PlatformWidgetTypes.h"
#include "nsWindow.h"
#include "SurfaceViewWrapperSupport.h"
namespace mozilla {
namespace widget {
AndroidCompositorWidget::AndroidCompositorWidget(
const AndroidCompositorWidgetInitData& aInitData,
const layers::CompositorOptions& aOptions)
: CompositorWidget(aOptions),
mWidgetId(aInitData.widgetId()),
mNativeWindow(nullptr),
mFormat(WINDOW_FORMAT_RGBA_8888),
mClientSize(aInitData.clientSize()) {}
AndroidCompositorWidget::~AndroidCompositorWidget() {
if (mNativeWindow) {
ANativeWindow_release(mNativeWindow);
}
}
already_AddRefed<gfx::DrawTarget>
AndroidCompositorWidget::StartRemoteDrawingInRegion(
const LayoutDeviceIntRegion& aInvalidRegion,
layers::BufferMode* aBufferMode) {
if (!mNativeWindow) {
EGLNativeWindowType window = GetEGLNativeWindow();
JNIEnv* const env = jni::GetEnvForThread();
mNativeWindow =
ANativeWindow_fromSurface(env, reinterpret_cast<jobject>(window));
if (mNativeWindow) {
mFormat = ANativeWindow_getFormat(mNativeWindow);
ANativeWindow_acquire(mNativeWindow);
} else {
return nullptr;
}
}
if (mFormat != WINDOW_FORMAT_RGBA_8888 &&
mFormat != WINDOW_FORMAT_RGBX_8888) {
gfxCriticalNoteOnce << "Non supported format: " << mFormat;
return nullptr;
}
// XXX Handle inOutDirtyBounds
if (ANativeWindow_lock(mNativeWindow, &mBuffer, nullptr) != 0) {
return nullptr;
}
const int bpp = 4;
gfx::SurfaceFormat format = gfx::SurfaceFormat::R8G8B8A8;
if (mFormat == WINDOW_FORMAT_RGBX_8888) {
format = gfx::SurfaceFormat::R8G8B8X8;
}
RefPtr<gfx::DrawTarget> dt = gfx::Factory::CreateDrawTargetForData(
gfx::BackendType::SKIA, static_cast<unsigned char*>(mBuffer.bits),
gfx::IntSize(mBuffer.width, mBuffer.height), mBuffer.stride * bpp, format,
true);
return dt.forget();
}
void AndroidCompositorWidget::EndRemoteDrawingInRegion(
gfx::DrawTarget* aDrawTarget, const LayoutDeviceIntRegion& aInvalidRegion) {
ANativeWindow_unlockAndPost(mNativeWindow);
}
bool AndroidCompositorWidget::OnResumeComposition() {
OnCompositorSurfaceChanged();
if (!mSurface) {
gfxCriticalError() << "OnResumeComposition called with null Surface";
return false;
}
// If our Surface is in an abandoned state then we will never succesfully
// create an EGL Surface, and will eventually crash. Better to explicitly
// crash now.
if (SurfaceViewWrapperSupport::IsSurfaceAbandoned(mSurface)) {
MOZ_CRASH("Compositor resumed with abandoned Surface");
}
return true;
}
EGLNativeWindowType AndroidCompositorWidget::GetEGLNativeWindow() {
return (EGLNativeWindowType)mSurface.Get();
}
LayoutDeviceIntSize AndroidCompositorWidget::GetClientSize() {
return mClientSize;
}
void AndroidCompositorWidget::NotifyClientSizeChanged(
const LayoutDeviceIntSize& aClientSize) {
mClientSize =
LayoutDeviceIntSize(std::min(aClientSize.width, MOZ_WIDGET_MAX_SIZE),
std::min(aClientSize.height, MOZ_WIDGET_MAX_SIZE));
}
} // namespace widget
} // namespace mozilla