fune/widget/android/SurfaceViewWrapperSupport.h
Jamie Nicol d40ea70ccc Bug 1772839 - Work around compositor being resumed with abandoned Surfaces. r=geckoview-reviewers,owlish
On some Android devices (predominantly Huawei devices running Android
9 or below) we are seeing large numbers of crashes due to the
compositor being unable to create an EGL surface to render in to. From
local testing, this appears to be due to the Surface we are being
provided from the SurfaceView being in an "abandoned"
state. Presumably this is due to an operating system bug - the Surface
is valid at the time of the surfaceChanged() callback, but becomes
abandoned moments later despite surfaceDestroyed() not being called.

We are able to detect when the Surface is in such a state from C++
code by calling ANativeWindow_getWidth(), as that will return a
negative value to indicate an error.

This patch uses this method to check whether the Surface is in such a
state prior to resuming the compositor. If so, rather than immediately
resuming the compositor it instead toggles the SurfaceView's
visibility. This tricks the SurfaceView in to providing a new (and
hopefully valid) Surface, which will in turn resume the compositor via
the surfaceChanged callback.

Differential Revision: https://phabricator.services.mozilla.com/D151479
2022-07-13 15:38:51 +00:00

39 lines
1.2 KiB
C++

/* -*- Mode: c++; c-basic-offset: 2; tab-width: 20; indent-tabs-mode: nil; -*-
* 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/. */
#ifndef SurfaceViewWrapperSupport_h__
#define SurfaceViewWrapperSupport_h__
#include "mozilla/java/SurfaceViewWrapperNatives.h"
#include <android/native_window.h>
#include <android/native_window_jni.h>
namespace mozilla {
namespace widget {
class SurfaceViewWrapperSupport final
: public java::SurfaceViewWrapper::Natives<SurfaceViewWrapperSupport> {
public:
static bool IsSurfaceAbandoned(jni::Object::Param aSurface) {
ANativeWindow* win =
ANativeWindow_fromSurface(jni::GetEnvForThread(), aSurface.Get());
if (!win) {
return true;
}
// If the Surface's underlying BufferQueue has been abandoned, then
// ANativeWindow_getWidth (or height) will return a negative value
// to indicate an error.
int32_t width = ANativeWindow_getWidth(win);
ANativeWindow_release(win);
return width < 0;
}
};
} // namespace widget
} // namespace mozilla
#endif // SurfaceViewWrapperSupport_h__