privatestatic String[] initLibPaths() { StringjavaLibraryPath= System.getProperty("java.library.path"); if (javaLibraryPath == null) { return EmptyArray.STRING; } String[] paths = javaLibraryPath.split(":"); // Add a '/' to the end of each directory so we don't have to do it every time. for (inti=0; i < paths.length; ++i) { if (!paths[i].endsWith("/")) { paths[i] += "/"; } } return paths; }
loadLibrary0 在加载 so 时,先判断 loader 是否为 null 。如果不为 null,就通过 loader 去找到 so 的绝对路径,然后再加载。如果为 null,就从 /system/lib64/ 中去找是否存在要加载的 so 。如果都没有找到就抛出异常。
// Don't let a pending exception from JNI_OnLoad cause a CheckJNI issue with NewStringUTF. env->ExceptionClear(); return env->NewStringUTF(error_msg.c_str()); }
// Open the shared library. Because we're using a full path, the system // doesn't have to search through LD_LIBRARY_PATH. (It may do so to // resolve this library's dependencies though.)
// Failures here are expected when java.library.path has several entries // and we have to hunt for the lib.
// Below we dlopen but there is no paired dlclose, this would be necessary if we supported // class unloading. Libraries will only be unloaded when the reference count (incremented by // dlopen) becomes zero from dlclose.
// Retrieve the library path from the classloader, if necessary. ScopedLocalRef<jstring> library_path(env, GetLibrarySearchPath(env, class_loader));
if (env->ExceptionCheck() == JNI_TRUE) { LOG(ERROR) << "Unexpected exception:"; env->ExceptionDescribe(); env->ExceptionClear(); } // Create a new entry. // TODO: move the locking (and more of this logic) into Libraries. bool created_library = false; { // Create SharedLibrary ahead of taking the libraries lock to maintain lock ordering. 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) { LOG(INFO) << "WOW: we lost a race to add shared library: " << "\"" << path << "\" ClassLoader=" << class_loader; return library->CheckOnLoadResult(); } VLOG(jni) << "[Added shared library \"" << path << "\" for ClassLoader " << class_loader << "]";
bool was_successful = false; void* sym = library->FindSymbol("JNI_OnLoad", nullptr); if (sym == nullptr) { VLOG(jni) << "[No JNI_OnLoad found in \"" << path << "\"]"; was_successful = true; } else { // Call JNI_OnLoad. We have to override the current class // loader, which will always be "null" since the stuff at the // top of the stack is around Runtime.loadLibrary(). (See // the comments in the JNI FindClass function.) ScopedLocalRef<jobject> old_class_loader(env, env->NewLocalRef(self->GetClassLoaderOverride())); self->SetClassLoaderOverride(class_loader);
VLOG(jni) << "[Calling JNI_OnLoad in \"" << path << "\"]"; typedefint(*JNI_OnLoadFn)(JavaVM*, void*); JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym); int version = (*jni_on_load)(this, nullptr);
if (runtime_->GetTargetSdkVersion() != 0 && runtime_->GetTargetSdkVersion() <= 21) { // Make sure that sigchain owns SIGSEGV. EnsureFrontOfChain(SIGSEGV); }
if (version == JNI_ERR) { StringAppendF(error_msg, "JNI_ERR returned from JNI_OnLoad in \"%s\"", path.c_str()); } elseif (JavaVMExt::IsBadJniVersion(version)) { StringAppendF(error_msg, "Bad JNI version returned from JNI_OnLoad in \"%s\": %d", path.c_str(), version); // It's unwise to call dlclose() here, but we can mark it // as bad and ensure that future load attempts will fail. // We don't know how far JNI_OnLoad got, so there could // be some partially-initialized stuff accessible through // newly-registered native method calls. We could try to // unregister them, but that doesn't seem worthwhile. } else { was_successful = true; } VLOG(jni) << "[Returned " << (was_successful ? "successfully" : "failure") << " from JNI_OnLoad in \"" << path << "\"]"; }
// No mutator lock since dlsym may block for a while if another thread is doing dlopen. void* FindSymbol(conststd::string& symbol_name, constchar* shorty = nullptr) REQUIRES(!Locks::mutator_lock_) { return NeedsNativeBridge() ? FindSymbolWithNativeBridge(symbol_name.c_str(), shorty) : FindSymbolWithoutNativeBridge(symbol_name.c_str()); }
// No mutator lock since dlsym may block for a while if another thread is doing dlopen. void* FindSymbolWithoutNativeBridge(conststd::string& symbol_name) REQUIRES(!Locks::mutator_lock_) { CHECK(!NeedsNativeBridge());