提交 0c5454bf 编写于 作者: A alanb

8005716: Enhance JNI specification to allow support of static JNI libraries in Embedded JREs

Reviewed-by: dlong, alanb, mduigou
Contributed-by: bill.pittore@oracle.com, bob.vandette@oracle.com
上级 714d218d
......@@ -133,6 +133,7 @@ SUNWprivate_1.1 {
Java_java_lang_ClassLoader_00024NativeLibrary_find;
Java_java_lang_ClassLoader_00024NativeLibrary_load;
Java_java_lang_ClassLoader_00024NativeLibrary_unload;
Java_java_lang_ClassLoader_00024NativeLibrary_findBuiltinLib;
Java_java_lang_ClassLoader_getCaller;
Java_java_lang_ClassLoader_registerNatives;
Java_java_lang_Compiler_registerNatives;
......
......@@ -133,6 +133,7 @@ SUNWprivate_1.1 {
Java_java_lang_ClassLoader_00024NativeLibrary_find;
Java_java_lang_ClassLoader_00024NativeLibrary_load;
Java_java_lang_ClassLoader_00024NativeLibrary_unload;
Java_java_lang_ClassLoader_00024NativeLibrary_findBuiltinLib;
Java_java_lang_ClassLoader_getCaller;
Java_java_lang_ClassLoader_registerNatives;
Java_java_lang_Compiler_registerNatives;
......
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 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
......@@ -1683,22 +1683,29 @@ public abstract class ClassLoader {
private int jniVersion;
// the class from which the library is loaded, also indicates
// the loader this native library belongs.
private Class<?> fromClass;
private final Class<?> fromClass;
// the canonicalized name of the native library.
// or static library name
String name;
// Indicates if the native library is linked into the VM
boolean isBuiltin;
// Indicates if the native library is loaded
boolean loaded;
native void load(String name, boolean isBuiltin);
native void load(String name);
native long find(String name);
native void unload();
native void unload(String name, boolean isBuiltin);
static native String findBuiltinLib(String name);
public NativeLibrary(Class<?> fromClass, String name) {
public NativeLibrary(Class<?> fromClass, String name, boolean isBuiltin) {
this.name = name;
this.fromClass = fromClass;
this.isBuiltin = isBuiltin;
}
protected void finalize() {
synchronized (loadedLibraryNames) {
if (fromClass.getClassLoader() != null && handle != 0) {
if (fromClass.getClassLoader() != null && loaded) {
/* remove the native library name */
int size = loadedLibraryNames.size();
for (int i = 0; i < size; i++) {
......@@ -1710,7 +1717,7 @@ public abstract class ClassLoader {
/* unload the library. */
ClassLoader.nativeLibraryContext.push(this);
try {
unload();
unload(name, isBuiltin);
} finally {
ClassLoader.nativeLibraryContext.pop();
}
......@@ -1830,20 +1837,24 @@ public abstract class ClassLoader {
}
private static boolean loadLibrary0(Class<?> fromClass, final File file) {
boolean exists = AccessController.doPrivileged(
new PrivilegedAction<Object>() {
public Object run() {
return file.exists() ? Boolean.TRUE : null;
}})
!= null;
if (!exists) {
return false;
}
String name;
try {
name = file.getCanonicalPath();
} catch (IOException e) {
return false;
// Check to see if we're attempting to access a static library
String name = NativeLibrary.findBuiltinLib(file.getName());
boolean isBuiltin = (name != null);
if (!isBuiltin) {
boolean exists = AccessController.doPrivileged(
new PrivilegedAction<Object>() {
public Object run() {
return file.exists() ? Boolean.TRUE : null;
}})
!= null;
if (!exists) {
return false;
}
try {
name = file.getCanonicalPath();
} catch (IOException e) {
return false;
}
}
ClassLoader loader =
(fromClass == null) ? null : fromClass.getClassLoader();
......@@ -1891,14 +1902,14 @@ public abstract class ClassLoader {
}
}
}
NativeLibrary lib = new NativeLibrary(fromClass, name);
NativeLibrary lib = new NativeLibrary(fromClass, name, isBuiltin);
nativeLibraryContext.push(lib);
try {
lib.load(name);
lib.load(name, isBuiltin);
} finally {
nativeLibraryContext.pop();
}
if (lib.handle != 0) {
if (lib.loaded) {
loadedLibraryNames.addElement(name);
libs.addElement(lib);
return true;
......
/*
* Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1995, 2013, 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
......@@ -749,10 +749,21 @@ public class Runtime {
public native void traceMethodCalls(boolean on);
/**
* Loads the specified filename as a dynamic library. The filename
* argument must be a complete path name,
* Loads the native library specified by the filename argument. The filename
* argument must be an absolute path name.
* (for example
* <code>Runtime.getRuntime().load("/home/avh/lib/libX11.so");</code>).
*
* If the filename argument, when stripped of any platform-specific library
* prefix, path, and file extension, indicates a library whose name is,
* for example, L, and a native library called L is statically linked
* with the VM, then the JNI_OnLoad_L function exported by the library
* is invoked rather than attempting to load a dynamic library.
* A filename matching the argument does not have to exist in the file
* system. See the JNI Specification for more details.
*
* Otherwise, the filename argument is mapped to a native library image in
* an implementation-dependent manner.
* <p>
* First, if there is a security manager, its <code>checkLink</code>
* method is called with the <code>filename</code> as its argument.
......@@ -769,7 +780,10 @@ public class Runtime {
* @exception SecurityException if a security manager exists and its
* <code>checkLink</code> method doesn't allow
* loading of the specified dynamic library
* @exception UnsatisfiedLinkError if the file does not exist.
* @exception UnsatisfiedLinkError if either the filename is not an
* absolute path name, the native library is not statically
* linked with the VM, or the library cannot be mapped to
* a native library image by the host system.
* @exception NullPointerException if <code>filename</code> is
* <code>null</code>
* @see java.lang.Runtime#getRuntime()
......@@ -793,12 +807,16 @@ public class Runtime {
}
/**
* Loads the dynamic library with the specified library name.
* A file containing native code is loaded from the local file system
* from a place where library files are conventionally obtained. The
* details of this process are implementation-dependent. The
* mapping from a library name to a specific filename is done in a
* system-specific manner.
* Loads the native library specified by the <code>libname</code>
* argument. The <code>libname</code> argument must not contain any platform
* specific prefix, file extension or path. If a native library
* called <code>libname</code> is statically linked with the VM, then the
* JNI_OnLoad_<code>libname</code> function exported by the library is invoked.
* See the JNI Specification for more details.
*
* Otherwise, the libname argument is loaded from a system library
* location and mapped to a native library image in an implementation-
* dependent manner.
* <p>
* First, if there is a security manager, its <code>checkLink</code>
* method is called with the <code>libname</code> as its argument.
......@@ -823,7 +841,10 @@ public class Runtime {
* @exception SecurityException if a security manager exists and its
* <code>checkLink</code> method doesn't allow
* loading of the specified dynamic library
* @exception UnsatisfiedLinkError if the library does not exist.
* @exception UnsatisfiedLinkError if either the libname argument
* contains a file path, the native library is not statically
* linked with the VM, or the library cannot be mapped to a
* native library image by the host system.
* @exception NullPointerException if <code>libname</code> is
* <code>null</code>
* @see java.lang.SecurityException
......
......@@ -1037,9 +1037,21 @@ public final class System {
}
/**
* Loads a code file with the specified filename from the local file
* system as a dynamic library. The filename
* argument must be a complete path name.
* Loads the native library specified by the filename argument. The filename
* argument must be an absolute path name.
*
* If the filename argument, when stripped of any platform-specific library
* prefix, path, and file extension, indicates a library whose name is,
* for example, L, and a native library called L is statically linked
* with the VM, then the JNI_OnLoad_L function exported by the library
* is invoked rather than attempting to load a dynamic library.
* A filename matching the argument does not have to exist in the
* file system.
* See the JNI Specification for more details.
*
* Otherwise, the filename argument is mapped to a native library image in
* an implementation-dependent manner.
*
* <p>
* The call <code>System.load(name)</code> is effectively equivalent
* to the call:
......@@ -1051,7 +1063,10 @@ public final class System {
* @exception SecurityException if a security manager exists and its
* <code>checkLink</code> method doesn't allow
* loading of the specified dynamic library
* @exception UnsatisfiedLinkError if the file does not exist.
* @exception UnsatisfiedLinkError if either the filename is not an
* absolute path name, the native library is not statically
* linked with the VM, or the library cannot be mapped to
* a native library image by the host system.
* @exception NullPointerException if <code>filename</code> is
* <code>null</code>
* @see java.lang.Runtime#load(java.lang.String)
......@@ -1062,9 +1077,16 @@ public final class System {
}
/**
* Loads the system library specified by the <code>libname</code>
* argument. The manner in which a library name is mapped to the
* actual system library is system dependent.
* Loads the native library specified by the <code>libname</code>
* argument. The <code>libname</code> argument must not contain any platform
* specific prefix, file extension or path. If a native library
* called <code>libname</code> is statically linked with the VM, then the
* JNI_OnLoad_<code>libname</code> function exported by the library is invoked.
* See the JNI Specification for more details.
*
* Otherwise, the libname argument is loaded from a system library
* location and mapped to a native library image in an implementation-
* dependent manner.
* <p>
* The call <code>System.loadLibrary(name)</code> is effectively
* equivalent to the call
......@@ -1076,7 +1098,10 @@ public final class System {
* @exception SecurityException if a security manager exists and its
* <code>checkLink</code> method doesn't allow
* loading of the specified dynamic library
* @exception UnsatisfiedLinkError if the library does not exist.
* @exception UnsatisfiedLinkError if either the libname argument
* contains a file path, the native library is not statically
* linked with the VM, or the library cannot be mapped to a
* native library image by the host system.
* @exception NullPointerException if <code>libname</code> is
* <code>null</code>
* @see java.lang.Runtime#loadLibrary(java.lang.String)
......
/*
* Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2013, 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
......@@ -1951,6 +1951,7 @@ JNI_OnUnload(JavaVM *vm, void *reserved);
#define JNI_VERSION_1_2 0x00010002
#define JNI_VERSION_1_4 0x00010004
#define JNI_VERSION_1_6 0x00010006
#define JNI_VERSION_1_8 0x00010008
#ifdef __cplusplus
} /* extern "C" */
......
/*
* Copyright (c) 1997, 2004, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2013, 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
......@@ -339,6 +339,10 @@ int getFastEncoding();
void initializeEncoding();
void* getProcessHandle();
void buildJniFunctionName(const char *sym, const char *cname,
char *jniEntryName);
#ifdef __cplusplus
} /* extern "C" */
......
/*
* Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2013, 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
......@@ -32,6 +32,7 @@
#include "jvm.h"
#include "java_lang_ClassLoader.h"
#include "java_lang_ClassLoader_NativeLibrary.h"
#include <string.h>
/* defined in libverify.so/verify.dll (src file common/check_format.c) */
extern jboolean VerifyClassname(char *utf_name, jboolean arrayAllowed);
......@@ -286,6 +287,8 @@ Java_java_lang_ClassLoader_findLoadedClass0(JNIEnv *env, jobject loader,
static jfieldID handleID;
static jfieldID jniVersionID;
static jfieldID loadedID;
static void *procHandle;
static jboolean initIDs(JNIEnv *env)
{
......@@ -300,6 +303,10 @@ static jboolean initIDs(JNIEnv *env)
jniVersionID = (*env)->GetFieldID(env, this, "jniVersion", "I");
if (jniVersionID == 0)
return JNI_FALSE;
loadedID = (*env)->GetFieldID(env, this, "loaded", "Z");
if (loadedID == 0)
return JNI_FALSE;
procHandle = getProcessHandle();
}
return JNI_TRUE;
}
......@@ -307,14 +314,60 @@ static jboolean initIDs(JNIEnv *env)
typedef jint (JNICALL *JNI_OnLoad_t)(JavaVM *, void *);
typedef void (JNICALL *JNI_OnUnload_t)(JavaVM *, void *);
/*
* Support for finding JNI_On(Un)Load_<lib_name> if it exists.
* If cname == NULL then just find normal JNI_On(Un)Load entry point
*/
static void *findJniFunction(JNIEnv *env, void *handle,
const char *cname, jboolean isLoad) {
const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS;
const char *onUnloadSymbols[] = JNI_ONUNLOAD_SYMBOLS;
const char **syms;
int symsLen;
void *entryName = NULL;
char *jniFunctionName;
int i;
int len;
// Check for JNI_On(Un)Load<_libname> function
if (isLoad) {
syms = onLoadSymbols;
symsLen = sizeof(onLoadSymbols) / sizeof(char *);
} else {
syms = onUnloadSymbols;
symsLen = sizeof(onUnloadSymbols) / sizeof(char *);
}
for (i = 0; i < symsLen; i++) {
// cname + sym + '_' + '\0'
if ((len = (cname != NULL ? strlen(cname) : 0) + strlen(syms[i]) + 2) >
FILENAME_MAX) {
goto done;
}
jniFunctionName = malloc(len);
if (jniFunctionName == NULL) {
JNU_ThrowOutOfMemoryError(env, NULL);
goto done;
}
buildJniFunctionName(syms[i], cname, jniFunctionName);
entryName = JVM_FindLibraryEntry(handle, jniFunctionName);
free(jniFunctionName);
if(entryName) {
break;
}
}
done:
return entryName;
}
/*
* Class: java_lang_ClassLoader_NativeLibrary
* Method: load
* Signature: (Ljava/lang/String;)J
* Signature: (Ljava/lang/String;Z)V
*/
JNIEXPORT void JNICALL
Java_java_lang_ClassLoader_00024NativeLibrary_load
(JNIEnv *env, jobject this, jstring name)
(JNIEnv *env, jobject this, jstring name, jboolean isBuiltin)
{
const char *cname;
jint jniVersion;
......@@ -327,18 +380,12 @@ Java_java_lang_ClassLoader_00024NativeLibrary_load
cname = JNU_GetStringPlatformChars(env, name, 0);
if (cname == 0)
return;
handle = JVM_LoadLibrary(cname);
handle = isBuiltin ? procHandle : JVM_LoadLibrary(cname);
if (handle) {
const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS;
JNI_OnLoad_t JNI_OnLoad;
unsigned int i;
for (i = 0; i < sizeof(onLoadSymbols) / sizeof(char *); i++) {
JNI_OnLoad = (JNI_OnLoad_t)
JVM_FindLibraryEntry(handle, onLoadSymbols[i]);
if (JNI_OnLoad) {
break;
}
}
JNI_OnLoad = (JNI_OnLoad_t)findJniFunction(env, handle,
isBuiltin ? cname : NULL,
JNI_TRUE);
if (JNI_OnLoad) {
JavaVM *jvm;
(*env)->GetJavaVM(env, &jvm);
......@@ -355,7 +402,8 @@ Java_java_lang_ClassLoader_00024NativeLibrary_load
goto done;
}
if (!JVM_IsSupportedJNIVersion(jniVersion)) {
if (!JVM_IsSupportedJNIVersion(jniVersion) ||
(isBuiltin && jniVersion < JNI_VERSION_1_8)) {
char msg[256];
jio_snprintf(msg, sizeof(msg),
"unsupported JNI version 0x%08X required by %s",
......@@ -375,6 +423,7 @@ Java_java_lang_ClassLoader_00024NativeLibrary_load
goto done;
}
(*env)->SetLongField(env, this, handleID, ptr_to_jlong(handle));
(*env)->SetBooleanField(env, this, loadedID, JNI_TRUE);
done:
JNU_ReleaseStringPlatformChars(env, name, cname);
......@@ -383,41 +432,40 @@ Java_java_lang_ClassLoader_00024NativeLibrary_load
/*
* Class: java_lang_ClassLoader_NativeLibrary
* Method: unload
* Signature: ()V
* Signature: (Z)V
*/
JNIEXPORT void JNICALL
Java_java_lang_ClassLoader_00024NativeLibrary_unload
(JNIEnv *env, jobject this)
(JNIEnv *env, jobject this, jstring name, jboolean isBuiltin)
{
const char *onUnloadSymbols[] = JNI_ONUNLOAD_SYMBOLS;
void *handle;
JNI_OnUnload_t JNI_OnUnload;
unsigned int i;
const char *cname;
if (!initIDs(env))
return;
handle = jlong_to_ptr((*env)->GetLongField(env, this, handleID));
for (i = 0; i < sizeof(onUnloadSymbols) / sizeof(char *); i++) {
JNI_OnUnload = (JNI_OnUnload_t )
JVM_FindLibraryEntry(handle, onUnloadSymbols[i]);
if (JNI_OnUnload) {
break;
}
cname = JNU_GetStringPlatformChars(env, name, 0);
if (cname == NULL) {
return;
}
handle = jlong_to_ptr((*env)->GetLongField(env, this, handleID));
JNI_OnUnload = (JNI_OnUnload_t )findJniFunction(env, handle,
isBuiltin ? cname : NULL,
JNI_FALSE);
if (JNI_OnUnload) {
JavaVM *jvm;
(*env)->GetJavaVM(env, &jvm);
(*JNI_OnUnload)(jvm, NULL);
}
JVM_UnloadLibrary(handle);
JNU_ReleaseStringPlatformChars(env, name, cname);
}
/*
* Class: java_lang_ClassLoader_NativeLibrary
* Method: find
* Signature: (Ljava/lang/String;J)J
* Signature: (Ljava/lang/String;)J
*/
JNIEXPORT jlong JNICALL
Java_java_lang_ClassLoader_00024NativeLibrary_find
......@@ -456,3 +504,63 @@ Java_java_lang_ClassLoader_getCaller(JNIEnv *env, jclass cls, jint index)
return NULL;
}
/*
* Class: java_lang_ClassLoader_NativeLibrary
* Method: findBuiltinLib
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL
Java_java_lang_ClassLoader_00024NativeLibrary_findBuiltinLib
(JNIEnv *env, jclass cls, jstring name)
{
const char *cname;
char *libName;
int prefixLen = (int) strlen(JNI_LIB_PREFIX);
int suffixLen = (int) strlen(JNI_LIB_SUFFIX);
int len;
jstring lib;
void *ret;
const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS;
if (name == NULL) {
JNU_ThrowInternalError(env, "NULL filename for native library");
return NULL;
}
// Can't call initIDs because it will recurse into NativeLibrary via
// FindClass to check context so set prochandle here as well.
procHandle = getProcessHandle();
cname = JNU_GetStringPlatformChars(env, name, 0);
if (cname == NULL) {
JNU_ThrowOutOfMemoryError(env, NULL);
return NULL;
}
// Copy name Skipping PREFIX
len = strlen(cname);
if (len <= (prefixLen+suffixLen)) {
JNU_ReleaseStringPlatformChars(env, name, cname);
return NULL;
}
libName = malloc(len + 1); //+1 for null if prefix+suffix == 0
if (libName == NULL) {
JNU_ReleaseStringPlatformChars(env, name, cname);
JNU_ThrowOutOfMemoryError(env, NULL);
return NULL;
}
if (len > prefixLen) {
strcpy(libName, cname+prefixLen);
}
JNU_ReleaseStringPlatformChars(env, name, cname);
// Strip SUFFIX
libName[strlen(libName)-suffixLen] = '\0';
// Check for JNI_OnLoad_libname function
ret = findJniFunction(env, procHandle, libName, JNI_TRUE);
if (ret != NULL) {
lib = JNU_NewStringPlatform(env, libName);
free(libName);
return lib;
}
free(libName);
return NULL;
}
/*
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2013, 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
......@@ -25,6 +25,7 @@
#include "jni.h"
#include "jni_util.h"
#include "dlfcn.h"
jstring nativeNewStringPlatform(JNIEnv *env, const char *str) {
return NULL;
......@@ -33,3 +34,22 @@ jstring nativeNewStringPlatform(JNIEnv *env, const char *str) {
char* nativeGetStringPlatformChars(JNIEnv *env, jstring jstr, jboolean *isCopy) {
return NULL;
}
void* getProcessHandle() {
static void *procHandle = NULL;
if (procHandle != NULL) {
return procHandle;
}
procHandle = (void*)dlopen(NULL, RTLD_LAZY);
return procHandle;
}
void buildJniFunctionName(const char *sym, const char *cname,
char *jniEntryName) {
strcpy(jniEntryName, sym);
if (cname != NULL) {
strcat(jniEntryName, "_");
strcat(jniEntryName, cname);
}
}
/*
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2004, 2013, 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
......@@ -137,3 +137,35 @@ char* nativeGetStringPlatformChars(JNIEnv *env, jstring jstr, jboolean *isCopy)
else
return NULL;
}
void* getProcessHandle() {
return (void*)GetModuleHandle(NULL);
}
/*
* Windows symbols can be simple like JNI_OnLoad or __stdcall format
* like _JNI_OnLoad@8. We need to handle both.
*/
void buildJniFunctionName(const char *sym, const char *cname,
char *jniEntryName) {
if (cname != NULL) {
char *p = strrchr(sym, '@');
if (p != NULL && p != sym) {
// sym == _JNI_OnLoad@8
strncpy(jniEntryName, sym, (p - sym));
jniEntryName[(p-sym)] = '\0';
// jniEntryName == _JNI_OnLoad
strcat(jniEntryName, "_");
strcat(jniEntryName, cname);
strcat(jniEntryName, p);
//jniEntryName == _JNI_OnLoad_cname@8
} else {
strcpy(jniEntryName, sym);
strcat(jniEntryName, "_");
strcat(jniEntryName, cname);
}
} else {
strcpy(jniEntryName, sym);
}
return;
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册