RFR: 8351073: [macos] jpackage produces invalid Java runtime DMG bundles [v2]

Alexander Matveev almatvee at openjdk.org
Thu Jul 10 21:48:52 UTC 2025


On Tue, 8 Jul 2025 00:15:29 GMT, Alexey Semenyuk <asemenyuk at openjdk.org> wrote:

>> Alexander Matveev has updated the pull request with a new target base due to a merge or a rebase. The incremental webrev excludes the unrelated changes brought in by the merge/rebase. The pull request contains two additional commits since the last revision:
>> 
>>  - Merge remote-tracking branch 'upstream/master' into JDK-8351073-2
>>  - 8351073: [macos] jpackage produces invalid Java runtime DMG bundles
>
> src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java line 184:
> 
>> 182:     }
>> 183: 
>> 184:     public String validatedBundleIdentifier() throws ConfigException {
> 
> This method is private on purpose. It should not be used outside of the MacApplicationBuilder class. If you need to get the valid bundle identifier, create MacApplication instance and call `MacApplication.bundleIdentifier()` on it.

I need it inside `createMacApplication()` before `MacApplication` instance is created.

> src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java line 80:
> 
>> 78:             if (!isRuntimeImageJDKBundle(runtimeImage)
>> 79:                     && !isRuntimeImageJDKImage(runtimeImage)) {
>> 80:                 throw new ConfigException(
> 
> 1. Can be simplified:
> 
> throw new ConfigException(
>                     I18N.format("message.runtime-image-invalid", runtimeImage),
>                     I18N.getString("message.runtime-image-invalid.advice"));
> 
> 
> 2. This validation should be a part of `MacPackageBuilder.create()`.

1 and 2 fixed.

> src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java line 120:
> 
>> 118:             return IOUtils.exists(jli);
>> 119:         } catch (IOException | NoSuchElementException ex) {
>> 120:             Log.verbose(ex);
> 
> So if jpackage doesn't know if the given path is a JDK image or a JDK bundle, it will proceed with packaging anyway. This doesn't look right. In general, most, if not all, of the existing constructions like:
> 
> } catch (Exception ex) {
>     Log.verbose(ex);
>     ...
> }
> 
> are wrong. Let's not add new ones.

Fixed.

> src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPackagingPipeline.java line 313:
> 
>> 311:     }
>> 312: 
>> 313:     private static void writeRuntimeBundleInfoPlist(MacApplication app, BuildEnv env, Path runtimeRootDirectory) throws IOException {
> 
> This function is almost a duplicate of writeRuntimeInfoPlist(). They can be merged together with branching:
> 
> if (app.asApplicationLayout().isPresent()) {
>     // This is application bundle
> } else {
>     // This is runtime bundle
> }

Fixed

> src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackage.java line 38:
> 
>> 36:     default AppImageLayout appImageLayout() {
>> 37:         if (isRuntimeInstaller()) {
>> 38:             return RuntimeLayout.DEFAULT;
> 
> Why is this change? It looks wrong. The layout of the output bundle should have the "Contents" folder. This is how it was before the change.

`RUNTIME_PACKAGE_LAYOUT` points to "Contents/Home". Bundle is "Contents/Home", "Contents/MacOS" and "Contents/Info.plist". So we need root of bundle and not "Home". Maybe I misunderstanding something.

> src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacPackage.java line 76:
> 
>> 74:             return !Files.exists(p);
>> 75:         }
>> 76:     }
> 
> Default interface methods should operate on values returned by other interface methods. These new functions involve filesystem operations. They probably don't belong to the interface.

Moved to `MacPackagingPipeline`.

> src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/RuntimeBundle-Info.plist.template line 1:
> 
>> 1: <?xml version="1.0" encoding="UTF-8"?>
> 
> What is the origin of this file?

Based on JDK Info plist template we using. You can find original file here https://github.com/openjdk/jdk/blob/master/make/data/bundle/JDK-Info.plist.template.

> src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/RuntimeBundle-Info.plist.template line 6:
> 
>> 4: <dict>
>> 5:         <key>CFBundleDevelopmentRegion</key>
>> 6:         <string>English</string>
> 
> I'm surprised there is no standard way to override this default value. Is it not important?

https://developer.apple.com/documentation/bundleresources/information-property-list/cfbundledevelopmentregion?language=objc

By default it will be `en-US`. Not sure why JDK Info.plist has `English`, since it is not a documented value. Also all jpackage Info plist template files also have `English`. I think we need to file a separate bug and change it to `en-US` or remove it. I think remove it is better, since no need to set it to default value.

Not sure if it is important for `runtime bundles`, but for `application bundles` it might be important in case if application does not have English localization. For example application is only in German language, then this value should be set to German language ID. I think it might make sense to file a bug to investigate if we want to provide CLI option to specify value for `CFBundleDevelopmentRegion` similar to `--mac-app-category`. Any suggestions?

> src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java line 101:
> 
>> 99:      */
>> 100:     Optional<Path> runtimeImage();
>> 101: 
> 
> What is "the source directory of this application"?
> Why is the method that returns a path to the source directory called `runtimeImage()`?

Copy-paste. Forgot to update description. I fixed it. `runtimeImageDir` is a value of `--runtime-image` in case of runtime installer.

> test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java line 974:
> 
>> 972:             // on macOS. On macOS runtime image will be signed ad-hoc or with
>> 973:             // real certificate when creating runtime installers.
>> 974:             return !(cmd.isRuntime() && TKit.isOSX());
> 
> I guess the directory referenced from the `--runtime-image` option will not be signed if it is a JDK image, not a JDK bundle. So, this switch turns off verification in cases when it should be done.
> 
> My interpretation of the PR description is that if the `-runtime-image` option references a JDK bundle, its contents will be copied, and the copy will be signed optionally. This makes this switch redundant.

Yes, it is no longer needed. I removed it.

> test/jdk/tools/jpackage/macosx/SigningRuntimeImagePackageTest.java line 65:
> 
>> 63:  * always allowed access to this keychain for user which runs test.
>> 64:  * note:
>> 65:  * "jpackage.openjdk.java.net" can be over-ridden by systerm property
> 
> systerm -> system

Fixed.

> test/jdk/tools/jpackage/macosx/SigningRuntimeImagePackageTest.java line 134:
> 
>> 132:     }
>> 133: 
>> 134:     private static Path getRuntimeImagePath(boolean useJDKBundle,
> 
> The name of the function is misleading. It doesn't get the runtime image. It creates it.
> 
> It returns a path to a JDK bundle or a JDK image depending on its arguments. So the "RuntimeImagePath" part of its name is also misleading.

Improved.

> test/jdk/tools/jpackage/macosx/SigningRuntimeImagePackageTest.java line 180:
> 
>> 178:             ex.execute();
>> 179: 
>> 180:             JPackageCommand dummyCMD = new JPackageCommand();
> 
> Why do you need a `dummyCMD`? You can configure a normal JPackageCommand command:
> 
> var cmd = new JPackageCommand().useToolProvider(true).dumpOutput(true).addArguments(...);

Fixed.

> test/jdk/tools/jpackage/macosx/SigningRuntimeImagePackageTest.java line 188:
> 
>> 186: 
>> 187:             MacHelper.withExplodedDmg(dummyCMD, dmgImage -> {
>> 188:                 if (dmgImage.endsWith(dummyCMD.name() + ".jdk")) {
> 
> Can this test ever return `false`?

Yes. `withExplodedDmg` is called for all content in DMG which will include link to `JavaVirtualMachines`. We have same checks for `.app` as well for exact same reason.

> test/jdk/tools/jpackage/macosx/SigningRuntimeImagePackageTest.java line 189:
> 
>> 187:             MacHelper.withExplodedDmg(dummyCMD, dmgImage -> {
>> 188:                 if (dmgImage.endsWith(dummyCMD.name() + ".jdk")) {
>> 189:                     Executor.of("cp", "-R")
> 
> Why noit use `FileUtils.copyRecursive()`?

All our other code uses `cp` command to copy mounted DMG. I tried `FileUtils.copyRecursive()`, but test failed due to signing. I think `FileUtils.copyRecursive()` breaks file permissions or something. Will keep `cp` for consistency.

> test/jdk/tools/jpackage/macosx/SigningRuntimeImagePackageTest.java line 222:
> 
>> 220:                             SigningBase.CertIndex JDKBundleCert,
>> 221:                             SigningBase.CertIndex signCert) throws Exception {
>> 222:         final int JDKBundleCertIndex = JDKBundleCert.value();
> 
> `JDKBundleCertIndex` -> `jdkBundleCertIndex`?

Fixed.

> test/jdk/tools/jpackage/macosx/SigningRuntimeImagePackageTest.java line 231:
> 
>> 229: 
>> 230:         new PackageTest()
>> 231:                 .forTypes(PackageType.MAC)
> 
> `.forTypes(PackageType.MAC)` is redundant. The test will only be executed on macOS

Fixed.

> test/jdk/tools/jpackage/share/ErrorTest.java line 98:
> 
>> 96:             // Missing "Contents/MacOS/libjli.dylib"
>> 97:             try {
>> 98:                 final Path runtimePath = TKit.createTempDirectory("invalidJDKBundle");
> 
> The name "invalid-jdk-bundle" fits better in dash-case naming scheme for path names in jpackage tests.

Fixed.

> test/jdk/tools/jpackage/share/ErrorTest.java line 637:
> 
>> 635:                         .addArgs("--runtime-image", Token.INVALID_MAC_JDK_BUNDLE.token())
>> 636:                         .error("message.runtime-image-invalid", JPackageCommand.cannedArgument(cmd -> {
>> 637:                             return Path.of(cmd.getArgumentValue("--runtime-image")).toAbsolutePath();
> 
> Why do we need an absolute path in error messages? Wouldn't it make more sense to have the value of `--runtime-image` parameter as is in error messages?

Not sure why. Fixed.

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/26173#discussion_r2193668918
PR Review Comment: https://git.openjdk.org/jdk/pull/26173#discussion_r2193679404
PR Review Comment: https://git.openjdk.org/jdk/pull/26173#discussion_r2193704037
PR Review Comment: https://git.openjdk.org/jdk/pull/26173#discussion_r2193710393
PR Review Comment: https://git.openjdk.org/jdk/pull/26173#discussion_r2193718285
PR Review Comment: https://git.openjdk.org/jdk/pull/26173#discussion_r2196225026
PR Review Comment: https://git.openjdk.org/jdk/pull/26173#discussion_r2196230170
PR Review Comment: https://git.openjdk.org/jdk/pull/26173#discussion_r2196251812
PR Review Comment: https://git.openjdk.org/jdk/pull/26173#discussion_r2196314256
PR Review Comment: https://git.openjdk.org/jdk/pull/26173#discussion_r2196395258
PR Review Comment: https://git.openjdk.org/jdk/pull/26173#discussion_r2196396676
PR Review Comment: https://git.openjdk.org/jdk/pull/26173#discussion_r2196401655
PR Review Comment: https://git.openjdk.org/jdk/pull/26173#discussion_r2196404744
PR Review Comment: https://git.openjdk.org/jdk/pull/26173#discussion_r2196406257
PR Review Comment: https://git.openjdk.org/jdk/pull/26173#discussion_r2196408886
PR Review Comment: https://git.openjdk.org/jdk/pull/26173#discussion_r2196410205
PR Review Comment: https://git.openjdk.org/jdk/pull/26173#discussion_r2196411953
PR Review Comment: https://git.openjdk.org/jdk/pull/26173#discussion_r2196413148
PR Review Comment: https://git.openjdk.org/jdk/pull/26173#discussion_r2198799393


More information about the core-libs-dev mailing list