diff --git a/platform/execution-process-mediator/client/intellij.execution.process.mediator.client.iml b/platform/execution-process-mediator/client/intellij.execution.process.mediator.client.iml
index 6db8a0e33ac6..b99fe95db7e4 100644
--- a/platform/execution-process-mediator/client/intellij.execution.process.mediator.client.iml
+++ b/platform/execution-process-mediator/client/intellij.execution.process.mediator.client.iml
@@ -20,6 +20,7 @@
+
@@ -39,5 +40,6 @@
+
\ No newline at end of file
diff --git a/platform/execution-process-mediator/client/src/com/intellij/execution/process/mediator/client/launcher/ProcessMediatorConnection.kt b/platform/execution-process-mediator/client/src/com/intellij/execution/process/mediator/client/launcher/ProcessMediatorConnection.kt
index 0fe20766181d..d71d8d892433 100644
--- a/platform/execution-process-mediator/client/src/com/intellij/execution/process/mediator/client/launcher/ProcessMediatorConnection.kt
+++ b/platform/execution-process-mediator/client/src/com/intellij/execution/process/mediator/client/launcher/ProcessMediatorConnection.kt
@@ -4,12 +4,17 @@ package com.intellij.execution.process.mediator.client.launcher
import com.intellij.execution.process.mediator.client.ProcessMediatorClient
import com.intellij.execution.process.mediator.common.DaemonClientCredentials
import com.intellij.execution.process.mediator.daemon.ProcessMediatorServerDaemon
+import com.intellij.openapi.Disposable
+import com.intellij.openapi.components.Service
+import com.intellij.openapi.components.service
import com.intellij.util.io.MultiCloseable
import com.intellij.util.io.runClosingOnFailure
import io.grpc.ManagedChannel
import io.grpc.ManagedChannelBuilder
+import io.grpc.ManagedChannelRegistry
import io.grpc.inprocess.InProcessChannelBuilder
import io.grpc.inprocess.InProcessServerBuilder
+import io.grpc.netty.shaded.io.grpc.netty.NettyChannelProvider
import io.grpc.stub.MetadataUtils
import kotlinx.coroutines.CoroutineScope
import java.io.Closeable
@@ -37,6 +42,7 @@ fun ProcessMediatorConnection.Companion.createDaemonConnection(
processHandle?.let {
registerCloseable { it.destroy() }
}
+ NettyChannelProviderRegistrationService.ensureChannelProviderRegistered()
val channel = ManagedChannelBuilder.forAddress(LOOPBACK_IP, port)
.usePlaintext()
.build().also(::registerCloseable)
@@ -76,3 +82,30 @@ private class ConnectionImpl(
) : ProcessMediatorConnection, Closeable, AutoCloseable by cleanup {
override fun toString(): String = "Connection(client=$client)"
}
+
+/**
+ * [ManagedChannelRegistry.getDefaultRegistry] has the ability to discover available [io.grpc.ManagedChannelProvider] subclasses.
+ * However, [ManagedChannelRegistry]
+ * uses a classloader that has no access to [NettyChannelProvider],
+ * because intellij.libraries.grpc module does not depend on intellij.libraries.grpc.netty.shaded,
+ * so automatic discovery fails.
+ */
+@Service(Service.Level.APP)
+private class NettyChannelProviderRegistrationService : Disposable {
+ private val registry = ManagedChannelRegistry.getDefaultRegistry()
+ private val channelProvider = NettyChannelProvider()
+
+ init {
+ registry.register(channelProvider)
+ }
+
+ override fun dispose() {
+ registry.deregister(channelProvider)
+ }
+
+ companion object {
+ fun ensureChannelProviderRegistered() {
+ service()
+ }
+ }
+}
diff --git a/platform/execution-process-mediator/client/testSrc/com/intellij/execution/process/mediator/client/ProcessMediatorTest.kt b/platform/execution-process-mediator/client/testSrc/com/intellij/execution/process/mediator/client/ProcessMediatorTest.kt
index 45750e8cc811..c06195818eed 100644
--- a/platform/execution-process-mediator/client/testSrc/com/intellij/execution/process/mediator/client/ProcessMediatorTest.kt
+++ b/platform/execution-process-mediator/client/testSrc/com/intellij/execution/process/mediator/client/ProcessMediatorTest.kt
@@ -5,6 +5,7 @@ import com.intellij.execution.process.mediator.client.launcher.ProcessMediatorCo
import com.intellij.execution.process.mediator.client.launcher.startInProcessServer
import com.intellij.execution.process.mediator.client.rt.MediatedProcessTestMain
import com.intellij.openapi.util.io.FileUtil
+import com.intellij.testFramework.junit5.TestApplication
import kotlinx.coroutines.*
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Assertions.*
@@ -20,6 +21,7 @@ import java.util.concurrent.CancellationException
import java.util.stream.Collectors
import java.util.stream.Stream
+@TestApplication
open class ProcessMediatorTest {
private val deferred = CompletableDeferred()
private val coroutineScope = CoroutineScope(deferred + CoroutineExceptionHandler { _, cause ->