Fix crash in OpenGLDriver::destroyStream (#9801)

Fixes a SIGSEGV crash that occurs during
`ExternalStreamManagerAndroid::release()` when users provide a custom
Platform instance during Engine creation.

When a custom Platform is used, ExternalStreamManagerAndroid is
instantiated on the application's thread. Its constructor was caching a
C++ reference (`VirtualMachineEnv& mVm`) to the `thread_local`
VirtualMachineEnv instance belonging to the application thread.

Later, when the Filament backend thread executed `release()`, it
accessed this cached reference. This caused the backend thread to
retrieve the `JNIEnv*` from the application thread's `thread_local`
instance, and subsequently call `env->DeleteGlobalRef()`.  A thread must
use its own `JNIEnv` pointer, so using the application thread's pointer
from the backend thread resulted in a crash.

BUGS=[489814416]
This commit is contained in:
Sungun Park
2026-03-19 02:26:58 +00:00
committed by GitHub
parent 45d92cac14
commit f24db4633e
3 changed files with 25 additions and 10 deletions
@@ -185,7 +185,7 @@ private:
};
int mOSVersion;
ExternalStreamManagerAndroid& mExternalStreamManager;
ExternalStreamManagerAndroid* mExternalStreamManager = nullptr;
AndroidDetails& mAndroidDetails;
utils::PerformanceHintManager mPerformanceHintManager;
utils::PerformanceHintManager::Session mPerformanceHintSession;
@@ -80,6 +80,9 @@ JNIEnv* ExternalStreamManagerAndroid::getEnvironmentSlow() noexcept {
Stream* ExternalStreamManagerAndroid::acquire(jobject surfaceTexture) noexcept {
// note: This is called on the application thread (not the GL thread)
// The application thread *MUST* be attached to the JVM to pass the java 'surfaceTexture' down
// to filament natively, so we are guaranteed to get a valid JNIEnv from getThreadEnvironment()
// without needing AttachCurrentThread.
JNIEnv* env = VirtualMachineEnv::getThreadEnvironment();
if (!env) {
return nullptr; // this should not happen
@@ -120,8 +120,7 @@ struct PlatformEGLAndroid::AndroidDetails {
// ---------------------------------------------------------------------------------------------
PlatformEGLAndroid::PlatformEGLAndroid() noexcept
: mExternalStreamManager(ExternalStreamManagerAndroid::create()),
mAndroidDetails(*(new(std::nothrow) AndroidDetails{})) {
: mAndroidDetails(*(new(std::nothrow) AndroidDetails{})) {
mOSVersion = android_get_device_api_level();
if (mOSVersion < 0) {
mOSVersion = __ANDROID_API_FUTURE__;
@@ -135,7 +134,10 @@ PlatformEGLAndroid::~PlatformEGLAndroid() noexcept {
void PlatformEGLAndroid::terminate() noexcept {
mPerformanceHintManager.terminate();
mAndroidDetails.androidFrameCallback.terminate();
ExternalStreamManagerAndroid::destroy(&mExternalStreamManager);
if (mExternalStreamManager) {
ExternalStreamManagerAndroid::destroy(mExternalStreamManager);
mExternalStreamManager = nullptr;
}
PlatformEGL::terminate();
}
@@ -225,6 +227,10 @@ Driver* PlatformEGLAndroid::createDriver(void* sharedContext,
mPerformanceHintSession = PerformanceHintManager::Session{
mPerformanceHintManager, &tid, 1, 16'666'667 };
mExternalStreamManager = &ExternalStreamManagerAndroid::create();
FILAMENT_CHECK_POSTCONDITION(mExternalStreamManager)
<< "Failed to create ExternalStreamManagerAndroid";
Driver* driver = PlatformEGL::createDriver(sharedContext, driverConfig);
auto const extensions = GLUtils::split(eglQueryString(getEglDisplay(), EGL_EXTENSIONS));
@@ -611,11 +617,13 @@ void PlatformEGLAndroid::setPresentationTime(int64_t const presentationTimeInNan
}
Platform::Stream* PlatformEGLAndroid::createStream(void* nativeStream) noexcept {
return mExternalStreamManager.acquire(static_cast<jobject>(nativeStream));
assert_invariant(mExternalStreamManager);
return mExternalStreamManager->acquire(static_cast<jobject>(nativeStream));
}
void PlatformEGLAndroid::destroyStream(Stream* stream) noexcept {
mExternalStreamManager.release(stream);
assert_invariant(mExternalStreamManager);
mExternalStreamManager->release(stream);
}
Platform::Sync* PlatformEGLAndroid::createSync() noexcept {
@@ -667,19 +675,23 @@ void PlatformEGLAndroid::destroySync(Sync* sync) noexcept {
}
void PlatformEGLAndroid::attach(Stream* stream, intptr_t const tname) noexcept {
mExternalStreamManager.attach(stream, tname);
assert_invariant(mExternalStreamManager);
mExternalStreamManager->attach(stream, tname);
}
void PlatformEGLAndroid::detach(Stream* stream) noexcept {
mExternalStreamManager.detach(stream);
assert_invariant(mExternalStreamManager);
mExternalStreamManager->detach(stream);
}
void PlatformEGLAndroid::updateTexImage(Stream* stream, int64_t* timestamp) noexcept {
mExternalStreamManager.updateTexImage(stream, timestamp);
assert_invariant(mExternalStreamManager);
mExternalStreamManager->updateTexImage(stream, timestamp);
}
math::mat3f PlatformEGLAndroid::getTransformMatrix(Stream* stream) noexcept {
return mExternalStreamManager.getTransformMatrix(stream);
assert_invariant(mExternalStreamManager);
return mExternalStreamManager->getTransformMatrix(stream);
}
int PlatformEGLAndroid::getOSVersion() const noexcept {