Develop custom plugin for Android Studio and got a LinkageError

Answered

I'm developing a custom plugin for Android Studio, which will reference some classes from the android plugin and call some gradle tasks through gradle tooling api.
After add <depends>org.jetbrains.android</depends> in the plugin.xml, I got a LinkageError when use the gradle tooling api:

org.gradle.tooling.GradleConnectionException: Could not create an instance of Tooling API implementation using the specified Gradle distribution 'https://services.gradle.org/distributions/gradle-5.4.1-all.zip'.
at org.gradle.tooling.internal.consumer.loader.DefaultToolingImplementationLoader.create(DefaultToolingImplementationLoader.java:110)
at org.gradle.tooling.internal.consumer.loader.CachingToolingImplementationLoader.create(CachingToolingImplementationLoader.java:44)
at org.gradle.tooling.internal.consumer.loader.SynchronizedToolingImplementationLoader.create(SynchronizedToolingImplementationLoader.java:43)
at org.gradle.tooling.internal.consumer.connection.LazyConsumerActionExecutor.onStartAction(LazyConsumerActionExecutor.java:101)
at org.gradle.tooling.internal.consumer.connection.LazyConsumerActionExecutor.run(LazyConsumerActionExecutor.java:83)
at org.gradle.tooling.internal.consumer.connection.CancellableConsumerActionExecutor.run(CancellableConsumerActionExecutor.java:45)
at org.gradle.tooling.internal.consumer.connection.ProgressLoggingConsumerActionExecutor.run(ProgressLoggingConsumerActionExecutor.java:58)
at org.gradle.tooling.internal.consumer.connection.RethrowingErrorsConsumerActionExecutor.run(RethrowingErrorsConsumerActionExecutor.java:38)
at org.gradle.tooling.internal.consumer.async.DefaultAsyncConsumerActionExecutor$1$1.run(DefaultAsyncConsumerActionExecutor.java:55)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
at java.lang.Thread.run(Thread.java:748)
at org.gradle.tooling.internal.consumer.BlockingResultHandler.getResult(BlockingResultHandler.java:46)
at org.gradle.tooling.internal.consumer.DefaultBuildLauncher.run(DefaultBuildLauncher.java:77)
at com.bytedance.farseer.ide.GradleCommandManager.run(GradleCommandManager.java:35)
at com.bytedance.farseer.ide.SwitchManager.cascadedInclude(SwitchManager.java:85)
at com.bytedance.farseer.ide.ui.CascadeIncludeAction$1.run(CascadeIncludeAction.java:39)
at com.intellij.openapi.progress.impl.CoreProgressManager$TaskRunnable.run(CoreProgressManager.java:894)
at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$runProcess$2(CoreProgressManager.java:169)
at com.intellij.openapi.progress.impl.CoreProgressManager.registerIndicatorAndRun(CoreProgressManager.java:591)
at com.intellij.openapi.progress.impl.CoreProgressManager.executeProcessUnderProgress(CoreProgressManager.java:537)
at com.intellij.openapi.progress.impl.ProgressManagerImpl.executeProcessUnderProgress(ProgressManagerImpl.java:59)
at com.intellij.openapi.progress.impl.CoreProgressManager.runProcess(CoreProgressManager.java:156)
at com.intellij.openapi.progress.impl.CoreProgressManager$4.run(CoreProgressManager.java:408)
at com.intellij.openapi.application.impl.ApplicationImpl$1.run(ApplicationImpl.java:294)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.RuntimeException: Could not create an implementation of service 'org.gradle.tooling.internal.protocol.ConnectionVersion4'.
at org.gradle.internal.service.DefaultServiceLocator$ServiceFactory.newInstance(DefaultServiceLocator.java:182)
at org.gradle.internal.service.DefaultServiceLocator$ServiceFactory.create(DefaultServiceLocator.java:175)
at org.gradle.tooling.internal.consumer.loader.DefaultToolingImplementationLoader.create(DefaultToolingImplementationLoader.java:84)
at org.gradle.tooling.internal.consumer.loader.CachingToolingImplementationLoader.create(CachingToolingImplementationLoader.java:44)
at org.gradle.tooling.internal.consumer.loader.SynchronizedToolingImplementationLoader.create(SynchronizedToolingImplementationLoader.java:43)
at org.gradle.tooling.internal.consumer.connection.LazyConsumerActionExecutor.onStartAction(LazyConsumerActionExecutor.java:101)
at org.gradle.tooling.internal.consumer.connection.LazyConsumerActionExecutor.run(LazyConsumerActionExecutor.java:83)
at org.gradle.tooling.internal.consumer.connection.CancellableConsumerActionExecutor.run(CancellableConsumerActionExecutor.java:45)
at org.gradle.tooling.internal.consumer.connection.ProgressLoggingConsumerActionExecutor.run(ProgressLoggingConsumerActionExecutor.java:58)
at org.gradle.tooling.internal.consumer.connection.RethrowingErrorsConsumerActionExecutor.run(RethrowingErrorsConsumerActionExecutor.java:38)
at org.gradle.tooling.internal.consumer.async.DefaultAsyncConsumerActionExecutor$1$1.run(DefaultAsyncConsumerActionExecutor.java:55)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
... 1 more
Caused by: org.gradle.api.reflect.ObjectInstantiationException: Could not create an instance of type org.gradle.tooling.internal.provider.DefaultConnection.
at org.gradle.internal.reflect.DirectInstantiator.newInstance(DirectInstantiator.java:55)
at org.gradle.internal.reflect.DirectInstantiator.instantiate(DirectInstantiator.java:35)
at org.gradle.internal.service.DefaultServiceLocator$ServiceFactory.newInstance(DefaultServiceLocator.java:180)
... 16 more
Caused by: java.lang.LinkageError: loader constraint violation in interface itable initialization: when resolving method "org.gradle.tooling.internal.provider.DefaultConnection.run(Lorg/gradle/tooling/internal/protocol/InternalPhasedAction;Lorg/gradle/tooling/internal/protocol/PhasedActionResultListener;Lorg/gradle/tooling/internal/protocol/InternalCancellationToken;Lorg/gradle/tooling/internal/protocol/BuildParameters;)Lorg/gradle/tooling/internal/protocol/BuildResult;" the class loader (instance of org/gradle/internal/classloader/VisitableURLClassLoader) of the current class, org/gradle/tooling/internal/provider/DefaultConnection, and the class loader (instance of com/intellij/ide/plugins/cl/PluginClassLoader) for interface org/gradle/tooling/internal/protocol/InternalPhasedActionConnection have different Class objects for the type org/gradle/tooling/internal/protocol/BuildParameters used in the signature
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
at java.lang.Class.getConstructors(Class.java:1651)
at org.gradle.internal.reflect.DirectInstantiator$ConstructorCache.create(DirectInstantiator.java:80)
at org.gradle.internal.reflect.DirectInstantiator$ConstructorCache.create(DirectInstantiator.java:75)
at org.gradle.internal.reflect.ReflectionCache$WeaklyClassReferencingCache.get(ReflectionCache.java:56)
at org.gradle.internal.reflect.ReflectionCache.get(ReflectionCache.java:36)
at org.gradle.internal.reflect.DirectInstantiator.newInstance(DirectInstantiator.java:49)
... 18 more


My intellij extension in build.gradle is:

intellij {
version '192.7142.36'
updateSinceUntilBuild false
sameSinceUntilBuild false
downloadSources !Boolean.valueOf(System.getenv('CI'))
type 'IC'
plugins "android"
}

My plugin.xml is:

<idea-plugin>
<id>com.bytedance.tools.build.farseer-idea-plugin</id>

<!-- please see https://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/plugin_compatibility.html
on how to target different products -->
<depends>org.jetbrains.android</depends>
<depends>com.intellij.modules.androidstudio</depends>
</idea-plugin>

What should I do to resolve this problem?

5 comments
Comment actions Permalink

Stacktrace refers to the Gradle version. Can you please make sure that you have the latest Gradle version available?

0
Comment actions Permalink

 My env is:

------------------------------------------------------------
Gradle 5.6
------------------------------------------------------------

Build time: 2019-08-14 21:05:25 UTC
Revision: f0b9d60906c7b8c42cd6c61a39ae7b74767bb012

Kotlin: 1.3.41
Groovy: 2.5.4
Ant: Apache Ant(TM) version 1.9.14 compiled on March 12 2019
JVM: 1.8.0_222 (AdoptOpenJDK 25.222-b10)
OS: Mac OS X 10.14.6 x86_64

But I think it's not a Gradle issue. In my opinion, the most important part in the stacktrace is:

Caused by: java.lang.LinkageError: loader constraint violation in interface itable initialization: when resolving method "org.gradle.tooling.internal.provider.DefaultConnection.run(Lorg/gradle/tooling/internal/protocol/InternalPhasedAction;Lorg/gradle/tooling/internal/protocol/PhasedActionResultListener;Lorg/gradle/tooling/internal/protocol/InternalCancellationToken;Lorg/gradle/tooling/internal/protocol/BuildParameters;)Lorg/gradle/tooling/internal/protocol/BuildResult;" the class loader (instance of org/gradle/internal/classloader/VisitableURLClassLoader) of the current class, org/gradle/tooling/internal/provider/DefaultConnection, and the class loader (instance of com/intellij/ide/plugins/cl/PluginClassLoader) for interface org/gradle/tooling/internal/protocol/InternalPhasedActionConnection have different Class objects for the type org/gradle/tooling/internal/protocol/BuildParameters used in the signature
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
at java.lang.Class.getConstructors(Class.java:1651)
at org.gradle.internal.reflect.DirectInstantiator$ConstructorCache.create(DirectInstantiator.java:80)
at org.gradle.internal.reflect.DirectInstantiator$ConstructorCache.create(DirectInstantiator.java:75)
at org.gradle.internal.reflect.ReflectionCache$WeaklyClassReferencingCache.get(ReflectionCache.java:56)
at org.gradle.internal.reflect.ReflectionCache.get(ReflectionCache.java:36)
at org.gradle.internal.reflect.DirectInstantiator.newInstance(DirectInstantiator.java:49)
... 18 more

And this only happens when I add

<depends>org.jetbrains.android</depends>

in the plugin.xml. Maybe it's about the classloader of this plugin? Thanks for your reply.

0
Comment actions Permalink

Accorading to the message of the LinkageError, I think the problem is that class org.gradle.tooling.internal.protocol.BuildParameters is loaded by com.intellij.ide.plugins.cl.PluginClassLoader and org.gradle.internal.classloader.VisitableURLClassLoader. So how can I avoid this in my plugin? By the way, this only happens when I add

<depends>org.jetbrains.android</depends>

in the plugin.xml. But I need to use some classes provided by this plugin. Is any thing wrong with my configuraion?

 

0
Comment actions Permalink

After I read the document about classloader again, I found:

 However, in the plugin.xml file, you may use the <depends> element to specify that a plugin depends on one or more other plugins. In this case the class loaders of those plugins will be used for classes not found in the current plugin.

So I make my dependency of gradle tooling api compileOnly:

compileOnly "org.gradle:gradle-tooling-api:4.4.1"

The problem was solved.

 

0
Comment actions Permalink

I'm glad that you've managed to fix it. Thanks for leaving the answer here!

0

Please sign in to leave a comment.