JDK-8294699 : Launcher causes lingering busy cursor
  • Type: Bug
  • Component: tools
  • Sub-Component: jpackage
  • Affected Version: 17.0.2,18,21,22
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_10
  • CPU: x86_64
  • Submitted: 2022-09-26
  • Updated: 2024-11-09
  • Resolved: 2023-12-05
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 17 JDK 21 JDK 22
17.0.12-oracleFixed 21.0.4-oracleFixed 22 b27Fixed
Related Reports
Duplicate :  
Duplicate :  
Relates :  
Description
ADDITIONAL SYSTEM INFORMATION :
Windows 10.
Java 17.

A DESCRIPTION OF THE PROBLEM :
Normally, when an application is launched from the desktop or start menu on Windows, the system turns the mouse cursor into a busy indicator (e.g. an hourglass or circle) while the application is launching and restores the regular cursor once the application has finished launching.

This works as expected for Java applications launched using "javaw.exe".

However, when a Java application is packaged with jpackage and launched using the exe launcher that jpackage creates, the busy cursor lingers for several seconds after the application's window shows up on screen.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Take any small Java application, one that launches quickly.
2. Package it on Windows using jpackage with the "--win-shortcut" option.
3. Install the packaged application.
4. Launch the packaged application from the desktop using the shortcut.

Below is a WSH script which, when executed with "cscript build.js" and assuming HelloSwing.java contains some simple Swing application, performs the first 3 steps and additionally creates the shortcut "ExpectedBehavior.lnk" for comparison (which launches the same JAR using "javaw").

    var shell = WSH.CreateObject("WScript.Shell")
    var shellapp = WSH.CreateObject("Shell.Application");
    var fs = WSH.CreateObject("Scripting.FileSystemObject")

    function main() {
      withTempDir(function(tempdir) {
        build(tempdir)
        package(tempdir)
      })

      install("HelloSwing-1.0.msi")

      createSystemJavaAppShortcut()
    }

    function build(appdir) {
      run("javac HelloSwing.java")
      var jarPath = joinPath(appdir, "hello.jar")
      run("jar cfe " + quote(jarPath) + " HelloSwing HelloSwing.class")
    }

    function package(appdir) {
      var cmd = "jpackage"
      cmd += " -i " + quote(appdir)
      cmd += " --main-jar hello.jar"
      cmd += " --type msi --win-per-user-install --win-shortcut"
      cmd += " --add-modules java.base,java.desktop"
      run(cmd)
    }

    function install(msiPath) {
      run("msiexec /i " + quote(msiPath) + " /norestart")
    }

    function createSystemJavaAppShortcut() {
      var exePath = getDesktopShortcutPath("HelloSwing.lnk")
      var installDir = fs.GetParentFolderName(exePath)
      var desktopPath = shell.SpecialFolders("Desktop")
      var shortcutPath = joinPath(desktopPath, "ExpectedBehavior.lnk")
      var jarPath = joinPath(installDir, "app", "hello.jar")
      var shortcut = shell.CreateShortcut(shortcutPath)
      shortcut.TargetPath = "javaw"
      shortcut.Arguments = "-jar " + quote(jarPath)
      shortcut.Save()
    }

    function getDesktopShortcutPath(name) {
        var desktop = shellapp.Namespace(0)
        var shortcut = desktop.ParseName(name).GetLink
        return shortcut.Path
    }

    function withTempDir(func) {
      var path = joinPath(fs.GetSpecialFolder(2), fs.GetTempName())
      fs.CreateFolder(path)
      try {
        func(path)
      }
      finally {
        try {
          fs.DeleteFolder(path)
        }
        catch (ex) {
          print("Failed to delete temp directory.")
        }
      }
    }

    function joinPath() {
      var parts = Array.prototype.slice.call(arguments, 0, arguments.length - 1)
      var last = arguments[arguments.length - 1]
      if (parts.length === 0)
        return last
      else
        return fs.BuildPath(joinPath.apply(null, parts), last)
    }

    function quote(s) {
       return "\"" + s + "\""
    }

    function run(command) {
      print("Running command: " + command)
      var result = shell.Run("cmd /c " + command, 0, true)
      if (result !== 0) throw new Error("Command failed: " + command)
    }

    function print() {
      var args = Array.prototype.slice.call(arguments)
      WScript.Echo(args.join(" "))
    }

    try {
      main()
    }
    catch (ex) {
      throw ex
    }


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
It should behave as it does when launched using "javaw.exe": The busy cursor should appear briefly while the application is launching. The regular mouse cursor should be restored when the application window is displayed.
ACTUAL -
The busy cursor remains for several seconds after the application window has shown up on screen.

---------- BEGIN SOURCE ----------
import javax.swing.*;

import static javax.swing.BorderFactory.createEmptyBorder;
import static javax.swing.WindowConstants.*;

public class HelloSwing {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            var label = new JLabel("Hello Swing!");
            label.setBorder(createEmptyBorder(30, 30, 30, 30));
            var frame = new JFrame("Hello Swing!");
            frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
            frame.add(label);
            frame.pack();
            frame.setVisible(true);
        });
    }
}

---------- END SOURCE ----------

FREQUENCY : always



Comments
A pull request was submitted for review. Branch: master URL: https://git.openjdk.org/jdk/pull/16958 Date: 2023-12-04 20:08:15 +0000
09-11-2024

[jdk17u-fix-request] Approval Request from Martin Should get backported for parity with 17.0.12-oracle. Applies cleanly and tier1-4 have passed.
28-05-2024

A pull request was submitted for review. URL: https://git.openjdk.org/jdk17u-dev/pull/2497 Date: 2024-05-27 16:05:57 +0000
27-05-2024

Windows only, fixes a jpackage msi launcher issue. Should be low risk.
03-04-2024

[jdk21u-fix-request] Approval Request from Dan Lutker Parity with Oracle 21.0.4
04-03-2024

A pull request was submitted for review. URL: https://git.openjdk.org/jdk21u-dev/pull/327 Date: 2024-03-04 17:03:09 +0000
04-03-2024

Changeset: d3df3eb5 Author: Alexey Semenyuk <asemenyuk@openjdk.org> Date: 2023-12-05 18:41:38 +0000 URL: https://git.openjdk.org/jdk/commit/d3df3eb5d7f5537ade917db7a36caba028f94111
05-12-2023

I played around the following jpackage command mentioned earlier: --- build/windows-x64/images/jdk/bin/jpackage.exe --type msi --input build/windows-x64/images/jdk/demo/jfc/J2Ddemo --main-jar J2Ddemo.jar --win-per-user-install --win-shortcut --add-modules java.base,java.desktop --jlink-options --- I don't see the issue with lingering wait cursor in the following cases: 1. run app launcher from a console window (cygwin shell or cmd.exe). This scenario creates a subprocess, but there is a console window attached to app launcher process implicitly. This means JDK-8272328 is not directly causing the issue. 2. set JPACKAGE_DEBUG=true env variable and launch the app from the explorer. In this scenario, app launcher creates a console window to collect debug output - https://github.com/openjdk/jdk/blob/316b78336c9fbf290e6d423f831f9eff1a84bc40/src/jdk.jpackage/windows/native/common/WinApp.cpp#L129 3. set system-wide PATH env variable to contain a path to app's "app" directory to prevent the restart of app launcher (PATH=%PATH%;C:/Users/asemenyu/AppData/Local/J2Ddemo/app). In this scenario, no subprocess is created, no existing console window is associated with the app launcher, and no console is created by app launcher. With the above observations, it looks like not having a GUI window and not running a message loop in app launcher linked with /SUBSYSTEM:WINDOWS option (the case of jpackageapplauncherw.exe launcher used as an app launcher in J2Ddemo) results in the lingering wait cursor. When jpackageapplauncherw.exe directly launches Java GUI app, the GUI window is created by the Java app. When jpackageapplauncherw.exe restarts itself and there is no existing console window or it doesn't create one the parent jpackageapplauncherw.exe process ends up without a single GUI window and more importantly without running a message loop. If the Windows app doesn't run a message loop it looks like the system provides some default behavior with extendeddisplay of a wait cursor. The solution would be to add a message loop to jpackage app launcher in case it needs to restart itself. The message loop must be bound to a valid HWND handle. Windows API supports message-only windows that are invisible, don't accept user input, and are not included in Z-ordering, i.e. completely excluded from GUI (https://learn.microsoft.com/en-us/windows/win32/winmsg/window-features#message-only-windows). The app launcher should create one such window and run a message loop for it. The app laucnher will create a message-only window and run a message loop (https://en.wikipedia.org/wiki/Message_loop_in_Microsoft_Windows) for it in the main thread. It will start an app launcher subprocess from a worker thread. The worker thread will wait for subprocess termination, collect its exit code, pass it to the main app launcher thread, and post WM_QUIT to exit the message loop and exit the app launcher process.
04-12-2023

Additional Information from submitter: ============================ Followup comment on issue JDK-8294699: This is a regression. The bug is reproducible in JDK 17.0.2 but not in 17.0.1. (And also not in JDK 16.) A very likely cause of the regression is commit cd2dbe5f007baf81ae9262c1152917e620970621 (the fix for issue JDK-8272328) which was backported to JDK 17.0.2 in issue JDK-8274441. This commit modified the launcher to run the application in a subprocess, which, as explained in the links referenced in earlier comments, will cause exactly this problem. Works as expected in JDK 17.0.1. Is broken (see issue JDK-8294699 for details) in JDK 17.0.2.
25-09-2023

Additional Information from submitter: ============================ As I mentioned in JDK-8294706, a likely explanation for the issue is that Windows is waiting for the launched process to enter its message loop and call GetMessage to indicate that it has finished launching. See the section on STARTF_FORCEONFEEDBACK here: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfoa See also: https://stackoverflow.com/questions/7522685
06-10-2022

I suspect this is due jli lib is statically linked to the standard launcher and dynamically loaded by jpackage app launcher. Also, jpackage app launcher is statically linked to msvc runtime and is almost 10x times larger than the standard java launcher. Need more evaluation
04-10-2022

I can reproduce the issue using the standard J2Ddemo demo jar. Command to create the msi: --- build/windows-x64/images/jdk/bin/jpackage.exe --type msi --input build/windows-x64/images/jdk/demo/jfc/J2Ddemo --main-jar J2Ddemo.jar --win-per-user-install --win-shortcut --add-modules java.base,java.desktop --jlink-options --- Go to the desktop and launch the app using J2Ddemo shortcut. The "busy" cursor stays for a while. Copy J2Ddemo shortcut (J2Ddemo-java) and replace "C:\Users\asemenyu\AppData\Local\J2Ddemo\J2Ddemo.exe" with "C:\Users\asemenyu\AppData\Local\J2Ddemo\runtime\bin\javaw.exe -jar C:\Users\asemenyu\AppData\Local\J2Ddemo\app\J2Ddemo.jar" command. Launch the app using this shortcut, The "busy" cursor goes away very fast. If I launch the app using J2Ddemo.exe from cmd prompt I don't see the "busy" cursor.
04-10-2022

I am getting following error when executing jpackage with the given reproducer. I have Wix 3.11.2 installed on my system PS C:\test> jpackage --verbose --type msi -i test --main-jar hello.jar --win-per-user-install --win-shortcut --add-modules java.base,java.desktop [09:48:35.758] Running candle.exe [09:48:35.773] Running C:\Program Files (x86)\WiX Toolset v3.11\bin\candle.exe [09:48:36.022] jdk.jpackage.internal.PackagerException: Error: Invalid or unsupported type: [msi] at jdk.jpackage/jdk.jpackage.internal.Arguments.generateBundle(Arguments.java:670) at jdk.jpackage/jdk.jpackage.internal.Arguments.processArguments(Arguments.java:550) at jdk.jpackage/jdk.jpackage.main.Main.execute(Main.java:91) at jdk.jpackage/jdk.jpackage.main.Main.main(Main.java:52) [09:48:36.022] Detected [candle.exe] version project. but version 3.0 is required. [09:48:36.022] Download WiX 3.0 or later from https://wixtoolset.org and add it to the PATH.
03-10-2022