diff --git a/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserApplication.java b/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserApplication.java index 1d207d1c0..32529ccbd 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserApplication.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserApplication.java @@ -8,6 +8,7 @@ import android.app.Application; import android.content.Context; import android.content.res.Configuration; +import android.os.Looper; import androidx.annotation.NonNull; @@ -53,12 +54,19 @@ public void onCreate() { return; } + // Fix potential Gecko static initialization order. + // GeckoResult.ALLOW and GeckoResult.DENY static initializer might get a null mDispatcher + // depending on how JVM classloader does the initialization job. + // See https://github.com/MozillaReality/FirefoxReality/issues/3651 + Looper.getMainLooper().getThread(); + SessionStore.prefOverrides(this); TelemetryWrapper.init(this, EngineProvider.INSTANCE.getDefaultClient(this)); GleanMetricsService.init(this, EngineProvider.INSTANCE.getDefaultClient(this)); } protected void onActivityCreate(@NonNull Context activityContext) { + EngineProvider.INSTANCE.getDefaultGeckoWebExecutor(activityContext); mPlaces = new Places(this); mServices = new Services(this, mPlaces); mAccounts = new Accounts(this); diff --git a/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/EngineProvider.kt b/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/EngineProvider.kt index 33a7f5752..56a278f9f 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/EngineProvider.kt +++ b/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/EngineProvider.kt @@ -63,20 +63,24 @@ object EngineProvider { return runtime != null } - fun createGeckoWebExecutor(context: Context): GeckoWebExecutor { + private fun createGeckoWebExecutor(context: Context): GeckoWebExecutor { return GeckoWebExecutor(getOrCreateRuntime(context)) } - fun getDefaultGeckoWebExecutor(context: Context): GeckoWebExecutor { + fun getDefaultGeckoWebExecutor(context: Context): GeckoWebExecutor { if (executor == null) { executor = createGeckoWebExecutor(context) + client?.let { it.executor = executor } + } return executor!! } fun createClient(context: Context): GeckoViewFetchClient { - return GeckoViewFetchClient(context) + val client = GeckoViewFetchClient(context) + client.executor = executor + return client } fun getDefaultClient(context: Context): GeckoViewFetchClient { diff --git a/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/GeckoViewFetchClient.kt b/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/GeckoViewFetchClient.kt index f69409ffc..8ad095e66 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/GeckoViewFetchClient.kt +++ b/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/GeckoViewFetchClient.kt @@ -28,10 +28,13 @@ class GeckoViewFetchClient( ) : Client() { @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) - internal var executor: GeckoWebExecutor = EngineProvider.createGeckoWebExecutor(context) + internal var executor: GeckoWebExecutor? = null @Throws(IOException::class) override fun fetch(request: Request): Response { + if (executor == null) { + throw IOException("GeckoWebExecutor not initialized") + } val webRequest = request.toWebRequest(defaultHeaders) val readTimeOut = request.readTimeout ?: maxReadTimeOut @@ -47,7 +50,7 @@ class GeckoViewFetchClient( if (request.redirect == Request.Redirect.MANUAL) { fetchFlags += GeckoWebExecutor.FETCH_FLAGS_NO_REDIRECTS } - val webResponse = executor.fetch(webRequest, fetchFlags).poll(readTimeOutMillis) + val webResponse = executor!!.fetch(webRequest, fetchFlags).poll(readTimeOutMillis) webResponse?.toResponse() ?: throw IOException("Fetch failed with null response") } catch (e: TimeoutException) { throw SocketTimeoutException()