imagej / imagej-launcher

The ImageJ native launcher
https://imagej.net/learn/launcher
BSD 2-Clause "Simplified" License
21 stars 23 forks source link

Splash screen broken with Java 9 #50

Closed stelfrich closed 5 years ago

stelfrich commented 6 years ago

See http://forum.imagej.net/t/please-test-the-new-imagej-launcher/8238/8.

ctrueden commented 6 years ago

IIRC, you will never see a splash screen when the launcher falls back to system Java.

The question is: is the splash screen shown when the libjvm.so is linked successfully?

stelfrich commented 6 years ago

IIRC, you will never see a splash screen when the launcher falls back to system Java.

I can confirm that.

The question is: is the splash screen shown when the libjvm.so is linked successfully?

I couldn't make the linking work properly. My first attempts are on the fix-java9-and-splash branch. This fixes the issue of the new folder structure in Java 9 but it can't dlopen(/<path>/libsplashscreen.so) even if <path> is correct.

imagejan commented 6 years ago

you will never see a splash screen when the launcher falls back to system Java.

That is strange: on my system (Windows 7, JDK 1.8.0_144) the splash screen is always shown, even with the new launcher (and it is using the system Java 8)...

ctrueden commented 6 years ago

and it is using the system Java 8

But do you see the message "falling back to system Java" on the console?

I think this message means that it invokes java.exe or javaw.exe as a subprocess, rather than linking to the jvm.dll and invoking Java via a function call.

But as always with the launcher, I could be wrong—I haven't studied the code in quite some time and my memory may be faulty.

stelfrich commented 6 years ago

At least for the Linux versions of JDK9 libsplashscreen is linked against libjvm (which was not the case for Java 8). dlopen("/path/to/libsplashscreen.so") will try to resolve libjvm which fails if LD_LIBRRAY_PATH does not contain /path/to/jdk/lib/server (that's on step of the default procedure to resolve dependencies):

➜  pwd
/opt/jdk-9.0.4/lib
➜  ldd libsplashscreen.so 
    linux-vdso.so.1 =>  (0x00007ffe761b7000)
    libjava.so => /opt/jdk-9.0.4/lib/./libjava.so (0x00007f66bb10b000)
    libjvm.so => not found
    libX11.so.6 => /usr/lib/x86_64-linux-gnu/libX11.so.6 (0x00007f66badd1000)
    libXext.so.6 => /usr/lib/x86_64-linux-gnu/libXext.so.6 (0x00007f66babbf000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f66ba8b6000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f66ba699000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f66ba495000)
    libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f66ba27b000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f66b9eb1000)
    libjvm.so => not found
    libverify.so => /opt/jdk-9.0.4/lib/./libverify.so (0x00007f66b9ca3000)
    libxcb.so.1 => /usr/lib/x86_64-linux-gnu/libxcb.so.1 (0x00007f66b9a81000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f66bb589000)
    libjvm.so => not found
    libXau.so.6 => /usr/lib/x86_64-linux-gnu/libXau.so.6 (0x00007f66b987d000)
    libXdmcp.so.6 => /usr/lib/x86_64-linux-gnu/libXdmcp.so.6 (0x00007f66b9677000)

With some fixes on fix-java9-on-cmake the following call spins up ImageJ using Java9 with a splashscreen.

LD_LIBRARY_PATH=/opt/jdk-9.0.1/lib/server ./imagej-launcher --ij-dir /opt/Fiji/Fiji.app --java-home /opt/jdk-9.0.1
stelfrich commented 6 years ago

I have tried to dlopen("libjvm.so", RTLD_NOW | RTLD_GLOBAL); before dlopening libsplashscreen on the fix-splash branch (as suggested in https://stackoverflow.com/a/26628126). This seems to solve the linking issue, but results in a segmentation fault in libosxapp#getJNIEnv().

stelfrich commented 6 years ago
Stack: [0x00007fff5d995000,0x00007fff5e195000],  sp=0x00007fff5e1935d0,  free space=8185k
Native frames: (J=compiled Java code, A=aot compiled Java code, j=interpreted, Vv=VM code, C=native code)
C  [libosxapp.dylib+0x36f6]  +[ThreadUtilities getJNIEnv]+0x96
C  [libosxapp.dylib+0x168a]  -[NSApplicationAWT registerWithProcessManager]+0x7f
C  [libosxapp.dylib+0x12e0]  -[NSApplicationAWT init]+0x8f
C  [AppKit+0x4282]  +[NSApplication sharedApplication]+0x8e
C  [libsplashscreen.dylib+0x36a71]  __SplashInitPlatform_block_invoke+0x31
C  [JavaNativeFoundation+0x65f5]  +[JNFRunLoop _performCopiedBlock:]+0x14
C  [Foundation+0x7152a]  __NSThreadPerformPerform+0x146
C  [CoreFoundation+0xa7321]  __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__+0x11
C  [CoreFoundation+0x8821d]  __CFRunLoopDoSources0+0x22d
C  [CoreFoundation+0x87716]  __CFRunLoopRun+0x3a6
C  [CoreFoundation+0x87114]  CFRunLoopRunSpecific+0x1a4
C  [CoreFoundation+0xc6b91]  CFRunLoopRun+0x61
C  [ImageJ-macosx+0xc9bc]  start_ij_macosx+0x1dc
C  [ImageJ-macosx+0x2c8d]  main+0x26d
C  [libdyld.dylib+0x5235]  start+0x1

http://hg.openjdk.java.net/jdk9/jdk9/jdk/file/38bf8bb1f5e7/src/java.desktop/macosx/native/libsplashscreen/splashscreen_sys.m#l206

http://hg.openjdk.java.net/jdk9/jdk9/jdk/file/38bf8bb1f5e7/src/java.desktop/macosx/native/libosxapp/NSApplicationAWT.m#l153

http://hg.openjdk.java.net/jdk9/jdk9/jdk/file/38bf8bb1f5e7/src/java.desktop/macosx/native/libosxapp/ThreadUtilities.m#l52


We could also think about using JLI instead of JNI:

http://mail.openjdk.java.net/pipermail/macosx-port-dev/2014-November/006798.html

http://hg.openjdk.java.net/jdk9/jdk9/jdk/file/38bf8bb1f5e7/src/java.base/share/native/launcher/main.c

stelfrich commented 6 years ago

@ctrueden has done some work on the splash branch. The idea is to use Java's built-in functionality via java -splash:images/icon-flat.png ....

The issue with this approach is, that this is an argument to the native launcher, which internally uses libsplashscreen for showing the splash screen. If we continue to manually spin up a JVM with libjvm, we can't use -splash:<file>. @ctrueden's implementation actually works with minor changes to force the launcher to fall back to directly calling java ... without using libjvm.