我是靠谱客的博主 俊秀哈密瓜,最近开发中收集的这篇文章主要介绍System源码浅析- initializeSystemClass(loadLibrary),觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
文章目录
- 前情提要
- loadLibrary
- loadLibrary0
- getCallerClass
- Java_sun_reflect_Reflection_getCallerClass__
- JVM_GetCallerClass
- security_get_caller_class
- security_get_caller_frame
- at_end
- security_next
- is_ignored_by_security_stack_walk
- init_intrinsic_id
- checkLink
- checkPermission
- checkPermission
- getStackAccessControlContext
- Java_java_security_AccessController_getStackAccessControlContext
- JVM_GetStackAccessControlContext
- doPrivileged
- isOn
- JVM_DoPrivileged
前情提要
在前面已经介绍过 System与initializeSystemClass 在此不做过多解释,没有看到的希望去查看!
System源码浅析- initializeSystemClass(initProperties)
System源码浅析- initializeSystemClass(saveAndRemoveProperties)
System源码浅析- initializeSystemClass(setXXX0)
System源码浅析- initializeSystemClass(loadLibrary)
System源码浅析- initializeSystemClass(setup)
System源码浅析- initializeSystemClass( initializeOSEnvironment )
System源码浅析- initializeSystemClass( setJavaLangAccess)
loadLibrary
/**
加载由 <code>libname<code> 参数指定的本机库。
<code>libname<code> 参数不得包含任何特定于平台的前缀、文件扩展名或路径。
如果名为 <code>libname<code> 的本机库与 VM 静态链接,
则调用该库导出的 JNI_OnLoad_<code>libname<code> 函数。有关更多详细信息,
请参阅 JNI 规范。
否则,libname 参数将从系统库位置加载并以与实现相关的方式映射到本机库映像。
*/
@CallerSensitive
public static void loadLibrary(String libname) {
Runtime.getRuntime().loadLibrary0(Reflection.getCallerClass(), libname);
}
loadLibrary0
// fromClass 调用者
synchronized void loadLibrary0(Class<?> fromClass, String libname) {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkLink(libname);
}
if (libname.indexOf((int)File.separatorChar) != -1) {
throw new UnsatisfiedLinkError(
"Directory separator should not appear in library name: " + libname);
}
ClassLoader.loadLibrary(fromClass, libname, false);
}
getCallerClass
@CallerSensitive
public static native Class<?> getCallerClass();
Java_sun_reflect_Reflection_getCallerClass__
JNIEXPORT jclass JNICALL Java_sun_reflect_Reflection_getCallerClass__
(JNIEnv *env, jclass unused)
{
/*
返回调用 JVM_GetCallerClass 的本机方法的直接调用者类。由于反射机制,Method.invoke 和其他帧被跳过。
深度参数必须为 -1 (JVM_DEPTH)。调用者应该被标记为 sun.reflect.CallerSensitive。如果没有正确标记,JVM 将抛出错误
JVM_GetCallerClass(JNIEnv *env, int depth);
/
return JVM_GetCallerClass(env, JVM_CALLER_DEPTH);
}
JVM_GetCallerClass
// 返回调用者
JVM_ENTRY(jclass, JVM_GetCallerClass(JNIEnv* env, int depth))
JVMWrapper("JVM_GetCallerClass");
//JDK 8 之前的版本和 JDK 8 的早期版本没有 CallerSensitive 注释;或带有深度参数的 sun.reflect.Reflection.getCallerClass 临时提供给现有代码使用,直到定义替换 API。
if (SystemDictionary::reflect_CallerSensitive_klass() == NULL || depth != JVM_CALLER_DEPTH) {
// 返回“深度”的方法 java 或栈中的原生帧 用于安全检查
Klass* k = thread->security_get_caller_class(depth);
return (k == NULL) ? NULL : (jclass) JNIHandles::make_local(env, k->java_mirror());
}
// 获取调用者框架的类
//
// 此时的调用堆栈如下所示:
//
// [0] [ @CallerSensitive public sun.reflect.Reflection.getCallerClass ]
// [1] [ @CallerSensitive API.method
]
// [.] [ (skipped intermediate frames)
]
// [n] [ caller
]
vframeStream vfst(thread);
// Cf. LibraryCallKit::inline_native_Reflection_getCallerClass
for (int n = 0; !vfst.at_end(); vfst.security_next(), n++) {
Method* m = vfst.method();
assert(m != NULL, "sanity");
switch (n) {
case 0:
// 这只能从 Reflection.getCallerClass 调用
if (m->intrinsic_id() != vmIntrinsics::_getCallerClass) {
THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "JVM_GetCallerClass must only be called from Reflection.getCallerClass");
}
// fall-through
case 1:
// Frame 0 和 1 必须是调用者sensitive.
if (!m->caller_sensitive()) {
THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), err_msg("CallerSensitive annotation expected at frame %d", n));
}
break;
default:
if (!m->is_ignored_by_security_stack_walk()) {
// 我们已经达到了预期的框架;返回持有者类。
return (jclass) JNIHandles::make_local(env, m->method_holder()->java_mirror());
}
break;
}
}
return NULL;
JVM_END
security_get_caller_class
Klass* JavaThread::security_get_caller_class(int depth) {
vframeStream vfst(this);
// 后退 n 帧,跳过其间的任何伪帧。该函数用于Class.forName、Class.newInstance、Method.Invoke、AccessController.doPrivileged。
vfst.security_get_caller_frame(depth);
if (!vfst.at_end()) {
return vfst.method()->method_holder();
}
return NULL;
}
security_get_caller_frame
// 后退 n 帧,跳过其间的任何伪帧。该函数用于Class.forName、Class.newInstance、Method.Invoke、AccessController.doPrivileged。
void vframeStreamCommon::security_get_caller_frame(int depth) {
assert(depth >= 0, err_msg("invalid depth: %d", depth));
for (int n = 0; !at_end(); security_next()) {
if (!method()->is_ignored_by_security_stack_walk()) {
if (n == depth) {
// We have reached the desired depth; return.
return;
}
n++;
// this is a non-skipped frame; count it against the depth
}
}
// NOTE: At this point there were not enough frames on the stack
// to walk to depth.
Callers of this method have to check for at_end.
}
at_end
// 是否到达末尾
bool at_end() {
return (_data == NULL) || (_index == _data->length());
}
security_next
// 下一个(安全)
void vframeStreamCommon::security_next() {
if (method()->is_prefixed_native()) {
skip_prefixed_method_and_wrappers();
// calls next()
} else {
next();
}
}
is_ignored_by_security_stack_walk
// 如果这是安全相关堆栈遍历的特殊处理方法之一(如 Reflection.getCallerClass),则返回 true。
bool Method::is_ignored_by_security_stack_walk() const {
const bool use_new_reflection = JDK_Version::is_gte_jdk14x_version() && UseNewReflection;
if (intrinsic_id() == vmIntrinsics::_invoke) {
// This is Method.invoke() -- ignore it
return true;
}
if (use_new_reflection &&
method_holder()->is_subclass_of(SystemDictionary::reflect_MethodAccessorImpl_klass())) {
// This is an auxilary frame -- ignore it
return true;
}
if (is_method_handle_intrinsic() || is_compiled_lambda_form()) {
// This is an internal adapter frame for method handles -- ignore it
return true;
}
return false;
}
init_intrinsic_id
void Method::init_intrinsic_id() {
assert(_intrinsic_id == vmIntrinsics::_none, "do this just once");
const uintptr_t max_id_uint = right_n_bits((int)(sizeof(_intrinsic_id) * BitsPerByte));
assert((uintptr_t)vmIntrinsics::ID_LIMIT <= max_id_uint, "else fix size");
assert(intrinsic_id_size_in_bytes() == sizeof(_intrinsic_id), "");
// the klass name is well-known:
vmSymbols::SID klass_id = klass_id_for_intrinsics(method_holder());
assert(klass_id != vmSymbols::NO_SID, "caller responsibility");
// ditto for method and signature:
vmSymbols::SID
name_id = vmSymbols::find_sid(name());
if (klass_id != vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_MethodHandle)
&& name_id == vmSymbols::NO_SID)
return;
vmSymbols::SID
sig_id = vmSymbols::find_sid(signature());
if (klass_id != vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_MethodHandle)
&& sig_id == vmSymbols::NO_SID)
return;
jshort flags = access_flags().as_short();
vmIntrinsics::ID id = vmIntrinsics::find_id(klass_id, name_id, sig_id, flags);
if (id != vmIntrinsics::_none) {
set_intrinsic_id(id);
return;
}
// A few slightly irregular cases:
switch (klass_id) {
case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_StrictMath):
// Second chance: check in regular Math.
switch (name_id) {
case vmSymbols::VM_SYMBOL_ENUM_NAME(min_name):
case vmSymbols::VM_SYMBOL_ENUM_NAME(max_name):
case vmSymbols::VM_SYMBOL_ENUM_NAME(sqrt_name):
// pretend it is the corresponding method in the non-strict class:
klass_id = vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_Math);
id = vmIntrinsics::find_id(klass_id, name_id, sig_id, flags);
break;
}
break;
// Signature-polymorphic methods: MethodHandle.invoke*, InvokeDynamic.*.
case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_MethodHandle):
if (!is_native())
break;
id = MethodHandles::signature_polymorphic_name_id(method_holder(), name());
if (is_static() != MethodHandles::is_signature_polymorphic_static(id))
id = vmIntrinsics::_none;
break;
}
if (id != vmIntrinsics::_none) {
// Set up its iid.
It is an alias method.
set_intrinsic_id(id);
return;
}
}
checkLink
/**
如果不允许调用线程动态链接由字符串参数文件指定的库代码,
则抛出 <code>SecurityException<code>。参数要么是一个简单的库名,要么是一个完整的文件名。
* <p>
此方法由类 <code>Runtime<code> 的方法 <code>load<code> 和 <code>loadLibrary<code> 为当前安全管理器调用。
* <p>
此方法使用 <code>RuntimePermission("loadLibrary."+lib)<code> 权限调用 <code>checkPermission<code>。
* <p>
如果你重写了这个方法,那么你应该调用 <code>super.checkLink<code> 在被重写的方法通常会抛出异常的地方。
*
* @param
lib
the name of the library.
* @exception
SecurityException if the calling thread does not have
*
permission to dynamically link the library.
* @exception
NullPointerException if the <code>lib</code> argument is
*
<code>null</code>.
* @see
java.lang.Runtime#load(java.lang.String)
* @see
java.lang.Runtime#loadLibrary(java.lang.String)
* @see
#checkPermission(java.security.Permission) checkPermission
*/
public void checkLink(String lib) {
if (lib == null) {
throw new NullPointerException("library can't be null");
}
checkPermission(new RuntimePermission("loadLibrary."+lib));
}
checkPermission
/**
如果根据当前有效的安全策略不允许由给定权限指定的请求访问,则抛出 <code>SecurityException<code>。
此方法使用给定的权限调用 <code>AccessController.checkPermission<code>。
*
* @param
perm
the requested permission.
* @exception SecurityException if access is not permitted based on
*
the current security policy.
* @exception NullPointerException if the permission argument is
*
<code>null</code>.
* @since
1.2
*/
public void checkPermission(Permission perm) {
java.security.AccessController.checkPermission(perm);
}
checkPermission
/**
根据当前的 AccessControlContext 和安全策略,确定是允许还是拒绝由指定权限指示的访问请求。
如果访问请求被允许,则此方法悄悄返回,否则抛出 AccessControlException。
AccessControlException 的 getPermission 方法返回 {@code perm} Permission 对象实例。
*
* @param perm the requested permission.
*
* @exception AccessControlException if the specified permission
*
is not permitted, based on the current security policy.
* @exception NullPointerException if the specified permission
*
is {@code null} and is checked based on the
*
security policy currently in effect.
*/
public static void checkPermission(Permission perm)
throws AccessControlException
{
//System.err.println("checkPermission "+perm);
//Thread.currentThread().dumpStack();
if (perm == null) {
throw new NullPointerException("permission can't be null");
}
AccessControlContext stack = getStackAccessControlContext();
// if context is null, we had privileged system code on the stack.
if (stack == null) {
Debug debug = AccessControlContext.getDebug();
boolean dumpDebug = false;
if (debug != null) {
dumpDebug = !Debug.isOn("codebase=");
dumpDebug &= !Debug.isOn("permission=") ||
Debug.isOn("permission=" + perm.getClass().getCanonicalName());
}
if (dumpDebug && Debug.isOn("stack")) {
Thread.dumpStack();
}
if (dumpDebug && Debug.isOn("domain")) {
debug.println("domain (context is null)");
}
if (dumpDebug) {
debug.println("access allowed "+perm);
}
return;
}
AccessControlContext acc = stack.optimize();
acc.checkPermission(perm);
}
}
getStackAccessControlContext
/**
返回访问AccessControl上下文。即,它获取堆栈上所有调用者的保护域,从具有非空保护域的第一个类开始。
*
* @return the access control context based on the current stack or
*
null if there was only privileged system code.
*/
private static native AccessControlContext getStackAccessControlContext();
Java_java_security_AccessController_getStackAccessControlContext
JNIEXPORT jobject JNICALL
Java_java_security_AccessController_getStackAccessControlContext(
JNIEnv *env,
jobject this)
{
return JVM_GetStackAccessControlContext(env, this);
}
JVM_GetStackAccessControlContext
JVM_ENTRY(jobject, JVM_GetStackAccessControlContext(JNIEnv *env, jclass cls))
JVMWrapper("JVM_GetStackAccessControlContext");
if (!UsePrivilegedStack) return NULL;
ResourceMark rm(THREAD);
GrowableArray<oop>* local_array = new GrowableArray<oop>(12);
JvmtiVMObjectAllocEventCollector oam;
// count the protection domains on the execution stack. We collapse
// duplicate consecutive protection domains into a single one, as
// well as stopping when we hit a privileged frame.
// Use vframeStream to iterate through Java frames
vframeStream vfst(thread);
oop previous_protection_domain = NULL;
Handle privileged_context(thread, NULL);
bool is_privileged = false;
oop protection_domain = NULL;
for(; !vfst.at_end(); vfst.next()) {
// get method of frame
Method* method = vfst.method();
intptr_t* frame_id
= vfst.frame_id();
// check the privileged frames to see if we have a match
if (thread->privileged_stack_top() && thread->privileged_stack_top()->frame_id() == frame_id) {
// this frame is privileged
is_privileged = true;
privileged_context = Handle(thread, thread->privileged_stack_top()->privileged_context());
protection_domain
= thread->privileged_stack_top()->protection_domain();
} else {
protection_domain = method->method_holder()->protection_domain();
}
if ((previous_protection_domain != protection_domain) && (protection_domain != NULL)) {
local_array->push(protection_domain);
previous_protection_domain = protection_domain;
}
if (is_privileged) break;
}
// either all the domains on the stack were system domains, or
// we had a privileged system domain
if (local_array->is_empty()) {
if (is_privileged && privileged_context.is_null()) return NULL;
oop result = java_security_AccessControlContext::create(objArrayHandle(), is_privileged, privileged_context, CHECK_NULL);
return JNIHandles::make_local(env, result);
}
// the resource area must be registered in case of a gc
RegisterArrayForGC ragc(thread, local_array);
objArrayOop context = oopFactory::new_objArray(SystemDictionary::ProtectionDomain_klass(),
local_array->length(), CHECK_NULL);
objArrayHandle h_context(thread, context);
for (int index = 0; index < local_array->length(); index++) {
h_context->obj_at_put(index, local_array->at(index));
}
oop result = java_security_AccessControlContext::create(h_context, is_privileged, privileged_context, CHECK_NULL);
return JNIHandles::make_local(env, result);
JVM_END
doPrivileged
/**
在启用权限的情况下执行指定的 {@code PrivilegedAction}。
使用调用者的保护域拥有的<i>all<i>权限执行该操作。
*
<p> 如果操作的 {@code run} 方法抛出(未经检查的)异常,它将通过此方法传播。
*
<p> 请注意,在执行操作时,与当前 AccessControlContext 关联的任何 DomainCombiner 都将被忽略。
*
* @param <T> the type of the value returned by the PrivilegedAction's
*
{@code run} method.
*
* @param action the action to be performed.
*
* @return the value returned by the action's {@code run} method.
*
* @exception NullPointerException if the action is {@code null}
*
* @see #doPrivileged(PrivilegedAction,AccessControlContext)
* @see #doPrivileged(PrivilegedExceptionAction)
* @see #doPrivilegedWithCombiner(PrivilegedAction)
* @see java.security.DomainCombiner
*/
@CallerSensitive
public static native <T> T doPrivileged(PrivilegedAction<T> action);
isOn
private static String args = (String)AccessController.doPrivileged(new GetPropertyAction("java.security.debug"));
public static boolean isOn(String var0) {
if (args == null) {
return false;
} else if (args.indexOf("all") != -1) {
return true;
} else {
return args.indexOf(var0) != -1;
}
}
JVM_DoPrivileged
JVM_ENTRY(jobject, JVM_DoPrivileged(JNIEnv *env, jclass cls, jobject action, jobject context, jboolean wrapException))
JVMWrapper("JVM_DoPrivileged");
if (action == NULL) {
THROW_MSG_0(vmSymbols::java_lang_NullPointerException(), "Null action");
}
// Compute the frame initiating the do privileged operation and setup the privileged stack
vframeStream vfst(thread);
vfst.security_get_caller_frame(1);
if (vfst.at_end()) {
THROW_MSG_0(vmSymbols::java_lang_InternalError(), "no caller?");
}
Method* method
= vfst.method();
instanceKlassHandle klass (THREAD, method->method_holder());
// Check that action object understands "Object run()"
Handle h_context;
if (context != NULL) {
h_context = Handle(THREAD, JNIHandles::resolve(context));
bool authorized = is_authorized(h_context, klass, CHECK_NULL);
if (!authorized) {
// Create an unprivileged access control object and call it's run function
// instead.
oop noprivs = create_dummy_access_control_context(CHECK_NULL);
h_context = Handle(THREAD, noprivs);
}
}
// Check that action object understands "Object run()"
Handle object (THREAD, JNIHandles::resolve(action));
// get run() method
Method* m_oop = object->klass()->uncached_lookup_method(
vmSymbols::run_method_name(),
vmSymbols::void_object_signature(),
Klass::find_overpass);
methodHandle m (THREAD, m_oop);
if (m.is_null() || !m->is_method() || !m()->is_public() || m()->is_static()) {
THROW_MSG_0(vmSymbols::java_lang_InternalError(), "No run method");
}
// Stack allocated list of privileged stack elements
PrivilegedElement pi;
if (!vfst.at_end()) {
pi.initialize(&vfst, h_context(), thread->privileged_stack_top(), CHECK_NULL);
thread->set_privileged_stack_top(&pi);
}
// invoke the Object run() in the action object. We cannot use call_interface here, since the static type
// is not really known - it is either java.security.PrivilegedAction or java.security.PrivilegedExceptionAction
Handle pending_exception;
JavaValue result(T_OBJECT);
JavaCallArguments args(object);
JavaCalls::call(&result, m, &args, THREAD);
// done with action, remove ourselves from the list
if (!vfst.at_end()) {
assert(thread->privileged_stack_top() != NULL && thread->privileged_stack_top() == &pi, "wrong top element");
thread->set_privileged_stack_top(thread->privileged_stack_top()->next());
}
if (HAS_PENDING_EXCEPTION) {
pending_exception = Handle(THREAD, PENDING_EXCEPTION);
CLEAR_PENDING_EXCEPTION;
// JVMTI has already reported the pending exception
// JVMTI internal flag reset is needed in order to report PrivilegedActionException
if (THREAD->is_Java_thread()) {
JvmtiExport::clear_detected_exception((JavaThread*) THREAD);
}
if ( pending_exception->is_a(SystemDictionary::Exception_klass()) &&
!pending_exception->is_a(SystemDictionary::RuntimeException_klass())) {
// Throw a java.security.PrivilegedActionException(Exception e) exception
JavaCallArguments args(pending_exception);
THROW_ARG_0(vmSymbols::java_security_PrivilegedActionException(),
vmSymbols::exception_void_signature(),
&args);
}
}
if (pending_exception.not_null()) THROW_OOP_0(pending_exception());
return JNIHandles::make_local(env, (oop) result.get_jobject());
JVM_END
最后
以上就是俊秀哈密瓜为你收集整理的System源码浅析- initializeSystemClass(loadLibrary)的全部内容,希望文章能够帮你解决System源码浅析- initializeSystemClass(loadLibrary)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复