substrate icon indicating copy to clipboard operation
substrate copied to clipboard

java.lang.NoSuchFieldError: java.net.Inet6Address.cached_scope_id on Android

Open marinier opened this issue 3 years ago • 10 comments

I have a complex Gluon Mobile application I can't share that I was previously building with Gluon GraalVM 21.2. It uses Socket.IO to connect to another application. Under Gluon GraalVM 22.0 it fails to create the socket.

This application was created using the Gluon Mobile Eclipse plugin (single view project). The versions of the various dependencies and plugins have been updated to their latest versions. The socket creation occurs in GluonApplication's constructor.

A reproducer is available at: https://github.com/marinier/androidsockettest

Expected Behavior

No exceptions.

Current Behavior

[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): Exception in thread "OkHttp Dispatcher" java.lang.NoSuchFieldError: java.net.Inet6Address.cached_scope_id
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at com.oracle.svm.jni.functions.JNIFunctions$Support.getFieldID(JNIFunctions.java:1207)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at com.oracle.svm.jni.functions.JNIFunctions.GetFieldID(JNIFunctions.java:434)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at java.net.Inet6Address.init(Inet6Address.java)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at java.net.Inet6Address.<clinit>(Inet6Address.java:369)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at java.lang.Class.ensureInitialized(DynamicHub.java:510)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at com.oracle.svm.jni.functions.JNIFunctions.FindClass(JNIFunctions.java:355)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at java.net.PlainSocketImpl.initProto(PlainSocketImpl.java)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at java.net.PlainSocketImpl.<clinit>(PlainSocketImpl.java:43)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at java.lang.Class.ensureInitialized(DynamicHub.java:510)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at java.net.Socket.setImpl(Socket.java:523)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at java.net.Socket.<init>(Socket.java:88)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at javax.net.DefaultSocketFactory.createSocket(SocketFactory.java:265)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.java:241)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:167)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:258)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:135)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:114)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:127)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:257)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at okhttp3.RealCall$AsyncCall.execute(RealCall.java:201)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at java.lang.Thread.run(Thread.java:829)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:597)
[Mon. Feb. 14 12:25:32 EST 2022][INFO] [SUB] D/GraalCompiled( 7241): 	at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:194)

Steps to Reproduce

Reproducer at: https://github.com/marinier/androidsockettest Using Gluon GraalVM 22.0.0.3 JDK 11:

mvn -Pandroid gluonfx:build gluonfx:package gluonfx:install gluonfx:nativerun

Since this looks like it could be reflection related, I added this to the reflection-config.json:

{
  "name":"java.net.Inet6Address",
  "allDeclaredConstructors" : true,
  "allPublicConstructors" : true,
  "allDeclaredMethods" : true,
  "allPublicMethods" : true,
  "allDeclaredClasses" : true,
  "allPublicClasses" : true,
  "queryAllPublicConstructors":true
}

But that makes no difference. (The rest of the reflection config was generated using the native agent.)

Your Environment

  • Ubuntu 20.04 in a VirtualBox VM on Windows 10
  • Gluon GraalVM 22.0.0.3 JDK 11
  • Android 12 (although the original application demonstrated the issue on Android 10 as well, I only have access to an Android 10 phone for testing the reproducer)

marinier avatar Feb 14 '22 20:02 marinier

Error message mentions JNI, did you try adding it to the jni-config.json instead?

For your info, we removed it from the default generated file jni-config.json: https://github.com/gluonhq/substrate/commit/06a0f1431397eebeabc5bdb626654fc8ae70645b

jperedadnr avatar Feb 14 '22 20:02 jperedadnr

I tried putting the same block I had in the reflection config in the jni config:

{
  "name":"java.net.Inet6Address",
  "allDeclaredConstructors" : true,
  "allPublicConstructors" : true,
  "allDeclaredMethods" : true,
  "allPublicMethods" : true,
  "allDeclaredClasses" : true,
  "allPublicClasses" : true,
  "queryAllPublicConstructors":true
}

This did not work (same exception). I then tried putting in the configuration from before the change in 06a0f1431397eebeabc5bdb626654fc8ae70645b:

{
  "name":"java.net.Inet6Address",
  "methods":[{"name":"<init>","parameterTypes":[] }],
    "fields":[
      {"name":"cached_scope_id"},
      {"name":"holder6"}
    ]
}

But that didn't work either (same exception).

marinier avatar Feb 14 '22 22:02 marinier

Hmm, so adding the method doesn't work, because it was removed from JDK 11.0.14 (the one used to build Gluon's GraalVM 22.0.0.3), but your dependencies might be still somehow calling it.

For a quick test you could try Gluon's GraalVM 22.0.0.2 that was built with JDK 11.0.13 (which uses that cached_scope_id field)?

jperedadnr avatar Feb 14 '22 23:02 jperedadnr

I confirmed that things work with 22.0.0.2 with no additional configuration needed in either reflection config or jni config in both the reproducer and my original app. Thank you!

The socket.io dependencies I'm using for network communication do not mention cached_scope_id anywhere in their code.

From the exception callstack, this involves the java.net.Inet6Address.init method, which is native. In the native code it is still trying to use cached_scope_id.

It seems like this change was intended to deal with the possible absence of this field, but the native java.net.Inet6Address.init method is still trying to access it. Is it possible this is a bug in the JDK itself? It looks like that native code hasn't been updated since 2017.

marinier avatar Feb 15 '22 14:02 marinier

This issue might be then with the JDK you are using (is it AdoptOpenJDK?).

GraalVM is built with labsjdk JDK 11.0.13 (for 22.0.0.2) or 11.0.14 (for 22.0.0.3), and labsjdk is forked from OpenJDK/jdk11u itself.

The change was a backport from https://bugs.openjdk.java.net/browse/JDK-8216417 into JDK 11.0.14, and that's why GraalVM has the change registering the field cached_scope_id based on a given version that you have linked.

See https://github.com/openjdk/jdk11u-dev/blob/master/src/java.base/share/native/libnet/Inet6Address.c, it doesn't have the field. It might be possible that AdoptOpenJDK doesn't include this backport yet?

If you run with export JAVA_HOME=$GRAALVM_HOME (instead of using Adopt

jperedadnr avatar Feb 18 '22 09:02 jperedadnr

Sorry, I just linked to open jdk because that's what I found first, and I assumed they were all the same. I checked and the default java on Ubuntu 20.04 is 11.0.13, so I just set JAVA_HOME to GRAALVM_HOME like you said.

soartech@soartech-VirtualBox:~/isaac/isaac$ echo $JAVA_HOME
/home/soartech/graalvm-svm-java11-linux-gluon-22.0.0.3-Final
soartech@soartech-VirtualBox:~/isaac/isaac$ java -version
openjdk version "11.0.14" 2022-01-18
OpenJDK Runtime Environment GraalVM 22.0.0.2 (build 11.0.14+9-jvmci-22.0-b05)
OpenJDK 64-Bit Server VM GraalVM 22.0.0.2 (build 11.0.14+9-jvmci-22.0-b05, mixed mode, sharing)

Unfortunately, I get the same exception.

marinier avatar Feb 18 '22 20:02 marinier

Have you tried the reproducer I created? https://github.com/marinier/androidsockettest

If it works for you, then we know it's something about my setup (although I don't see what it could be) vs. something in graalvm or substrate or something else.

marinier avatar Feb 18 '22 21:02 marinier

There is a similar issue reported here: https://github.com/gluonhq/gluonfx-maven-plugin/issues/417

marinier avatar Feb 18 '22 21:02 marinier

I've tested your project with GraalVM 22.0.0.3 (JDK11), on Android 10, Either with an old OpenJDK 11.0.2 or when doing export JAVA_HOME=$GRAALVM_HOME, I get

[Fri Feb 18 23:47:34 CET 2022][INFO] [SUB] D/GraalCompiled(11789): Exception in thread "OkHttp Dispatcher" java.lang.NoSuchFieldError: java.net.Inet6Address.cached_scope_id
[Fri Feb 18 23:47:34 CET 2022][INFO] [SUB] D/GraalCompiled(11789): 	at com.oracle.svm.jni.functions.JNIFunctions$Support.getFieldID(JNIFunctions.java:1207)
[Fri Feb 18 23:47:34 CET 2022][INFO] [SUB] D/GraalCompiled(11789): 	at com.oracle.svm.jni.functions.JNIFunctions.GetFieldID(JNIFunctions.java:434)
[Fri Feb 18 23:47:34 CET 2022][INFO] [SUB] D/GraalCompiled(11789): 	at java.net.Inet6Address.init(Inet6Address.java)
[Fri Feb 18 23:47:34 CET 2022][INFO] [SUB] D/GraalCompiled(11789): 	at java.net.Inet6Address.<clinit>(Inet6Address.java:369)
[Fri Feb 18 23:47:34 CET 2022][INFO] [SUB] D/GraalCompiled(11789): 	at java.lang.Class.ensureInitialized(DynamicHub.java:510)

Building with 22.0.0.3 (JDK17) works fine though. No exception is shown.

I might have an explanation for this issue: Substrate for Android uses java static libs from openjdk/mobile, for JDK 17 the libs were recently generated, but for 11 these libs use an old version: https://github.com/gluonhq/substrate/blob/master/src/main/java/com/gluonhq/substrate/Constants.java#L109

that was done before the inet6Address change was done. Therefore, there is a mismatch between GraalVM and Substrate Java/static.

The proper fix will be building again the Java/static libs for mobile with the latest JDK 11 (right, @johanvos ?).

jperedadnr avatar Feb 18 '22 23:02 jperedadnr

For what it's worth, I've just upgraded

From:

  • <maven.compiler.release>11</maven.compiler.release>
  • <gluonfx.plugin.version>1.0.12</gluonfx.plugin.version>
  • <charm-glisten.version>6.1.1</charm-glisten.version>
  • <gluonhq-attach.version>4.0.14</gluonhq-attach.version>
  • GRAALVM_HOME=/opt/graalvm/graalvm-svm-java11-linux-gluon-22.0.0.3-Final

To:

  • <maven.compiler.release>17</maven.compiler.release>
  • <gluonfx.plugin.version>1.0.16</gluonfx.plugin.version>
  • <charm-glisten.version>6.2.2</charm-glisten.version>
  • <gluonhq-attach.version>4.0.16</gluonhq-attach.version>
  • GRAALVM_HOME=/opt/graalvm/graalvm-svm-java17-linux-gluon-22.1.0.1-Final

and all of my build / run problems went away.

Note, I still had some dwindling issues afterwards which cleared up after I purged folder ~/.gluon/substrate/Android and updated file src/android/AndroidManifest.xml with new, required attribute android:exported="true".

javateer avatar Dec 01 '22 18:12 javateer