| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 
 | java_vm_ext.cc
 bool JavaVMExt::LoadNativeLibrary(JNIEnv* env, const std::string& path, jobject class_loader,
 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.
 // TODO: for better results we should canonicalize the pathname (or even compare
 // inodes). This implementation is fine if everybody is using System.loadLibrary.
 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);
 }
 if (library != nullptr) {
 if (env->IsSameObject(library->GetClassLoader(), class_loader) == JNI_FALSE) {
 // The library will be associated with class_loader. The JNI
 // spec says we can't load the same library into more than one
 // class loader.
 StringAppendF(error_msg, "Shared library \"%s\" already opened by "
 "ClassLoader %p; can't open in ClassLoader %p",
 path.c_str(), library->GetClassLoader(), class_loader);
 LOG(WARNING) << error_msg;
 return false;
 }
 VLOG(jni) << "[Shared library \"" << path << "\" already loaded in "
 << " ClassLoader " << class_loader << "]";
 if (!library->CheckOnLoadResult()) {
 StringAppendF(error_msg, "JNI_OnLoad failed on a previous attempt "
 "to load \"%s\"", path.c_str());
 return false;
 }
 return true;
 }
 
 // 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.
 
 Locks::mutator_lock_->AssertNotHeld(self);
 const char* path_str = path.empty() ? nullptr : path.c_str();
 void* handle = dlopen(path_str, RTLD_NOW);
 bool needs_native_bridge = false;
 if (handle == nullptr) {
 if (android::NativeBridgeIsSupported(path_str)) {
 handle = android::NativeBridgeLoadLibrary(path_str, RTLD_NOW);
 needs_native_bridge = true;
 }
 }
 
 VLOG(jni) << "[Call to dlopen(\"" << path << "\", RTLD_NOW) returned " << handle << "]";
 
 if (handle == nullptr) {
 *error_msg = dlerror();
 VLOG(jni) << "dlopen(\"" << path << "\", RTLD_NOW) failed: " << *error_msg;
 return false;
 }
 
 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, class_loader));
 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;
 if (needs_native_bridge) {
 library->SetNeedsNativeBridge();
 sym = library->FindSymbolWithNativeBridge("JNI_OnLoad", nullptr);
 } else {
 sym = dlsym(handle, "JNI_OnLoad");
 }
 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 << "\"]";
 typedef int (*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) {
 fault_manager.EnsureArtActionInFrontOfSignalChain();
 }
 
 self->SetClassLoaderOverride(old_class_loader.get());
 
 if (version == JNI_ERR) {
 StringAppendF(error_msg, "JNI_ERR returned from JNI_OnLoad in \"%s\"", path.c_str());
 } else if (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;
 }
 
 |