Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8280131

jcmd reports "Module jdk.jfr not found." when "jdk.management.jfr" is missing

    XMLWordPrintable

Details

    • jfr
    • b21
    • generic
    • generic

    Description

      ADDITIONAL SYSTEM INFORMATION :
      openjdk version "17.0.1" 2021-10-19
      OpenJDK Runtime Environment (build 17.0.1+12-39)
      OpenJDK 64-Bit Server VM (build 17.0.1+12-39, mixed mode, sharing)

      openjdk version "18-ea" 2022-03-15
      OpenJDK Runtime Environment (build 18-ea+25-1670)
      OpenJDK 64-Bit Server VM (build 18-ea+25-1670, mixed mode, sharing)

      A DESCRIPTION OF THE PROBLEM :
      Using jcmd to access Java Flight Recorder on a process running a jlink:ed runtime containing module "jdk.jfr", but missing module "jdk.management.jfr",
      jcmd reports "Module jdk.jfr not found."

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      The attached Java 17 source code first creates a module and two runtimes (one with and one without "jdk.management.jfr"),
      then launches the module with the two runtimes,
      then runs "jcmd <pid> JFR.check" and prints the output.

      java JcmdMissingModule.java

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      "Module jdk.management.jfr not found."
      ACTUAL -
      "Module jdk.jfr not found."

      ---------- BEGIN SOURCE ----------
      import java.io.ByteArrayOutputStream;
      import java.io.File;
      import java.io.InputStream;
      import java.nio.file.Files;
      import java.nio.file.Path;
      import java.util.Collections;
      import java.util.spi.ToolProvider;

      /**
       * jcmd prints message "Module jdk.jfr not found.",
       * when using slimmed jlink:ed runtime,
       * containing module "jdk.jfr".
       *
       * Adding "jdk.management.jfr" to the jlink:ed runtime,
       * makes jcmd happy.
       *
       * This java program creates source code of a module which just sleeps,
       * compiles that,
       * makes two jlink:ed runtimes (one without and one with module "jdk.management.jfr"),
       * launches the sleeping module with the both runtimes,
       * and invokes "jcmd <pid> JFR.check" on theses processes,
       * and prints their output.
       */
      class JcmdMissingModule {
          static ToolProvider javac = ToolProvider.findFirst("javac").orElseThrow(() -> new RuntimeException("No javac"));
          static ToolProvider jlink = ToolProvider.findFirst("jlink").orElseThrow(() -> new RuntimeException("No jlink"));
                                                                                                                                     
          static String module = "sleep";
          static String moduleInfo = "module %s {}".formatted(module);
          static String Main = """
              package example;
              class Main {
                  public static void main(String[] args) throws InterruptedException {
                      Thread.sleep(Long.MAX_VALUE);
                  }
              }
              """;
                                                                                                                                     
          public static void main(String[] args) throws Exception {
              Path out = Path.of("out");
              Path src = out.resolve("src");
              Path classes = out.resolve("classes");
                                                                     
              del(out);
                                                                                                                                     
              Files.createDirectories(src.resolve(module).resolve("example"));
              Files.write(src.resolve(module).resolve("module-info.java"), moduleInfo.getBytes());
              Files.write(src.resolve(module).resolve("example").resolve("Main.java"), Main.getBytes());
                                                                     
              // Compile module
              javac.run(System.out, System.err,
                      "--module-source-path", src.toString(),
                      "--module", module,
                      "-d", classes.toString());
                                                                     
              Path javaHome = Path.of(System.getProperty("java.home"));
              Path jmods = javaHome.resolve("jmods");
              Path jcmd = javaHome.resolve("bin").resolve("jcmd");
                                                                     
              String reproducerModules = String.join(",", module, "jdk.jfr", "jdk.management");
              String workaroundModules = String.join(",", module, "jdk.jfr", "jdk.management", "jdk.management.jfr");
                                                                                                                                     
              String modulePath = String.join(File.pathSeparator, jmods.toString(), classes.toString());
              String reproducer = out.resolve("reproducer").toString();
              String workaround = out.resolve("workaround").toString();
                                                                     
              // Create runtimes with limited set of modules
              jlink(reproducerModules, modulePath, reproducer);
              jlink(workaroundModules, modulePath, workaround);
                                                                     
              String reproducerJava = Path.of(reproducer, "bin", "java").toString();
              String workaroundJava = Path.of(workaround, "bin", "java").toString();
                                                                     
              String moduleWithMain = module + "/example.Main";
                                                                     
              // Start processes which just sleep
              long reproducerPid = run(reproducerJava, "--module", moduleWithMain).pid();
              long workaroundPid = run(workaroundJava, "--module", moduleWithMain).pid();

              // Run JFR.check on the processes
              String reproducerJcmd = runAndReadOutput(jcmd.toString(), String.valueOf(reproducerPid), "JFR.check");
              String workaroundJcmd = runAndReadOutput(jcmd.toString(), String.valueOf(workaroundPid), "JFR.check");
                                                                     
              // List modules
              String reproducerListModules = runAndReadOutput(reproducerJava, "--list-modules");
              String workaroundListModules = runAndReadOutput(workaroundJava, "--list-modules");
                                                                     
              System.out.println("""
                  jcmd:
                  %s
                  --list-modules:
                  %s
                                                                     
                  jcmd:
                  %s
                  --list-modules:
                  %s
                  """.formatted(reproducerJcmd, reproducerListModules, workaroundJcmd, workaroundListModules));
         }
                                                                                                                                     
          static Process run(String... cmd) throws Exception {
              Process process = new ProcessBuilder(cmd)
                  .redirectErrorStream(true)
                  .start();
              Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { process.destroy(); } } );
              return process;
          }
                                                                     
          static String runAndReadOutput(String... cmd) throws Exception {
              Process process = run(cmd);
              process.waitFor();
              String output = readOutput(process.getInputStream());
              return output;
          }
                                                                     
          static String readOutput(InputStream is) throws Exception {
              var baos = new ByteArrayOutputStream();
              is.transferTo(baos);
              return baos.toString();
          }
                                                                     
          static void jlink(String modules, String modulePath, String output) {
              jlink.run(System.out, System.err,
                      "--add-modules", modules,
                      "--module-path", modulePath,
                      "--output", output
                      );
          }
                                                                     
          static void del(Path dir) {
              if (dir.toFile().exists()) {
                  try (var files = Files.walk(dir)) {
                      files.sorted(Collections.reverseOrder()).map(Path::toFile).forEach(f -> f.delete());
                  } catch (Exception e) {}
              }
          }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Adding "jdk.management.jfr" to the jlink:ed runtime

      FREQUENCY : always


      Attachments

        Issue Links

          Activity

            People

              egahlin Erik Gahlin
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              8 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: