diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/CxxInspectorPackagerConnection.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/CxxInspectorPackagerConnection.kt index 5e3be8b14413..c6b6b7839353 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/CxxInspectorPackagerConnection.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/CxxInspectorPackagerConnection.kt @@ -14,14 +14,13 @@ import com.facebook.jni.HybridData import com.facebook.proguard.annotations.DoNotStrip import com.facebook.proguard.annotations.DoNotStripAny import com.facebook.react.common.annotations.VisibleForTesting +import com.facebook.react.devsupport.inspector.DevSupportHttpClient import com.facebook.soloader.SoLoader import java.io.Closeable import java.nio.ByteBuffer import java.nio.charset.StandardCharsets import java.util.ArrayDeque import java.util.Queue -import java.util.concurrent.TimeUnit -import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response import okhttp3.WebSocket @@ -173,12 +172,7 @@ internal class CxxInspectorPackagerConnection( /** Java implementation of the C++ InspectorPackagerConnectionDelegate interface. */ private class DelegateImpl { - private val httpClient = - OkHttpClient.Builder() - .connectTimeout(10, TimeUnit.SECONDS) - .writeTimeout(10, TimeUnit.SECONDS) - .readTimeout(0, TimeUnit.MINUTES) // Disable timeouts for read - .build() + private val httpClient = DevSupportHttpClient.websocketClient private val handler = Handler(Looper.getMainLooper()) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.kt index cfbceaac4dae..6fdcb1c85d28 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.kt @@ -21,6 +21,7 @@ import com.facebook.react.bridge.ReactContext import com.facebook.react.common.ReactConstants import com.facebook.react.devsupport.InspectorFlags.getFuseboxEnabled import com.facebook.react.devsupport.InspectorFlags.getIsProfilingBuild +import com.facebook.react.devsupport.inspector.DevSupportHttpClient import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener import com.facebook.react.devsupport.interfaces.PackagerStatusCallback import com.facebook.react.modules.debug.interfaces.DeveloperSettings @@ -39,7 +40,6 @@ import java.io.UnsupportedEncodingException import java.security.MessageDigest import java.security.NoSuchAlgorithmException import java.util.Locale -import java.util.concurrent.TimeUnit import okhttp3.Call import okhttp3.Callback import okhttp3.OkHttpClient @@ -86,12 +86,7 @@ public open class DevServerHelper( MAP("map"), } - private val client: OkHttpClient = - OkHttpClient.Builder() - .connectTimeout(HTTP_CONNECT_TIMEOUT_MS.toLong(), TimeUnit.MILLISECONDS) - .readTimeout(0, TimeUnit.MILLISECONDS) - .writeTimeout(0, TimeUnit.MILLISECONDS) - .build() + private val client: OkHttpClient = DevSupportHttpClient.httpClient private val bundleDownloader: BundleDownloader = BundleDownloader(client) private val packagerStatusCheck: PackagerStatusCheck = PackagerStatusCheck(client) private val packageName: String = applicationContext.packageName @@ -397,7 +392,6 @@ public open class DevServerHelper( } private companion object { - private const val HTTP_CONNECT_TIMEOUT_MS = 5000 private const val DEBUGGER_MSG_DISABLE = "{ \"id\":1,\"method\":\"Debugger.disable\" }" private fun getSHA256(string: String): String { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/PackagerStatusCheck.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/PackagerStatusCheck.kt index bbb86aa95e6a..02a2a6155d10 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/PackagerStatusCheck.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/PackagerStatusCheck.kt @@ -11,10 +11,10 @@ package com.facebook.react.devsupport import com.facebook.common.logging.FLog import com.facebook.react.common.ReactConstants +import com.facebook.react.devsupport.inspector.DevSupportHttpClient import com.facebook.react.devsupport.interfaces.PackagerStatusCallback import java.io.IOException import java.util.Locale -import java.util.concurrent.TimeUnit import okhttp3.Call import okhttp3.Callback import okhttp3.OkHttpClient @@ -22,22 +22,9 @@ import okhttp3.Request import okhttp3.Response /** Use this class to check if the JavaScript packager is running on the provided host. */ -internal class PackagerStatusCheck { +internal class PackagerStatusCheck(private val client: OkHttpClient) { - private val client: OkHttpClient - - constructor() { - client = - OkHttpClient.Builder() - .connectTimeout(HTTP_CONNECT_TIMEOUT_MS.toLong(), TimeUnit.MILLISECONDS) - .readTimeout(0, TimeUnit.MILLISECONDS) - .writeTimeout(0, TimeUnit.MILLISECONDS) - .build() - } - - constructor(client: OkHttpClient) { - this.client = client - } + constructor() : this(DevSupportHttpClient.httpClient) fun run(host: String, callback: PackagerStatusCallback) { val statusURL = createPackagerStatusURL(host) @@ -92,7 +79,6 @@ internal class PackagerStatusCheck { private companion object { private const val PACKAGER_OK_STATUS = "packager-status:running" - private const val HTTP_CONNECT_TIMEOUT_MS = 5_000 private const val PACKAGER_STATUS_URL_TEMPLATE = "http://%s/status" private fun createPackagerStatusURL(host: String): String = diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/RedBoxContentView.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/RedBoxContentView.kt index 30440cf10d1b..3d7b7626165a 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/RedBoxContentView.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/RedBoxContentView.kt @@ -33,12 +33,12 @@ import android.widget.TextView import com.facebook.common.logging.FLog import com.facebook.react.R import com.facebook.react.common.ReactConstants +import com.facebook.react.devsupport.inspector.DevSupportHttpClient import com.facebook.react.devsupport.interfaces.DevSupportManager import com.facebook.react.devsupport.interfaces.ErrorType import com.facebook.react.devsupport.interfaces.RedBoxHandler import com.facebook.react.devsupport.interfaces.StackFrame import okhttp3.MediaType -import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.RequestBody import org.json.JSONObject @@ -165,7 +165,7 @@ internal class RedBoxContentView( .query(null) .build() .toString() - val client = OkHttpClient() + val client = DevSupportHttpClient.httpClient for (frame in stackFrames) { val payload = stackFrameToJson(checkNotNull(frame)).toString() val body: RequestBody = RequestBody.create(JSON, payload) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/DevSupportHttpClient.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/DevSupportHttpClient.kt new file mode 100644 index 000000000000..997c3c971a55 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/DevSupportHttpClient.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +@file:Suppress("DEPRECATION_ERROR") // Conflicting okhttp versions + +package com.facebook.react.devsupport.inspector + +import java.util.concurrent.TimeUnit +import okhttp3.OkHttpClient + +/** + * Shared [OkHttpClient] instances for devsupport networking. Uses a single connection pool and + * dispatcher across all dev support HTTP and WebSocket usage. + */ +internal object DevSupportHttpClient { + /** Client for HTTP requests: connect=5s, write=disabled, read=disabled. */ + val httpClient: OkHttpClient = + OkHttpClient.Builder() + .connectTimeout(5, TimeUnit.SECONDS) + .writeTimeout(0, TimeUnit.MILLISECONDS) + .readTimeout(0, TimeUnit.MINUTES) + .build() + + /** Client for WebSocket connections: connect=10s, write=10s, read=disabled. */ + val websocketClient: OkHttpClient = + httpClient + .newBuilder() + .connectTimeout(10, TimeUnit.SECONDS) + .writeTimeout(10, TimeUnit.SECONDS) + .build() +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/InspectorNetworkHelper.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/InspectorNetworkHelper.kt index f8459b4b51e3..5b6198b5d8a0 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/InspectorNetworkHelper.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/InspectorNetworkHelper.kt @@ -10,26 +10,15 @@ package com.facebook.react.devsupport.inspector import java.io.IOException -import java.util.concurrent.TimeUnit import okhttp3.Call import okhttp3.Callback -import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response internal object InspectorNetworkHelper { - private lateinit var client: OkHttpClient @JvmStatic fun loadNetworkResource(url: String, listener: InspectorNetworkRequestListener) { - if (!::client.isInitialized) { - client = - OkHttpClient.Builder() - .connectTimeout(10, TimeUnit.SECONDS) - .writeTimeout(10, TimeUnit.SECONDS) - .readTimeout(0, TimeUnit.MINUTES) // Disable timeouts for read - .build() - } val request = try { @@ -40,7 +29,7 @@ internal object InspectorNetworkHelper { } // TODO(T196951523): Assign cancel function to listener - val call = client.newCall(request) + val call = DevSupportHttpClient.httpClient.newCall(request) call.enqueue( object : Callback {