diff --git a/src/java.base/macosx/native/libjava/java_props_macosx.c b/src/java.base/macosx/native/libjava/java_props_macosx.c index 07bc2be9d54d4..6656bf04efcf3 100644 --- a/src/java.base/macosx/native/libjava/java_props_macosx.c +++ b/src/java.base/macosx/native/libjava/java_props_macosx.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ * questions. */ +#include #include #include #include @@ -229,33 +230,50 @@ void setOSNameAndVersion(java_props_t *sprops) { NSString *nsVerStr = NULL; char* osVersionCStr = NULL; NSOperatingSystemVersion osVer = [[NSProcessInfo processInfo] operatingSystemVersion]; - // Copy out the char* if running on version other than 10.16 Mac OS (10.16 == 11.x) - // or explicitly requesting version compatibility - if (!((long)osVer.majorVersion == 10 && (long)osVer.minorVersion >= 16) || - (getenv("SYSTEM_VERSION_COMPAT") != NULL)) { - if (osVer.patchVersion == 0) { // Omit trailing ".0" + // Some macOS versions require special handling. For example, + // when the NSOperatingSystemVersion reports 10.16 as the version + // then it should be treated as 11. Similarly, when it reports 16.0 + // as the version then it should be treated as 26. + // If the SYSTEM_VERSION_COMPAT environment variable (a macOS construct) + // is set to 1, then we don't do any special handling for any versions + // and just literally use the value that NSOperatingSystemVersion reports. + const char* envVal = getenv("SYSTEM_VERSION_COMPAT"); + const bool versionCompatEnabled = envVal != NULL + && strncmp(envVal, "1", 1) == 0; + const bool requiresSpecialHandling = + ((long) osVer.majorVersion == 10 && (long) osVer.minorVersion >= 16) + || ((long) osVer.majorVersion == 16 && (long) osVer.minorVersion >= 0); + if (!requiresSpecialHandling || versionCompatEnabled) { + // no special handling - just use the version reported + // by NSOperatingSystemVersion + if (osVer.patchVersion == 0) { + // Omit trailing ".0" nsVerStr = [NSString stringWithFormat:@"%ld.%ld", (long)osVer.majorVersion, (long)osVer.minorVersion]; } else { nsVerStr = [NSString stringWithFormat:@"%ld.%ld.%ld", - (long)osVer.majorVersion, (long)osVer.minorVersion, (long)osVer.patchVersion]; + (long)osVer.majorVersion, (long)osVer.minorVersion, + (long)osVer.patchVersion]; } } else { - // Version 10.16, without explicit env setting of SYSTEM_VERSION_COMPAT - // AKA 11+ Read the *real* ProductVersion from the hidden link to avoid SYSTEM_VERSION_COMPAT - // If not found, fallback below to the SystemVersion.plist - NSDictionary *version = [NSDictionary dictionaryWithContentsOfFile : - @"/System/Library/CoreServices/.SystemVersionPlatform.plist"]; + // Requires special handling. We ignore the version reported + // by the NSOperatingSystemVersion API and instead read the + // *real* ProductVersion from + // /System/Library/CoreServices/.SystemVersionPlatform.plist. + // If not found there, then as a last resort we fallback to + // /System/Library/CoreServices/SystemVersion.plist + NSDictionary *version = [NSDictionary dictionaryWithContentsOfFile: + @"/System/Library/CoreServices/.SystemVersionPlatform.plist"]; if (version != NULL) { - nsVerStr = [version objectForKey : @"ProductVersion"]; + nsVerStr = [version objectForKey: @"ProductVersion"]; } } - // Fallback to reading the SystemVersion.plist + // Last resort - fallback to reading the SystemVersion.plist if (nsVerStr == NULL) { - NSDictionary *version = [NSDictionary dictionaryWithContentsOfFile : - @"/System/Library/CoreServices/SystemVersion.plist"]; + NSDictionary *version = [NSDictionary dictionaryWithContentsOfFile: + @"/System/Library/CoreServices/SystemVersion.plist"]; if (version != NULL) { - nsVerStr = [version objectForKey : @"ProductVersion"]; + nsVerStr = [version objectForKey: @"ProductVersion"]; } } diff --git a/test/jdk/java/lang/System/OsVersionTest.java b/test/jdk/java/lang/System/OsVersionTest.java index d35f71453b12f..9a1cb976db8f4 100644 --- a/test/jdk/java/lang/System/OsVersionTest.java +++ b/test/jdk/java/lang/System/OsVersionTest.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2015, 2021 SAP SE. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,56 +29,65 @@ /* * @test - * @bug 8132374 + * @bug 8132374 8359830 * @summary Check that the value of the os.version property is equal * to the value of the corresponding OS provided tools. * @library /test/lib + * @build jtreg.SkippedException * @run main OsVersionTest * @author Volker Simonis */ public class OsVersionTest { - public static void main(String args[]) throws Throwable { + public static void main(String[] args) throws Throwable { final String osVersion = System.getProperty("os.version"); if (osVersion == null) { - throw new Error("Cant query 'os.version' property!"); + throw new Error("Missing value for os.version system property"); } if (Platform.isLinux()) { OutputAnalyzer output = ProcessTools.executeProcess("uname", "-r"); + output.shouldHaveExitValue(0); if (!osVersion.equals(output.getOutput().trim())) { throw new Error(osVersion + " != " + output.getOutput().trim()); } - } - else if (Platform.isOSX()) { - OutputAnalyzer output = ProcessTools.executeProcess("sw_vers", "-productVersion"); - String swVersOutput = output.getOutput().trim(); - if (!osVersion.equals(swVersOutput)) { - // This section can be removed if minimum build SDK is xcode 12+ - if (swVersOutput.startsWith(osVersion)) { - throw new SkippedException("MacOS version only matches in parts, this is expected when " + - "JDK was built with Xcode < 12 and MacOS version patch is > 0"); - } - throw new Error(osVersion + " != " + swVersOutput); - } - } - else if (Platform.isAix()) { + } else if (Platform.isOSX()) { + testMacOS(osVersion); + } else if (Platform.isAix()) { OutputAnalyzer output1 = ProcessTools.executeProcess("uname", "-v"); + output1.shouldHaveExitValue(0); OutputAnalyzer output2 = ProcessTools.executeProcess("uname", "-r"); + output2.shouldHaveExitValue(0); String version = output1.getOutput().trim() + "." + output2.getOutput().trim(); if (!osVersion.equals(version)) { throw new Error(osVersion + " != " + version); } - } - else if (Platform.isWindows()) { + } else if (Platform.isWindows()) { OutputAnalyzer output = ProcessTools.executeProcess("cmd", "/c", "ver"); + output.shouldHaveExitValue(0); String version = output.firstMatch(".+\\[Version ([0-9.]+)\\]", 1); if (version == null || !version.startsWith(osVersion)) { throw new Error(osVersion + " != " + version); } - } - else { - System.out.println("This test is currently not supported on " + + } else { + throw new jtreg.SkippedException("This test is currently not supported on " + Platform.getOsName()); } } + + private static void testMacOS(final String sysPropOsVersion) throws Exception { + final ProcessBuilder pb = new ProcessBuilder("sw_vers", "-productVersion"); + // if the test was launched with SYSTEM_VERSION_COMPAT environment variable set, + // then propagate that to the sw_vers too + final String versionCompat = System.getenv().get("SYSTEM_VERSION_COMPAT"); + if (versionCompat != null) { + pb.environment().put("SYSTEM_VERSION_COMPAT", versionCompat); + } + final OutputAnalyzer output = ProcessTools.executeCommand(pb); + output.shouldHaveExitValue(0); + final String swVersOutput = output.getOutput().trim(); + if (!sysPropOsVersion.equals(swVersOutput)) { + throw new Error("sw_vers reports macOS version: " + swVersOutput + + " but os.version system property reports version: " + sysPropOsVersion); + } + } }