IDEA-336005 unload services by module descriptor instead of plugin id

What happened:
1. plugin X was unloaded.
2. a module U of another plugin Y was unloaded as well because it depends on module from X.
3. still loaded module L of Y was requesting the services which is a part of L.

Before the change:
- L services were unloaded together with U services on a step 2 because of `PluginId` as the key.

After the change:
- L services are intact, step 2 only unloads services of unloaded module U.

GitOrigin-RevId: 455fca458a8622ef3efb8b250a5e56ac516f4084
This commit is contained in:
Daniil Ovchinnikov
2023-10-25 16:57:16 +02:00
committed by intellij-monorepo-bot
parent a4f53413fd
commit 01b9d2dbc0
3 changed files with 20 additions and 22 deletions

View File

@@ -702,6 +702,9 @@ object DynamicPlugins {
val app = ApplicationManager.getApplication() as ApplicationImpl
(ActionManager.getInstance() as ActionManagerImpl).unloadActions(module)
if (module.pluginId.idString == "com.intellij.jsp") {
println("Unloading")
}
val openedProjects = ProjectUtil.getOpenProjects().asList()
val appExtensionArea = app.extensionArea
val priorityUnloadListeners = mutableListOf<Runnable>()
@@ -738,20 +741,19 @@ object DynamicPlugins {
area.unregisterExtensionPoints(points, module)
}
val pluginId = module.pluginId
app.unloadServices(module.appContainerDescriptor.services, pluginId)
app.unloadServices(module, module.appContainerDescriptor.services)
val appMessageBus = app.messageBus as MessageBusEx
module.appContainerDescriptor.listeners?.let { appMessageBus.unsubscribeLazyListeners(module, it) }
for (project in openedProjects) {
(project as ComponentManagerImpl).unloadServices(module.projectContainerDescriptor.services, pluginId)
(project as ComponentManagerImpl).unloadServices(module, module.projectContainerDescriptor.services)
module.projectContainerDescriptor.listeners?.let {
((project as ComponentManagerImpl).messageBus as MessageBusEx).unsubscribeLazyListeners(module, it)
}
val moduleServices = module.moduleContainerDescriptor.services
for (ideaModule in ModuleManager.getInstance(project).modules) {
(ideaModule as ComponentManagerImpl).unloadServices(moduleServices, pluginId)
(ideaModule as ComponentManagerImpl).unloadServices(module, moduleServices)
createDisposeTreePredicate(module)?.let { Disposer.disposeChildren(ideaModule, it) }
}

View File

@@ -2,11 +2,11 @@
package com.intellij.openapi.client
import com.intellij.codeWithMe.ClientId
import com.intellij.ide.plugins.IdeaPluginDescriptor
import com.intellij.ide.plugins.IdeaPluginDescriptorImpl
import com.intellij.openapi.application.Application
import com.intellij.openapi.components.ServiceDescriptor
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.extensions.PluginId
import com.intellij.serviceContainer.ComponentManagerImpl
import com.intellij.serviceContainer.PrecomputedExtensionModel
import com.intellij.serviceContainer.throwAlreadyDisposedError
@@ -69,12 +69,12 @@ abstract class ClientAwareComponentManager: ComponentManagerImpl {
}
}
override fun unloadServices(services: List<ServiceDescriptor>, pluginId: PluginId) {
super.unloadServices(services, pluginId)
override fun unloadServices(module: IdeaPluginDescriptor, services: List<ServiceDescriptor>) {
super.unloadServices(module, services)
val sessionsManager = super.getService(ClientSessionsManager::class.java)!!
for (session in sessionsManager.getSessions(ClientKind.ALL)) {
(session as? ClientSessionImpl)?.unloadServices(services, pluginId)
(session as? ClientSessionImpl)?.unloadServices(module, services)
}
}

View File

@@ -17,10 +17,7 @@ import com.intellij.openapi.application.*
import com.intellij.openapi.components.*
import com.intellij.openapi.components.ServiceDescriptor.PreloadMode
import com.intellij.openapi.components.impl.stores.IComponentStore
import com.intellij.openapi.diagnostic.Attachment
import com.intellij.openapi.diagnostic.ControlFlowException
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.diagnostic.*
import com.intellij.openapi.extensions.*
import com.intellij.openapi.extensions.impl.ExtensionPointImpl
import com.intellij.openapi.extensions.impl.ExtensionsAreaImpl
@@ -219,7 +216,7 @@ abstract class ComponentManagerImpl(
ordered = true,
)
private val pluginServices = ConcurrentHashMap<PluginId, UnregisterHandle>()
private val pluginServices = ConcurrentHashMap<IdeaPluginDescriptor, UnregisterHandle>()
@Suppress("LeakingThis")
internal val dependencyResolver = ComponentManagerResolver(this)
@@ -914,8 +911,7 @@ abstract class ComponentManagerImpl(
}
val handle: UnregisterHandle? = registrar.complete()
if (handle != null) {
val pluginId = pluginDescriptor.pluginId
pluginServices.put(pluginId, handle)
pluginServices.put(pluginDescriptor, handle)
}
}
@@ -1465,9 +1461,9 @@ abstract class ComponentManagerImpl(
return PluginException(message, error, pluginId, attachments?.map { Attachment(it.key, it.value) } ?: emptyList())
}
open fun unloadServices(services: List<ServiceDescriptor>, pluginId: PluginId) {
open fun unloadServices(module: IdeaPluginDescriptor, services: List<ServiceDescriptor>) {
if (useInstanceContainer) {
unloadServices2(pluginId)
unloadServices2(module)
return
}
checkState()
@@ -1497,7 +1493,7 @@ abstract class ComponentManagerImpl(
val iterator = componentKeyToAdapter.values.iterator()
while (iterator.hasNext()) {
val adapter = iterator.next() as? LightServiceComponentAdapter ?: continue
if (adapter.pluginId == pluginId) {
if (adapter.pluginId == module.pluginId) {
adapter.getInitializedInstance()?.let { instance ->
if (instance is Disposable) {
Disposer.dispose(instance)
@@ -1510,17 +1506,17 @@ abstract class ComponentManagerImpl(
}
}
private fun unloadServices2(pluginId: PluginId) {
private fun unloadServices2(module: IdeaPluginDescriptor) {
val debugString = debugString(true)
val handle = pluginServices.get(pluginId)
val handle = pluginServices.get(module)
if (handle == null) {
LOG.debug("$debugString : nothing to unload $pluginId")
LOG.debug { "$debugString : nothing to unload ${module.pluginId}:${module.descriptorPath}" }
return
}
val holders = handle.unregister()
if (holders.isEmpty()) {
// warn because the handle should not be in the map in the first place
LOG.warn("$debugString : nothing unloaded for $pluginId")
LOG.warn("$debugString : nothing unloaded for ${module.pluginId}:${module.descriptorPath}")
return
}
val store = componentStore