diff --git a/CHANGELOG.md b/CHANGELOG.md index fda3fec2..b1714e11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,11 @@ FlatLaf Change Log - `FlatSVGIcon` color filters now support linear gradients. (PR #817) - Added support for `JSplitPane.expandableSide` client property to `FlatSplitPane`. +- Native libraries: Added API version check to test whether native library + matches the JAR (bad builds could e.g. ship a newer JAR with an older + incompatible native library) and to test whether native methods can be invoked + (some security software allows loading native library but blocks method + invocation). ## 3.4 diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLibrary.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLibrary.java index 5ffc2a6a..3c169c28 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLibrary.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLibrary.java @@ -37,16 +37,18 @@ class FlatNativeLibrary private static boolean initialized; private static NativeLibrary nativeLibrary; + private native static int getApiVersion(); + /** * Loads native library (if available) and returns whether loaded successfully. * Returns {@code false} if no native library is available. */ - static synchronized boolean isLoaded() { - initialize(); + static synchronized boolean isLoaded( int apiVersion ) { + initialize( apiVersion ); return (nativeLibrary != null) ? nativeLibrary.isLoaded() : false; } - private static void initialize() { + private static void initialize( int apiVersion ) { if( initialized ) return; initialized = true; @@ -104,7 +106,26 @@ class FlatNativeLibrary return; // no native library available for current OS or CPU architecture // load native library - nativeLibrary = createNativeLibrary( classifier, ext ); + NativeLibrary nativeLibrary = createNativeLibrary( classifier, ext ); + if( !nativeLibrary.isLoaded() ) + return; + + // check API version (and check whether library works) + try { + int actualApiVersion = getApiVersion(); + if( actualApiVersion != apiVersion ) { + LoggingFacade.INSTANCE.logSevere( "FlatLaf: Wrong API version in native library (expected " + + apiVersion + ", actual " + actualApiVersion + "). Ignoring native library.", null ); + return; + } + } catch( Throwable ex ) { + // could be a UnsatisfiedLinkError in case that loading native library + // from temp directory was blocked by some OS security mechanism + LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to get API version of native library. Ignoring native library.", ex ); + return; + } + + FlatNativeLibrary.nativeLibrary = nativeLibrary; } private static NativeLibrary createNativeLibrary( String classifier, String ext ) { @@ -118,9 +139,9 @@ class FlatNativeLibrary if( library.isLoaded() ) return library; - LoggingFacade.INSTANCE.logSevere( "Did not find library '" + System.mapLibraryName( libraryName ) - + "' in java.library.path '" + System.getProperty( "java.library.path" ) - + "', using extracted library instead", null ); + LoggingFacade.INSTANCE.logSevere( "FlatLaf: Native library '" + System.mapLibraryName( libraryName ) + + "' not found in java.library.path '" + System.getProperty( "java.library.path" ) + + "'. Using extracted native library instead.", null ); } else { // try standard library naming scheme // (same as in flatlaf.jar in package 'com/formdev/flatlaf/natives') @@ -139,11 +160,11 @@ class FlatNativeLibrary return new NativeLibrary( libraryFile2, true ); } - LoggingFacade.INSTANCE.logSevere( "Did not find library '" + LoggingFacade.INSTANCE.logSevere( "FlatLaf: Native library '" + libraryFile.getName() + (libraryName2 != null ? ("' or '" + libraryName2) : "") - + "' in '" + libraryFile.getParentFile().getAbsolutePath() - + "', using extracted library instead", null ); + + "' not found in '" + libraryFile.getParentFile().getAbsolutePath() + + "'. Using extracted native library instead.", null ); } } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLinuxLibrary.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLinuxLibrary.java index b60922ec..8f0ee8b3 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLinuxLibrary.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLinuxLibrary.java @@ -35,6 +35,8 @@ import com.formdev.flatlaf.util.SystemInfo; */ class FlatNativeLinuxLibrary { + private static int API_VERSION_LINUX = 3001; + /** * Checks whether native library is loaded/available. *

@@ -42,7 +44,7 @@ class FlatNativeLinuxLibrary * method of this class. Otherwise, the native library may not be loaded. */ static boolean isLoaded() { - return SystemInfo.isLinux && FlatNativeLibrary.isLoaded(); + return SystemInfo.isLinux && FlatNativeLibrary.isLoaded( API_VERSION_LINUX ); } // direction for _NET_WM_MOVERESIZE message diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeMacLibrary.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeMacLibrary.java index 0ef75f50..7d08376a 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeMacLibrary.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeMacLibrary.java @@ -44,6 +44,8 @@ import com.formdev.flatlaf.util.SystemInfo; */ public class FlatNativeMacLibrary { + private static int API_VERSION_MACOS = 2001; + /** * Checks whether native library is loaded/available. *

@@ -51,7 +53,7 @@ public class FlatNativeMacLibrary * method of this class. Otherwise, the native library may not be loaded. */ public static boolean isLoaded() { - return SystemInfo.isMacOS && FlatNativeLibrary.isLoaded(); + return SystemInfo.isMacOS && FlatNativeLibrary.isLoaded( API_VERSION_MACOS ); } public native static boolean setWindowRoundedBorder( Window window, float radius, float borderWidth, int borderColor ); diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeWindowsLibrary.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeWindowsLibrary.java index 669271e6..8a4ce3cf 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeWindowsLibrary.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeWindowsLibrary.java @@ -30,6 +30,8 @@ import com.formdev.flatlaf.util.SystemInfo; */ public class FlatNativeWindowsLibrary { + private static int API_VERSION_WINDOWS = 1001; + private static long osBuildNumber = Long.MIN_VALUE; /** @@ -39,7 +41,7 @@ public class FlatNativeWindowsLibrary * method of this class. Otherwise, the native library may not be loaded. */ public static boolean isLoaded() { - return SystemInfo.isWindows && FlatNativeLibrary.isLoaded(); + return SystemInfo.isWindows && FlatNativeLibrary.isLoaded( API_VERSION_WINDOWS ); } /** diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatWindowsNativeWindowBorder.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatWindowsNativeWindowBorder.java index dda40c28..a4014001 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatWindowsNativeWindowBorder.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatWindowsNativeWindowBorder.java @@ -89,7 +89,7 @@ class FlatWindowsNativeWindowBorder return null; // check whether native library was successfully loaded - if( !FlatNativeLibrary.isLoaded() ) + if( !FlatNativeWindowsLibrary.isLoaded() ) return null; // create new instance diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/flatlaf-windows-arm64.dll b/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/flatlaf-windows-arm64.dll index b9c9aaa8..ea7d69bd 100644 Binary files a/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/flatlaf-windows-arm64.dll and b/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/flatlaf-windows-arm64.dll differ diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/flatlaf-windows-x86.dll b/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/flatlaf-windows-x86.dll index e2b447e2..37c592cd 100644 Binary files a/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/flatlaf-windows-x86.dll and b/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/flatlaf-windows-x86.dll differ diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/flatlaf-windows-x86_64.dll b/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/flatlaf-windows-x86_64.dll index 1afddbf9..d3ccf1b6 100644 Binary files a/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/flatlaf-windows-x86_64.dll and b/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/flatlaf-windows-x86_64.dll differ diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/libflatlaf-linux-x86_64.so b/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/libflatlaf-linux-x86_64.so index 9942ff5c..3d0ddc5a 100644 Binary files a/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/libflatlaf-linux-x86_64.so and b/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/libflatlaf-linux-x86_64.so differ diff --git a/flatlaf-natives/flatlaf-natives-linux/build.gradle.kts b/flatlaf-natives/flatlaf-natives-linux/build.gradle.kts index 4fcb9838..a81d6643 100644 --- a/flatlaf-natives/flatlaf-natives-linux/build.gradle.kts +++ b/flatlaf-natives/flatlaf-natives-linux/build.gradle.kts @@ -21,7 +21,10 @@ plugins { } flatlafJniHeaders { - headers = listOf( "com_formdev_flatlaf_ui_FlatNativeLinuxLibrary.h" ) + headers = listOf( + "com_formdev_flatlaf_ui_FlatNativeLibrary.h", + "com_formdev_flatlaf_ui_FlatNativeLinuxLibrary.h" + ) } library { diff --git a/flatlaf-natives/flatlaf-natives-linux/src/main/cpp/ApiVersion.cpp b/flatlaf-natives/flatlaf-natives-linux/src/main/cpp/ApiVersion.cpp new file mode 100644 index 00000000..02454fb3 --- /dev/null +++ b/flatlaf-natives/flatlaf-natives-linux/src/main/cpp/ApiVersion.cpp @@ -0,0 +1,37 @@ +/* + * Copyright 2024 FormDev Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "com_formdev_flatlaf_ui_FlatNativeLibrary.h" + +/** + * @author Karl Tauber + */ + + +// increase this version if changing API or functionality of native library +// also update version in Java class com.formdev.flatlaf.ui.FlatNativeLinuxLibrary +#define API_VERSION_LINUX 3001 + + +//---- JNI methods ------------------------------------------------------------ + +extern "C" +JNIEXPORT jint JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLibrary_getApiVersion + ( JNIEnv* env, jclass cls ) +{ + return API_VERSION_LINUX; +} diff --git a/flatlaf-natives/flatlaf-natives-linux/src/main/headers/com_formdev_flatlaf_ui_FlatNativeLibrary.h b/flatlaf-natives/flatlaf-natives-linux/src/main/headers/com_formdev_flatlaf_ui_FlatNativeLibrary.h new file mode 100644 index 00000000..35ba342b --- /dev/null +++ b/flatlaf-natives/flatlaf-natives-linux/src/main/headers/com_formdev_flatlaf_ui_FlatNativeLibrary.h @@ -0,0 +1,21 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class com_formdev_flatlaf_ui_FlatNativeLibrary */ + +#ifndef _Included_com_formdev_flatlaf_ui_FlatNativeLibrary +#define _Included_com_formdev_flatlaf_ui_FlatNativeLibrary +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: com_formdev_flatlaf_ui_FlatNativeLibrary + * Method: getApiVersion + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLibrary_getApiVersion + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/flatlaf-natives/flatlaf-natives-macos/build.gradle.kts b/flatlaf-natives/flatlaf-natives-macos/build.gradle.kts index cf650d74..5b542d3a 100644 --- a/flatlaf-natives/flatlaf-natives-macos/build.gradle.kts +++ b/flatlaf-natives/flatlaf-natives-macos/build.gradle.kts @@ -26,7 +26,10 @@ plugins { } flatlafJniHeaders { - headers = listOf( "com_formdev_flatlaf_ui_FlatNativeMacLibrary.h" ) + headers = listOf( + "com_formdev_flatlaf_ui_FlatNativeLibrary.h", + "com_formdev_flatlaf_ui_FlatNativeMacLibrary.h" + ) } library { diff --git a/flatlaf-natives/flatlaf-natives-macos/src/main/headers/com_formdev_flatlaf_ui_FlatNativeLibrary.h b/flatlaf-natives/flatlaf-natives-macos/src/main/headers/com_formdev_flatlaf_ui_FlatNativeLibrary.h new file mode 100644 index 00000000..35ba342b --- /dev/null +++ b/flatlaf-natives/flatlaf-natives-macos/src/main/headers/com_formdev_flatlaf_ui_FlatNativeLibrary.h @@ -0,0 +1,21 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class com_formdev_flatlaf_ui_FlatNativeLibrary */ + +#ifndef _Included_com_formdev_flatlaf_ui_FlatNativeLibrary +#define _Included_com_formdev_flatlaf_ui_FlatNativeLibrary +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: com_formdev_flatlaf_ui_FlatNativeLibrary + * Method: getApiVersion + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLibrary_getApiVersion + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/flatlaf-natives/flatlaf-natives-macos/src/main/objcpp/ApiVersion.mm b/flatlaf-natives/flatlaf-natives-macos/src/main/objcpp/ApiVersion.mm new file mode 100644 index 00000000..ef0ff0f3 --- /dev/null +++ b/flatlaf-natives/flatlaf-natives-macos/src/main/objcpp/ApiVersion.mm @@ -0,0 +1,37 @@ +/* + * Copyright 2024 FormDev Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "com_formdev_flatlaf_ui_FlatNativeLibrary.h" + +/** + * @author Karl Tauber + */ + + +// increase this version if changing API or functionality of native library +// also update version in Java class com.formdev.flatlaf.ui.FlatNativeMacLibrary +#define API_VERSION_MACOS 2001 + + +//---- JNI methods ------------------------------------------------------------ + +extern "C" +JNIEXPORT jint JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLibrary_getApiVersion + ( JNIEnv* env, jclass cls ) +{ + return API_VERSION_MACOS; +} diff --git a/flatlaf-natives/flatlaf-natives-windows/build.gradle.kts b/flatlaf-natives/flatlaf-natives-windows/build.gradle.kts index b7e8ff3e..e297703e 100644 --- a/flatlaf-natives/flatlaf-natives-windows/build.gradle.kts +++ b/flatlaf-natives/flatlaf-natives-windows/build.gradle.kts @@ -22,6 +22,7 @@ plugins { flatlafJniHeaders { headers = listOf( + "com_formdev_flatlaf_ui_FlatNativeLibrary.h", "com_formdev_flatlaf_ui_FlatNativeWindowsLibrary.h", "com_formdev_flatlaf_ui_FlatWindowsNativeWindowBorder.h", "com_formdev_flatlaf_ui_FlatWindowsNativeWindowBorder_WndProc.h" diff --git a/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/ApiVersion.cpp b/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/ApiVersion.cpp new file mode 100644 index 00000000..a32f0d6d --- /dev/null +++ b/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/ApiVersion.cpp @@ -0,0 +1,37 @@ +/* + * Copyright 2024 FormDev Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "com_formdev_flatlaf_ui_FlatNativeLibrary.h" + +/** + * @author Karl Tauber + */ + + +// increase this version if changing API or functionality of native library +// also update version in Java class com.formdev.flatlaf.ui.FlatNativeWindowsLibrary +#define API_VERSION_WINDOWS 1001 + + +//---- JNI methods ------------------------------------------------------------ + +extern "C" +JNIEXPORT jint JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLibrary_getApiVersion + ( JNIEnv* env, jclass cls ) +{ + return API_VERSION_WINDOWS; +} diff --git a/flatlaf-natives/flatlaf-natives-windows/src/main/headers/com_formdev_flatlaf_ui_FlatNativeLibrary.h b/flatlaf-natives/flatlaf-natives-windows/src/main/headers/com_formdev_flatlaf_ui_FlatNativeLibrary.h new file mode 100644 index 00000000..35ba342b --- /dev/null +++ b/flatlaf-natives/flatlaf-natives-windows/src/main/headers/com_formdev_flatlaf_ui_FlatNativeLibrary.h @@ -0,0 +1,21 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class com_formdev_flatlaf_ui_FlatNativeLibrary */ + +#ifndef _Included_com_formdev_flatlaf_ui_FlatNativeLibrary +#define _Included_com_formdev_flatlaf_ui_FlatNativeLibrary +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: com_formdev_flatlaf_ui_FlatNativeLibrary + * Method: getApiVersion + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLibrary_getApiVersion + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif