// 当 loader 为 null 时执行如下操作 // We know some apps use mLibPaths directly, potentially assuming it's not null. // Initialize it here to make sure apps see a non-null value. getLibPaths();// 获取 mLibPaths 值: /system/lib64/ // mapLibraryName 功能是将动态库 xxx 的名字转换为 libxxx.so,见 1.1.4 Stringfilename= System.mapLibraryName(libraryName); // 真正加载库的函数 nativeLoad Stringerror= nativeLoad(filename, loader, callerClass); if (error != null) { thrownewUnsatisfiedLinkError(error); } } privatevolatile String[] mLibPaths = null; private String[] getLibPaths() { if (mLibPaths == null) { synchronized(this) { if (mLibPaths == null) { mLibPaths = initLibPaths(); } } } return mLibPaths; }
privatestatic String[] initLibPaths() { // java.library.path = /system/lib64 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; }
if (zipDir == null) { StringentryPath=newFile(path, name).getPath(); if (IoUtils.canOpenReadOnly(entryPath)) { return entryPath; } } elseif (urlHandler != null) { // Having a urlHandler means the element has a zip file. // In this case Android supports loading the library iff // it is stored in the zip uncompressed. StringentryName= zipDir + '/' + name; if (urlHandler.isEntryStored(entryName)) { return path.getPath() + zipSeparator + entryName; } }
boolJavaVMExt::LoadNativeLibrary(JNIEnv* env, conststd::string& path, jobject class_loader, jclass caller_class, std::string* error_msg) { error_msg->clear(); // See if we've already loaded this library. If we have, and the class loader // matches, return successfully without doing anything. // 判断是否已经加载过这个库,如果加载过直接返回 SharedLibrary* library; Thread* self = Thread::Current(); { // TODO: move the locking (and more of this logic) into Libraries. MutexLock mu(self, *Locks::jni_libraries_lock_); library = libraries_->Get(path); } ... ... // 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)); Locks::mutator_lock_->AssertNotHeld(self); constchar* path_str = path.empty() ? nullptr : path.c_str(); bool needs_native_bridge = false; char* nativeloader_error_msg = nullptr; // 通过 OpenNativeLibrary 加载,旧版本中通过 dlopen void* handle = android::OpenNativeLibrary( env, runtime_->GetTargetSdkVersion(), path_str, class_loader, (caller_location.empty() ? nullptr : caller_location.c_str()), library_path.get(), &needs_native_bridge, &nativeloader_error_msg); VLOG(jni) << "[Call to dlopen(\"" << path << "\", RTLD_NOW) returned " << handle << "]"; if (handle == nullptr) { // 加载失败 *error_msg = nativeloader_error_msg; android::NativeLoaderFreeErrorMessage(nativeloader_error_msg); VLOG(jni) << "dlopen(\"" << path << "\", RTLD_NOW) failed: " << *error_msg; returnfalse; } 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; } } ... ... 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 << "\"]"; using JNI_OnLoadFn = int(*)(JavaVM*, void*); JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym); int version = (*jni_on_load)(this, nullptr); if (IsSdkVersionSetAndAtMost(runtime_->GetTargetSdkVersion(), SdkVersion::kL)) { // Make sure that sigchain owns SIGSEGV. EnsureFrontOfChain(SIGSEGV); } self->SetClassLoaderOverride(old_class_loader.get()); 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 << "\"]"; } library->SetResult(was_successful); return was_successful; }