< prev index next >

src/java.base/share/classes/jdk/internal/loader/NativeLibraries.java

Print this page




   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package jdk.internal.loader;
  26 

  27 import jdk.internal.ref.CleanerFactory;
  28 import jdk.internal.util.StaticProperty;
  29 
  30 import java.io.File;
  31 import java.io.IOException;
  32 import java.security.AccessController;
  33 import java.security.PrivilegedAction;
  34 import java.util.ArrayDeque;
  35 import java.util.Deque;
  36 import java.util.HashSet;

  37 import java.util.Map;
  38 import java.util.Set;
  39 import java.util.concurrent.ConcurrentHashMap;
  40 
  41 /**
  42  * Native libraries are loaded via {@link System#loadLibrary(String)},
  43  * {@link System#load(String)}, {@link Runtime#loadLibrary(String)} and
  44  * {@link Runtime#load(String)}.  They are caller-sensitive.
  45  *
  46  * Each class loader has a NativeLibraries instance to register all of its
  47  * loaded native libraries.  System::loadLibrary (and other APIs) only
  48  * allows a native library to be loaded by one class loader, i.e. one
  49  * NativeLibraries instance.  Any attempt to load a native library that
  50  * has already been loaded by a class loader with another class loader
  51  * will fail.
  52  */
  53 public final class NativeLibraries {
  54 
  55     private final Map<String, NativeLibrary> libraries = new ConcurrentHashMap<>();
  56     private final ClassLoader loader;
  57     private final Class<?> caller;      // may be null.  If not null, this is used as
  58                                         // fromClass as a fast-path.  See loadLibrary(String name).

  59     private final boolean searchJavaLibraryPath;


  60 
  61     public NativeLibraries(ClassLoader loader) {




































  62         // for null loader, default the caller to this class and
  63         // do not search java.library.path
  64         this(loader, loader != null ? null : NativeLibraries.class, loader != null ? true : false);



  65     }
  66     public NativeLibraries(ClassLoader loader, Class<?> caller, boolean searchJavaLibraryPath) {
  67         if (caller != null && caller.getClassLoader() != loader) {
  68             throw new IllegalArgumentException(caller.getName() + " must be defined by " + loader);






  69         }
  70         this.loader = loader;
  71         this.caller = caller;
  72         this.searchJavaLibraryPath = searchJavaLibraryPath;

  73     }
  74 
  75     /*
  76      * Find the address of the given symbol name from the native libraries
  77      * loaded in this NativeLibraries instance.
  78      */
  79     public long find(String name) {
  80         if (libraries.isEmpty())
  81             return 0;
  82 
  83         // the native libraries map may be updated in another thread
  84         // when a native library is being loaded.  No symbol will be
  85         // searched from it yet.
  86         for (NativeLibrary lib : libraries.values()) {
  87             long entry = lib.find(name);
  88             if (entry != 0) return entry;
  89         }
  90         return 0;
  91     }
  92 


 152              *
 153              * We use a static stack to hold the list of libraries we are
 154              * loading because this can happen only when called by the
 155              * same thread because this block is synchronous.
 156              *
 157              * If there is a pending load operation for the library, we
 158              * immediately return success; otherwise, we raise
 159              * UnsatisfiedLinkError.
 160              */
 161             for (NativeLibraryImpl lib : nativeLibraryContext) {
 162                 if (name.equals(lib.name())) {
 163                     if (loader == lib.fromClass.getClassLoader()) {
 164                         return lib;
 165                     } else {
 166                         throw new UnsatisfiedLinkError("Native Library " +
 167                                 name + " is being loaded in another classloader");
 168                     }
 169                 }
 170             }
 171 
 172             NativeLibraryImpl lib = new NativeLibraryImpl(fromClass, name, isBuiltin);
 173             // load the native library
 174             nativeLibraryContext.push(lib);
 175             try {
 176                 if (!lib.open()) return null;















 177             } finally {
 178                 nativeLibraryContext.pop();
 179             }
 180             // register the loaded native library
 181             loadedLibraryNames.add(name);
 182             libraries.put(name, lib);
 183             return lib;
 184         }
 185     }
 186 
 187     /**
 188      * Loads a native library from the system library path and java library path.
 189      *
 190      * @param name library name
 191      *
 192      * @throws UnsatisfiedLinkError if the native library has already been loaded
 193      *      and registered in another NativeLibraries
 194      */
 195     public NativeLibrary loadLibrary(String name) {
 196         assert name.indexOf(File.separatorChar) < 0;


 201 
 202     /**
 203      * Loads a native library from the system library path and java library path.
 204      *
 205      * @param name library name
 206      * @param fromClass the caller class calling System::loadLibrary
 207      *
 208      * @throws UnsatisfiedLinkError if the native library has already been loaded
 209      *      and registered in another NativeLibraries
 210      */
 211     public NativeLibrary loadLibrary(Class<?> fromClass, String name) {
 212         assert name.indexOf(File.separatorChar) < 0;
 213 
 214         NativeLibrary lib = findFromPaths(LibraryPaths.SYS_PATHS, fromClass, name);
 215         if (lib == null && searchJavaLibraryPath) {
 216             lib = findFromPaths(LibraryPaths.USER_PATHS, fromClass, name);
 217         }
 218         return lib;
 219     }
 220 




















 221     private NativeLibrary findFromPaths(String[] paths, Class<?> fromClass, String name) {
 222         for (String path : paths) {
 223             File libfile = new File(path, System.mapLibraryName(name));
 224             NativeLibrary nl = loadLibrary(fromClass, libfile);
 225             if (nl != null) {
 226                 return nl;
 227             }
 228             libfile = ClassLoaderHelper.mapAlternativeName(libfile);
 229             if (libfile != null) {
 230                 nl = loadLibrary(fromClass, libfile);
 231                 if (nl != null) {
 232                     return nl;
 233                 }
 234             }
 235         }
 236         return null;
 237     }
 238 
 239     /**
 240      * NativeLibraryImpl denotes a loaded native library instance.
 241      * Each NativeLibraries contains a map of loaded native libraries in the
 242      * private field {@code libraries}.
 243      *
 244      * Every native library requires a particular version of JNI. This is
 245      * denoted by the private {@code jniVersion} field.  This field is set by
 246      * the VM when it loads the library, and used by the VM to pass the correct
 247      * version of JNI to the native methods.
 248      */
 249     static class NativeLibraryImpl implements NativeLibrary {
 250         // the class from which the library is loaded, also indicates
 251         // the loader this native library belongs.
 252         final Class<?> fromClass;
 253         // the canonicalized name of the native library.
 254         // or static library name
 255         final String name;
 256         // Indicates if the native library is linked into the VM
 257         final boolean isBuiltin;


 258 
 259         // opaque handle to native library, used in native code.
 260         long handle;
 261         // the version of JNI environment the native library requires.
 262         int jniVersion;
 263 
 264         NativeLibraryImpl(Class<?> fromClass, String name, boolean isBuiltin) {


 265             this.fromClass = fromClass;
 266             this.name = name;
 267             this.isBuiltin = isBuiltin;

 268         }
 269 
 270         @Override
 271         public String name() {
 272             return name;
 273         }
 274 
 275         @Override
 276         public long find(String name) {
 277             return findEntry0(this, name);
 278         }
 279 




 280         /*
 281          * Loads the native library and registers for cleanup when its
 282          * associated class loader is unloaded
 283          */
 284         boolean open() {
 285             if (handle != 0) {
 286                 throw new InternalError("Native library " + name + " has been loaded");
 287             }
 288 
 289             if (!load(this, name, isBuiltin)) return false;
 290 
 291             // register the class loader for cleanup when unloaded
 292             // builtin class loaders are never unloaded
 293             ClassLoader loader = fromClass != null ? fromClass.getClassLoader() : null;
 294             if (loader != null &&
 295                     loader != ClassLoaders.platformClassLoader() &&
 296                     loader != ClassLoaders.appClassLoader()) {
 297                 CleanerFactory.cleaner().register(loader, new Unloader(name, handle, isBuiltin));
 298             }
 299             return true;
 300         }
 301     }
 302 
 303     /*
 304      * The run() method will be invoked when this class loader becomes
 305      * phantom reachable to unload the native library.
 306      */
 307     static class Unloader implements Runnable {
 308         // This represents the context when a native library is unloaded
 309         // and getFromClass() will return null,
 310         static final NativeLibraryImpl UNLOADER =
 311                 new NativeLibraryImpl(null, "dummy", false);
 312 
 313         final String name;
 314         final long handle;
 315         final boolean isBuiltin;

 316 
 317         Unloader(String name, long handle, boolean isBuiltin) {

 318             if (handle == 0) {
 319                 throw new IllegalArgumentException(
 320                         "Invalid handle for native library " + name);
 321             }
 322 
 323             this.name = name;
 324             this.handle = handle;
 325             this.isBuiltin = isBuiltin;

 326         }
 327 
 328         @Override
 329         public void run() {
 330             synchronized (NativeLibraries.loadedLibraryNames) {
 331                 /* remove the native library name */
 332                 NativeLibraries.loadedLibraryNames.remove(name);
 333                 NativeLibraries.nativeLibraryContext.push(UNLOADER);


 334                 try {
 335                     unload(name, isBuiltin, handle);
 336                 } finally {
 337                     NativeLibraries.nativeLibraryContext.pop();
 338                 }
 339             }
 340         }
 341     }
 342 
 343     /*
 344      * Holds system and user library paths derived from the
 345      * {@code java.library.path} and {@code sun.boot.library.path} system
 346      * properties. The system properties are eagerly read at bootstrap, then
 347      * lazily parsed on first use to avoid initialization ordering issues.
 348      */
 349     static class LibraryPaths {
 350         // The paths searched for libraries
 351         static final String[] SYS_PATHS = ClassLoaderHelper.parsePath(StaticProperty.sunBootLibraryPath());
 352         static final String[] USER_PATHS = ClassLoaderHelper.parsePath(StaticProperty.javaLibraryPath());
 353     }
 354 
 355     // All native libraries we've loaded.
 356     // This also serves as the lock to obtain nativeLibraries
 357     // and write to nativeLibraryContext.
 358     private static final Set<String> loadedLibraryNames = new HashSet<>();
 359 
 360     // native libraries being loaded
 361     private static Deque<NativeLibraryImpl> nativeLibraryContext = new ArrayDeque<>(8);
 362 
 363     // Invoked in the VM to determine the context class in JNI_OnLoad
 364     // and JNI_OnUnload
 365     private static Class<?> getFromClass() {
 366         if (nativeLibraryContext.isEmpty()) { // only default library
 367             return Object.class;
 368         }
 369         return nativeLibraryContext.peek().fromClass;
 370     }
 371 
 372     // JNI FindClass expects the caller class if invoked from JNI_OnLoad
 373     // and JNI_OnUnload is NativeLibrary class
 374     private static native boolean load(NativeLibraryImpl impl, String name, boolean isBuiltin);
 375     private static native void unload(String name, boolean isBuiltin, long handle);
 376     private static native String findBuiltinLib(String name);
 377     private static native long findEntry0(NativeLibraryImpl lib, String name);
 378 }


   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package jdk.internal.loader;
  26 
  27 import jdk.internal.misc.VM;
  28 import jdk.internal.ref.CleanerFactory;
  29 import jdk.internal.util.StaticProperty;
  30 
  31 import java.io.File;
  32 import java.io.IOException;
  33 import java.security.AccessController;
  34 import java.security.PrivilegedAction;
  35 import java.util.ArrayDeque;
  36 import java.util.Deque;
  37 import java.util.HashSet;
  38 import java.util.Objects;
  39 import java.util.Map;
  40 import java.util.Set;
  41 import java.util.concurrent.ConcurrentHashMap;
  42 
  43 /**
  44  * Native libraries are loaded via {@link System#loadLibrary(String)},
  45  * {@link System#load(String)}, {@link Runtime#loadLibrary(String)} and
  46  * {@link Runtime#load(String)}.  They are caller-sensitive.
  47  *
  48  * Each class loader has a NativeLibraries instance to register all of its
  49  * loaded native libraries.  System::loadLibrary (and other APIs) only
  50  * allows a native library to be loaded by one class loader, i.e. one
  51  * NativeLibraries instance.  Any attempt to load a native library that
  52  * has already been loaded by a class loader with another class loader
  53  * will fail.
  54  */
  55 public final class NativeLibraries {
  56 
  57     private final Map<String, NativeLibraryImpl> libraries = new ConcurrentHashMap<>();
  58     private final ClassLoader loader;
  59     // caller, if non-null, is the fromClass parameter for NativeLibraries::loadLibrary
  60     // unless specified
  61     private final Class<?> caller;      // may be null
  62     private final boolean searchJavaLibraryPath;
  63     // loading JNI native libraries
  64     private final boolean isJNI;
  65 
  66     /**
  67      * Creates a NativeLibraries instance for loading JNI native libraries
  68      * via for System::loadLibrary use.
  69      *
  70      * 1. Support of auto-unloading.  The loaded native libraries are unloaded
  71      *    when the class loader is reclaimed.
  72      * 2. Support of linking of native method.  See JNI spec.
  73      * 3. Restriction on a native library that can only be loaded by one class loader.
  74      *    Each class loader manages its own set of native libraries.
  75      *    The same JNI native library cannot be loaded into more than one class loader.
  76      *
  77      * This static factory method is intended only for System::loadLibrary use.
  78      *
  79      * @see <a href="${docroot}/specs/jni/invocation.html##library-and-version-management">
  80      *     JNI Specification: Library and Version Management</a>
  81      */
  82     public static NativeLibraries jniNativeLibraries(ClassLoader loader) {
  83         return new NativeLibraries(loader);
  84     }
  85 
  86     /**
  87      * Creates a raw NativeLibraries instance that has the following properties:
  88      * 1. Native libraries loaded in this raw NativeLibraries instance are
  89      *    not JNI native libraries.  Hence JNI_OnLoad and JNI_OnUnload will
  90      *    be ignored.  No support for linking of native method.
  91      * 2. Native libraries not auto-unloaded.  They may be explicitly unloaded
  92      *    via NativeLibraries::unload.
  93      * 3. No relationship with class loaders.
  94      *
  95      * This static factory method is restricted for JDK trusted class use.
  96      */
  97     public static NativeLibraries rawNativeLibraries(Class<?> trustedCaller,
  98                                                      boolean searchJavaLibraryPath) {
  99         return new NativeLibraries(trustedCaller, searchJavaLibraryPath);
 100     }
 101 
 102     private NativeLibraries(ClassLoader loader) {
 103         // for null loader, default the caller to this class and
 104         // do not search java.library.path
 105         this.loader = loader;
 106         this.caller = loader != null ? null : NativeLibraries.class;
 107         this.searchJavaLibraryPath = loader != null ? true : false;
 108         this.isJNI = true;
 109     }
 110 
 111     /*
 112      * Constructs a NativeLibraries instance of no relationship with class loaders
 113      * and disabled auto unloading.
 114      */
 115     private NativeLibraries(Class<?> caller, boolean searchJavaLibraryPath) {
 116         Objects.requireNonNull(caller);
 117         if (!VM.isSystemDomainLoader(caller.getClassLoader())) {
 118             throw new IllegalArgumentException("must be JDK trusted class");
 119         }
 120         this.loader = caller.getClassLoader();
 121         this.caller = caller;
 122         this.searchJavaLibraryPath = searchJavaLibraryPath;
 123         this.isJNI = false;
 124     }
 125 
 126     /*
 127      * Find the address of the given symbol name from the native libraries
 128      * loaded in this NativeLibraries instance.
 129      */
 130     public long find(String name) {
 131         if (libraries.isEmpty())
 132             return 0;
 133 
 134         // the native libraries map may be updated in another thread
 135         // when a native library is being loaded.  No symbol will be
 136         // searched from it yet.
 137         for (NativeLibrary lib : libraries.values()) {
 138             long entry = lib.find(name);
 139             if (entry != 0) return entry;
 140         }
 141         return 0;
 142     }
 143 


 203              *
 204              * We use a static stack to hold the list of libraries we are
 205              * loading because this can happen only when called by the
 206              * same thread because this block is synchronous.
 207              *
 208              * If there is a pending load operation for the library, we
 209              * immediately return success; otherwise, we raise
 210              * UnsatisfiedLinkError.
 211              */
 212             for (NativeLibraryImpl lib : nativeLibraryContext) {
 213                 if (name.equals(lib.name())) {
 214                     if (loader == lib.fromClass.getClassLoader()) {
 215                         return lib;
 216                     } else {
 217                         throw new UnsatisfiedLinkError("Native Library " +
 218                                 name + " is being loaded in another classloader");
 219                     }
 220                 }
 221             }
 222 
 223             NativeLibraryImpl lib = new NativeLibraryImpl(fromClass, name, isBuiltin, isJNI);
 224             // load the native library
 225             nativeLibraryContext.push(lib);
 226             try {
 227                 if (!lib.open()) {
 228                     return null;    // fail to open the native library
 229                 }
 230                 // auto unloading is only supported for JNI native libraries
 231                 // loaded by custom class loaders that can be unloaded.
 232                 // built-in class loaders are never unloaded.
 233                 boolean autoUnload = isJNI && !VM.isSystemDomainLoader(loader)
 234                         && loader != ClassLoaders.appClassLoader();
 235                 if (autoUnload) {
 236                     // register the loaded native library for auto unloading
 237                     // when the class loader is reclaimed, all native libraries
 238                     // loaded that class loader will be unloaded.
 239                     // The entries in the libraries map are not removed since
 240                     // the entire map will be reclaimed altogether.
 241                     CleanerFactory.cleaner().register(loader, lib.unloader());
 242                 }
 243             } finally {
 244                 nativeLibraryContext.pop();
 245             }
 246             // register the loaded native library
 247             loadedLibraryNames.add(name);
 248             libraries.put(name, lib);
 249             return lib;
 250         }
 251     }
 252 
 253     /**
 254      * Loads a native library from the system library path and java library path.
 255      *
 256      * @param name library name
 257      *
 258      * @throws UnsatisfiedLinkError if the native library has already been loaded
 259      *      and registered in another NativeLibraries
 260      */
 261     public NativeLibrary loadLibrary(String name) {
 262         assert name.indexOf(File.separatorChar) < 0;


 267 
 268     /**
 269      * Loads a native library from the system library path and java library path.
 270      *
 271      * @param name library name
 272      * @param fromClass the caller class calling System::loadLibrary
 273      *
 274      * @throws UnsatisfiedLinkError if the native library has already been loaded
 275      *      and registered in another NativeLibraries
 276      */
 277     public NativeLibrary loadLibrary(Class<?> fromClass, String name) {
 278         assert name.indexOf(File.separatorChar) < 0;
 279 
 280         NativeLibrary lib = findFromPaths(LibraryPaths.SYS_PATHS, fromClass, name);
 281         if (lib == null && searchJavaLibraryPath) {
 282             lib = findFromPaths(LibraryPaths.USER_PATHS, fromClass, name);
 283         }
 284         return lib;
 285     }
 286 
 287     /**
 288      * Unloads the given native library
 289      *
 290      * @param lib native library
 291      */
 292     public void unload(NativeLibrary lib) {
 293         if (isJNI) {
 294             throw new UnsupportedOperationException("explicit unloading cannot be used with auto unloading");
 295         }
 296         Objects.requireNonNull(lib);
 297         synchronized (loadedLibraryNames) {
 298             NativeLibraryImpl nl = libraries.remove(lib.name());
 299             if (nl != lib) {
 300                 throw new IllegalArgumentException(lib.name() + " not loaded by this NativeLibraries instance");
 301             }
 302             // unload the native library and also remove from the global name registry
 303             nl.unloader().run();
 304         }
 305     }
 306 
 307     private NativeLibrary findFromPaths(String[] paths, Class<?> fromClass, String name) {
 308         for (String path : paths) {
 309             File libfile = new File(path, System.mapLibraryName(name));
 310             NativeLibrary nl = loadLibrary(fromClass, libfile);
 311             if (nl != null) {
 312                 return nl;
 313             }
 314             libfile = ClassLoaderHelper.mapAlternativeName(libfile);
 315             if (libfile != null) {
 316                 nl = loadLibrary(fromClass, libfile);
 317                 if (nl != null) {
 318                     return nl;
 319                 }
 320             }
 321         }
 322         return null;
 323     }
 324 
 325     /**
 326      * NativeLibraryImpl denotes a loaded native library instance.
 327      * Each NativeLibraries contains a map of loaded native libraries in the
 328      * private field {@code libraries}.
 329      *
 330      * Every native library requires a particular version of JNI. This is
 331      * denoted by the private {@code jniVersion} field.  This field is set by
 332      * the VM when it loads the library, and used by the VM to pass the correct
 333      * version of JNI to the native methods.
 334      */
 335     static class NativeLibraryImpl implements NativeLibrary {
 336         // the class from which the library is loaded, also indicates
 337         // the loader this native library belongs.
 338         final Class<?> fromClass;
 339         // the canonicalized name of the native library.
 340         // or static library name
 341         final String name;
 342         // Indicates if the native library is linked into the VM
 343         final boolean isBuiltin;
 344         // Indicate if this is JNI native library
 345         final boolean isJNI;
 346 
 347         // opaque handle to native library, used in native code.
 348         long handle;
 349         // the version of JNI environment the native library requires.
 350         int jniVersion;
 351 
 352         NativeLibraryImpl(Class<?> fromClass, String name, boolean isBuiltin, boolean isJNI) {
 353             assert !isBuiltin || isJNI : "a builtin native library must be JNI library";
 354 
 355             this.fromClass = fromClass;
 356             this.name = name;
 357             this.isBuiltin = isBuiltin;
 358             this.isJNI = isJNI;
 359         }
 360 
 361         @Override
 362         public String name() {
 363             return name;
 364         }
 365 
 366         @Override
 367         public long find(String name) {
 368             return findEntry0(this, name);
 369         }
 370 
 371         Runnable unloader() {
 372             return new Unloader(name, handle, isBuiltin, isJNI);
 373         }
 374 
 375         /*
 376          * Loads the named native library

 377          */
 378         boolean open() {
 379             if (handle != 0) {
 380                 throw new InternalError("Native library " + name + " has been loaded");
 381             }
 382 
 383             return load(this, name, isBuiltin, isJNI);










 384         }
 385     }
 386 
 387     /*
 388      * The run() method will be invoked when this class loader becomes
 389      * phantom reachable to unload the native library.
 390      */
 391     static class Unloader implements Runnable {
 392         // This represents the context when a native library is unloaded
 393         // and getFromClass() will return null,
 394         static final NativeLibraryImpl UNLOADER =
 395                 new NativeLibraryImpl(null, "dummy", false, false);
 396 
 397         final String name;
 398         final long handle;
 399         final boolean isBuiltin;
 400         final boolean isJNI;
 401 
 402         Unloader(String name, long handle, boolean isBuiltin, boolean isJNI) {
 403             assert !isBuiltin || isJNI : "a builtin native library must be JNI library";
 404             if (handle == 0) {
 405                 throw new IllegalArgumentException(
 406                         "Invalid handle for native library " + name);
 407             }
 408 
 409             this.name = name;
 410             this.handle = handle;
 411             this.isBuiltin = isBuiltin;
 412             this.isJNI = isJNI;
 413         }
 414 
 415         @Override
 416         public void run() {
 417             synchronized (loadedLibraryNames) {
 418                 /* remove the native library name */
 419                 if (!loadedLibraryNames.remove(name)) {
 420                     throw new IllegalStateException(name + " has already been unloaded");
 421                 }
 422                 nativeLibraryContext.push(UNLOADER);
 423                 try {
 424                     unload(name, isBuiltin, isJNI, handle);
 425                 } finally {
 426                     nativeLibraryContext.pop();
 427                 }
 428             }
 429         }
 430     }
 431 
 432     /*
 433      * Holds system and user library paths derived from the
 434      * {@code java.library.path} and {@code sun.boot.library.path} system
 435      * properties. The system properties are eagerly read at bootstrap, then
 436      * lazily parsed on first use to avoid initialization ordering issues.
 437      */
 438     static class LibraryPaths {
 439         // The paths searched for libraries
 440         static final String[] SYS_PATHS = ClassLoaderHelper.parsePath(StaticProperty.sunBootLibraryPath());
 441         static final String[] USER_PATHS = ClassLoaderHelper.parsePath(StaticProperty.javaLibraryPath());
 442     }
 443 
 444     // All native libraries we've loaded.
 445     // This also serves as the lock to obtain nativeLibraries
 446     // and write to nativeLibraryContext.
 447     private static final Set<String> loadedLibraryNames = new HashSet<>();
 448 
 449     // native libraries being loaded
 450     private static Deque<NativeLibraryImpl> nativeLibraryContext = new ArrayDeque<>(8);
 451 
 452     // Invoked in the VM to determine the context class in JNI_OnLoad
 453     // and JNI_OnUnload
 454     private static Class<?> getFromClass() {
 455         if (nativeLibraryContext.isEmpty()) { // only default library
 456             return Object.class;
 457         }
 458         return nativeLibraryContext.peek().fromClass;
 459     }
 460 
 461     // JNI FindClass expects the caller class if invoked from JNI_OnLoad
 462     // and JNI_OnUnload is NativeLibrary class
 463     private static native boolean load(NativeLibraryImpl impl, String name, boolean isBuiltin, boolean isJNI);
 464     private static native void unload(String name, boolean isBuiltin, boolean isJNI, long handle);
 465     private static native String findBuiltinLib(String name);
 466     private static native long findEntry0(NativeLibraryImpl lib, String name);
 467 }
< prev index next >