首页 > 编程知识 正文

编译原理语法分析器源码,线程池源码分析

时间:2023-05-04 12:00:34 阅读:246390 作者:4945

前言

本文介绍System.loadLibrary原理。

Java层源码流程

System#loadLibrary
-> Runtime#loadLibrary0
–> BaseDexClassLoader#findLibrary
–> DexPathList#findNativeLibrary
->Runtime#nativeLoad,走向c层源码

主要是从nativeLibraryPathElements中找到so路径,遍历所有路径找到存在的so,不存在则抛出UnsatisfiedLinkError。在c层进行打开so逻辑,如果c层返回false,就会拼接error字符串,Java层收到后也会抛出UnsatisfiedLinkError。
可以通过反射打印下nativeLibraryPathElements,以更好的理解这块代码 Field pathListF = BaseDexClassLoader.class.getDeclaredField("pathList"); pathListF.setAccessible(true); ClassLoader dexPathClassLoader = TestSocketFragment.class.getClassLoader(); Object pathList = pathListF.get(dexPathClassLoader); Field nativeLibraryPathElementsF = Class.forName("dalvik.system.DexPathList").getDeclaredField("nativeLibraryPathElements"); nativeLibraryPathElementsF.setAccessible(true); Object nativeLibraryPathElements = nativeLibraryPathElementsF.get(pathList); android.util.Log.e("mLogU", nativeLibraryPathElements.toString()); Object[] arr = (Object[]) nativeLibraryPathElements; for (Object o : arr) { android.util.Log.e("mLogU", o.toString()); } native层源码流程

从c层加载so,返回false就会在Java层抛出UnsatisfiedLinkError,流程如下:

-> nativeLoad
->libcore/ojluni/src/main/native/Runtime.c#Runtime_nativeLoad
->art/openjdkjvm/OpenjdkJvm.cc#JVM_NativeLoad
->art/runtime/jni/java_vm_ext.cc#LoadNativeLibrary
–>art/libnativeloader/native_loader.cpp#OpenNativeLibrary

bool JavaVMExt::LoadNativeLibrary(JNIEnv* env, const std::string& path, jobject class_loader, std::string* error_msg) { error_msg->clear(); /* * 1. 从缓存中获取该library, * 2. 如果存在则比较classLoader是否相同,如果相同则返回成功。不同则返回失败。 * 3. 不存在则进行加载,并放入缓存中 */ SharedLibrary* library; Thread* self = Thread::Current(); { MutexLock mu(self, *Locks::jni_libraries_lock_); library = libraries_->Get(path); } void* class_loader_allocator = nullptr; { ScopedObjectAccess soa(env); ObjPtr<mirror::ClassLoader> loader = soa.Decode<mirror::ClassLoader>(class_loader); ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); if (class_linker->IsBootClassLoader(soa, loader.Ptr())) { loader = nullptr; class_loader = nullptr; } // 获取当前classloader的Allocator class_loader_allocator = class_linker->GetAllocatorForClassLoader(loader.Ptr()); CHECK(class_loader_allocator != nullptr); } /* * The JNI spec says we can't load the same library into more than one class loader. * JNI规范要求不能加载相同库到同一个classLoader中 */ if (library != nullptr) { // Use the allocator pointers for class loader equality to avoid unnecessary weak root decode. if (library->GetClassLoaderAllocator() != class_loader_allocator) { // .... 拼接一大堆str return false; } // 已经加载过了,问题不大 if (!library->CheckOnLoadResult()) { return false; } return true; } // android_dlopen_ext该库,并返回句柄(指针) void* handle = android::OpenNativeLibrary(env, runtime_->GetTargetSdkVersion(), path_str, class_loader, library_path.get(), &needs_native_bridge, error_msg); if (handle == nullptr) { // 打开失败 return false; } bool created_library = false; { std::unique_ptr<SharedLibrary> new_library( new SharedLibrary(env, self, path, handle, needs_native_bridge, class_loader, class_loader_allocator)); MutexLock mu(self, *Locks::jni_libraries_lock_); library = libraries_->Get(path); if (library == nullptr) { // We won race to get libraries_lock. library = new_library.release(); // 放入缓存 libraries_->Put(path, library); created_library = true; } } if (!created_library) { return library->CheckOnLoadResult(); } /* * 加载成功,dlsym获取JNI_OnLoad句柄,并调用JNI_OnLoad方法,根据返回值判断设置是否加载成功 */ bool was_successful = false; void* sym = library->FindSymbol("JNI_OnLoad", nullptr); if (sym == nullptr) { was_successful = true; } else { JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym); int version = (*jni_on_load)(this, nullptr); if (version == JNI_ERR) { StringAppendF(error_msg, "JNI_ERR returned from JNI_OnLoad in "%s"", path.c_str()); } else if (JavaVMExt::IsBadJniVersion(version)) { StringAppendF(error_msg, "Bad JNI version returned from JNI_OnLoad in "%s": %d", path.c_str(), version); } else { was_successful = true; } } library->SetResult(was_successful); return was_successful;} 结语

从源码可以看出System#loadLibrary在正常情况下只会调用一次JNI_OnLoad方法;
其中SharedLibrary在析构函数里会调用dlclose关闭该库;
并且从官方文档JNI tips可以看出一般放在静态代码块里加载so,该so生命周期绑定class生命周期。
本文梳理了System#loadLibrary源码流程,若有错误敬请指正。

margin

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。