Android JNI之System.loadLibrary()流程

来源:互联网 发布:java遍历jsonobject 编辑:程序博客网 时间:2024/05/17 08:13

文档目的

JNI全称Java Native Interface,相当于java语言和C/C++语言打交道的桥梁。主要是用来在java语言中加载lib库。然后就可以在java中使用native中定义的方法。

用法如下:

[java] view plain copy
  1. static {  
  2.     System.loadLibrary("TestJni");  
  3. }  
  4. private static native String getResult();  

本文主要来跟踪一下System.loadLibrary的调用流程,不对jni文件实现做探究。


Library查找过程

以Android N代码为例,System.loadLibrary源码位于:

./libcore/ojluni/src/main/java/java/lang/System.java

[java] view plain copy
  1. /** 
  2.  * Loads the system library specified by the <code>libname</code> 
  3.  * argument. The manner in which a library name is mapped to the 
  4.  * actual system library is system dependent. 
  5.  * <p> 
  6.  * The call <code>System.loadLibrary(name)</code> is effectively 
  7.  * equivalent to the call 
  8.  * <blockquote><pre> 
  9.  * Runtime.getRuntime().loadLibrary(name) 
  10.  * </pre></blockquote> 
  11.  * 
  12.  * @param      libname   the name of the library. 
  13.  * @exception  SecurityException  if a security manager exists and its 
  14.  *             <code>checkLink</code> method doesn't allow 
  15.  *             loading of the specified dynamic library 
  16.  * @exception  UnsatisfiedLinkError  if the library does not exist. 
  17.  * @exception  NullPointerException if <code>libname</code> is 
  18.  *             <code>null</code> 
  19.  * @see        java.lang.Runtime#loadLibrary(java.lang.String) 
  20.  * @see        java.lang.SecurityManager#checkLink(java.lang.String) 
  21.  */  
  22. public static void loadLibrary(String libname) {  
  23.     Runtime.getRuntime().loadLibrary0(VMStack.getCallingClassLoader(), libname);  
  24. }  

可以看到然后又调用了Runtime.java的loadLibrary0方法:

./libcore/ojluni/src/main/java/java/lang/Runtime.java

[java] view plain copy
  1. synchronized void loadLibrary0(ClassLoader loader, String libname) {  
  2.     if (libname.indexOf((int)File.separatorChar) != -1) {  
  3.         throw new UnsatisfiedLinkError(  
  4. "Directory separator should not appear in library name: " + libname);  
  5.     }  
  6.     String libraryName = libname;  
  7.     if (loader != null) {  
  8.         String filename = loader.findLibrary(libraryName);  
  9.         if (filename == null) {  
  10.             // It's not necessarily true that the ClassLoader used  
  11.             // System.mapLibraryName, but the default setup does, and it's  
  12.             // misleading to say we didn't find "libMyLibrary.so" when we  
  13.             // actually searched for "liblibMyLibrary.so.so".  
  14.             throw new UnsatisfiedLinkError(loader + " couldn't find \"" +  
  15.                                            System.mapLibraryName(libraryName) + "\"");  
  16.         }  
  17.         String error = doLoad(filename, loader);  
  18.         if (error != null) {  
  19.             throw new UnsatisfiedLinkError(error);  
  20.         }  
  21.         return;  
  22.     }  
  23.   
  24.     String filename = System.mapLibraryName(libraryName);  
  25.     List<String> candidates = new ArrayList<String>();  
  26.     String lastError = null;  
  27.     for (String directory : getLibPaths()) {  
  28.         String candidate = directory + filename;  
  29.         candidates.add(candidate);  
  30.   
  31.         if (IoUtils.canOpenReadOnly(candidate)) {  
  32.             String error = doLoad(candidate, loader);  
  33.             if (error == null) {  
  34.                 return// We successfully loaded the library. Job done.  
  35.             }  
  36.             lastError = error;  
  37.         }  
  38.     }  
  39.   
  40.     if (lastError != null) {  
  41.         throw new UnsatisfiedLinkError(lastError);  
  42.     }  
  43.     throw new UnsatisfiedLinkError("Library " + libraryName + " not found; tried " + candidates);  
  44. }  

这个方法主要有两个作用:

    1. 找到lib的全称

    2. 调用doLoad加载lib库

首先会判断loader 不为空来执行上面两步,如果为空,则换个方法继续执行上面两步。

这个方法的第一个参数是ClassLoader,是获取系统的loader,一般情况下这个值不会为空,是通过ContextImpl.java中的getClassLoader来生成的,且实例化为PathClassLoader。PathClassLoader继承BaseDexClassLoader,BaseDexClassLoader继承ClassLoader。

所以loader.findLibrary(libraryName)最终是调用BaseDexClassLoader中的findLibrary。

代码位于:./libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java

[java] view plain copy
  1. @Override  
  2. public String findLibrary(String name) {  
  3.     return pathList.findLibrary(name);  
  4. }  

其中pathList是一个DexPathList对象,位于./libcore/dalvik/src/main/java/dalvik/system/DexPathList.java:

[java] view plain copy
  1. /** 
  2.  * Finds the named native code library on any of the library 
  3.  * directories pointed at by this instance. This will find the 
  4.  * one in the earliest listed directory, ignoring any that are not 
  5.  * readable regular files. 
  6.  * 
  7.  * @return the complete path to the library or {@code null} if no 
  8.  * library was found 
  9.  */  
  10. public String findLibrary(String libraryName) {  
  11.     String fileName = System.mapLibraryName(libraryName);  
  12.   
  13.     for (Element element : nativeLibraryPathElements) {  
  14.         String path = element.findNativeLibrary(fileName);  
  15.   
  16.         if (path != null) {  
  17.             return path;  
  18.         }  
  19.     }  
  20.   
  21.     return null;  
  22. }  

可以看到这里会先调用System.java中的mapLibraryName方法来对libraryName做处理,这是一个native方法,在System.c中实现:

./libcore/ojluni/src/main/native/System.c

[cpp] view plain copy
  1. JNIEXPORT jstring JNICALL  
  2. System_mapLibraryName(JNIEnv *env, jclass ign, jstring libname)  
  3. {  
  4.     int len;  
  5.     int prefix_len = (int) strlen(JNI_LIB_PREFIX);  
  6.     int suffix_len = (int) strlen(JNI_LIB_SUFFIX);  
  7.     
  8.     jchar chars[256];  
  9.     if (libname == NULL) {  
  10.         JNU_ThrowNullPointerException(env, 0);  
  11.         return NULL;  
  12.     }  
  13.     len = (*env)->GetStringLength(env, libname);  
  14.     if (len > 240) {  
  15.         JNU_ThrowIllegalArgumentException(env, "name too long");  
  16.         return NULL;  
  17.     }  
  18.     cpchars(chars, JNI_LIB_PREFIX, prefix_len);  
  19.     (*env)->GetStringRegion(env, libname, 0, len, chars + prefix_len);  
  20.     len += prefix_len;  
  21.     cpchars(chars + len, JNI_LIB_SUFFIX, suffix_len);  
  22.     len += suffix_len;  
  23.     
  24.     return (*env)->NewString(env, chars, len);  
  25. }  

这个方法主要目的是给传进来的name添加前缀lib和后缀.so,最开始我们传进来的name是TestJni,所以此处处理后返回的是libTestJni.so.

接下来使用for循环对nativeLibraryPathElements调用findNativeLibrary方法。我们先看一下nativeLibraryPathElements是在哪里赋值的。在DexPathList的构造函数中:

[java] view plain copy
  1. public DexPathList(ClassLoader definingContext, String dexPath,  
  2.         String librarySearchPath, File optimizedDirectory) {  
  3.   
  4.     if (definingContext == null) {  
  5.         throw new NullPointerException("definingContext == null");  
  6.     }  
  7.   
  8.     if (dexPath == null) {  
  9.         throw new NullPointerException("dexPath == null");  
  10.     }  
  11.   
  12.     if (optimizedDirectory != null) {  
  13.         if (!optimizedDirectory.exists())  {  
  14.             throw new IllegalArgumentException(  
  15.                     "optimizedDirectory doesn't exist: "  
  16.                     + optimizedDirectory);  
  17.         }  
  18.   
  19.         if (!(optimizedDirectory.canRead()  
  20.                         && optimizedDirectory.canWrite())) {  
  21.             throw new IllegalArgumentException(  
  22.                     "optimizedDirectory not readable/writable: "  
  23.                     + optimizedDirectory);  
  24.         }  
  25.     }  
  26.   
  27.     this.definingContext = definingContext;  
  28.   
  29.     ArrayList<IOException> suppressedExceptions = new ArrayList<IOException>();  
  30.     // save dexPath for BaseDexClassLoader  
  31.     this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,  
  32.                                        suppressedExceptions, definingContext);  
  33.   
  34.     // Native libraries may exist in both the system and  
  35.     // application library paths, and we use this search order:  
  36.     //  
  37.     //   1. This class loader's library path for application libraries (librarySearchPath):  
  38.     //   1.1. Native library directories  
  39.     //   1.2. Path to libraries in apk-files  
  40.     //   2. The VM's library path from the system property for system libraries  
  41.     //      also known as java.library.path  
  42.     //  
  43.     // This order was reversed prior to Gingerbread; see http://b/2933456.  
  44.     this.nativeLibraryDirectories = splitPaths(librarySearchPath, false);  
  45.     this.systemNativeLibraryDirectories =  
  46.             splitPaths(System.getProperty("java.library.path"), true);  
  47.     List<File> allNativeLibraryDirectories = new ArrayList<>(nativeLibraryDirectories);  
  48.     allNativeLibraryDirectories.addAll(systemNativeLibraryDirectories);  
  49.   
  50.     this.nativeLibraryPathElements = makePathElements(allNativeLibraryDirectories,  
  51.                                                       suppressedExceptions,  
  52.                                                       definingContext);  
  53.   
  54.     if (suppressedExceptions.size() > 0) {  
  55.         this.dexElementsSuppressedExceptions =  
  56.             suppressedExceptions.toArray(new IOException[suppressedExceptions.size()]);  
  57.     } else {  
  58.         dexElementsSuppressedExceptions = null;  
  59.     }  
  60. }  

上述第44~50行代码就是nativeLibraryPathElements赋值的地方。

此处nativeLibraryPathElements依赖allNativeLibraryDirectories并通过makePathElements方法生成。

allNativeLibraryDirectories是一个list,由nativeLibraryDirectories和systemNativeLibraryDirectories组成。

librarySearchPath是由LoadedApk.java中createOrUpdateClassLoaderLocked方法中赋值的:

./frameworks/base/core/java/android/app/LoadedApk.java

[java] view plain copy
  1. final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);  

然后在ApplicationLoaders中实例化PathClassLoader时传递过去。在一般的app中类似于如下目录:

[java] view plain copy
  1. /data/app/com.example.testjni-1/lib/arm64  

systemNativeLibraryDirectories是从系统java属性java.library.path中获取。Java.library.path这个值是在System.c的System_specialProperties方法中调用系统内核方法android_get_LD_LIBRARY_PATH赋值的。

android_get_LD_LIBRARY_PATH最终是在系统内核源码./bionic/linker/linker.cpp中实现:

[cpp] view plain copy
  1. void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {  
  2.   // Use basic string manipulation calls to avoid snprintf.  
  3.   // snprintf indirectly calls pthread_getspecific to get the size of a buffer.  
  4.   // When debug malloc is enabled, this call returns 0. This in turn causes  
  5.   // snprintf to do nothing, which causes libraries to fail to load.  
  6.   // See b/17302493 for further details.  
  7.   // Once the above bug is fixed, this code can be modified to use  
  8.   // snprintf again.  
  9.   size_t required_len = 0;  
  10.   for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {  
  11.     required_len += strlen(g_default_ld_paths[i]) + 1;  
  12.   }  
  13.   if (buffer_size < required_len) {  
  14.     __libc_fatal("android_get_LD_LIBRARY_PATH failed, buffer too small: "  
  15.                  "buffer len %zu, required len %zu", buffer_size, required_len);  
  16.   }  
  17.   char* end = buffer;  
  18.   for (size_t i = 0; g_default_ld_paths[i] != nullptr; ++i) {  
  19.     if (i > 0) *end++ = ':';  
  20.     end = stpcpy(end, g_default_ld_paths[i]);  
  21.   }  
  22. }  

g_default_ld_paths在init_default_namespace的时候被赋值:

[cpp] view plain copy
  1. if (bname && (strcmp(bname, "linker_asan") == 0 || strcmp(bname, "linker_asan64") == 0)) {  
  2.   g_default_ld_paths = kAsanDefaultLdPaths;  
  3. else {  
  4.   g_default_ld_paths = kDefaultLdPaths;  
  5. }  


[cpp] view plain copy
  1. static const charconst kDefaultLdPaths[] = {  
  2. #if defined(__LP64__)  
  3.   "/system/lib64",  
  4.   "/vendor/lib64",  
  5. #else  
  6.   "/system/lib",  
  7.   "/vendor/lib",  
  8. #endif  
  9.   nullptr  
  10. };  

所以systemNativeLibraryDirectories得值为 /system/lib64:/vendor/lib64

再返回到DexPathList的findLibrary方法,查看for循环,调用Element的findNativeLibrary方法查找fileName是否存在且可读,返回第一个存在且可读的path。

总结一下loadLibrary0的第一步,主要是调用loader.findLibrary(libraryName)完成以下任务:

    1) 调用System.mapLibraryName(libraryName)拼接处完整的lib名字

    2) 在下述3个路径查找lib库是否存在并返回第一个可读的文件路径:

        /data/app/com.example.testjni-1/lib/arm64

        /vendor/lib64

        /system/lib64

 

Library加载过程

如果lib库的路径不为空,接下来就调用doLoad进行下载。我们看下doLoad方法:

[cpp] view plain copy
  1. private String doLoad(String name, ClassLoader loader) {  
  2.     // Android apps are forked from the zygote, so they can't have a custom LD_LIBRARY_PATH,  
  3.     // which means that by default an app's shared library directory isn't on LD_LIBRARY_PATH.  
  4.   
  5.     // The PathClassLoader set up by frameworks/base knows the appropriate path, so we can load  
  6.     // libraries with no dependencies just fine, but an app that has multiple libraries that  
  7.     // depend on each other needed to load them in most-dependent-first order.  
  8.   
  9.     // We added API to Android's dynamic linker so we can update the library path used for  
  10.     // the currently-running process. We pull the desired path out of the ClassLoader here  
  11.     // and pass it to nativeLoad so that it can call the private dynamic linker API.  
  12.   
  13.     // We didn't just change frameworks/base to update the LD_LIBRARY_PATH once at the  
  14.     // beginning because multiple apks can run in the same process and third party code can  
  15.     // use its own BaseDexClassLoader.  
  16.   
  17.     // We didn't just add a dlopen_with_custom_LD_LIBRARY_PATH call because we wanted any  
  18.     // dlopen(3) calls made from a .so's JNI_OnLoad to work too.  
  19.   
  20.     // So, find out what the native library search path is for the ClassLoader in question...  
  21.     String librarySearchPath = null;  
  22.     if (loader != null && loader instanceof BaseDexClassLoader) {  
  23.         BaseDexClassLoader dexClassLoader = (BaseDexClassLoader) loader;  
  24.         librarySearchPath = dexClassLoader.getLdLibraryPath();  
  25.     }  
  26.     // nativeLoad should be synchronized so there's only one LD_LIBRARY_PATH in use regardless  
  27.     // of how many ClassLoaders are in the system, but dalvik doesn't support synchronized  
  28.     // internal natives.  
  29.     synchronized (this) {  
  30.         return nativeLoad(name, loader, librarySearchPath);  
  31.     }  
  32. }  

此处主要是先获取librarySearchPath,然后调用nativeLoad加载。

nativeLoad实现在libcore/ojluni/src/main/native/Runtime.c中:

[cpp] view plain copy
  1. JNIEXPORT jstring JNICALL  
  2. Runtime_nativeLoad(JNIEnv* env, jclass ignored, jstring javaFilename,  
  3.                    jobject javaLoader, jstring javaLibrarySearchPath)  
  4. {  
  5.     return JVM_NativeLoad(env, javaFilename, javaLoader, javaLibrarySearchPath);  
  6. }  

接着调用 ./art/runtime/openjdkjvm/OpenjdkJvm.cc中的JVM_NativeLoad

[cpp] view plain copy
  1. JNIEXPORT jstring JVM_NativeLoad(JNIEnv* env,  
  2.                                  jstring javaFilename,  
  3.                                  jobject javaLoader,  
  4.                                  jstring javaLibrarySearchPath) {  
  5.   ScopedUtfChars filename(env, javaFilename);  
  6.   if (filename.c_str() == NULL) {  
  7.     return NULL;  
  8.   }  
  9.    
  10.   std::string error_msg;  
  11.   {  
  12.     art::JavaVMExt* vm = art::Runtime::Current()->GetJavaVM();  
  13.     bool success = vm->LoadNativeLibrary(env,  
  14.                                          filename.c_str(),  
  15.                                          javaLoader,  
  16.                                          javaLibrarySearchPath,  
  17.                                          &error_msg);  
  18.     if (success) {  
  19.       return nullptr;  
  20.     }  
  21.   }  

此处先获取当前运行的虚拟机,然后调用虚拟机的LoadNativeLibrary,代码位于:

./art/runtime/java_vm_ext.cc:

[cpp] view plain copy
  1. bool JavaVMExt::LoadNativeLibrary(JNIEnv* env,  
  2.                                   const std::string& path,  
  3.                                   jobject class_loader,  
  4.                                   jstring library_path,  
  5.                                   std::string* error_msg) {  
  6.   error_msg->clear();  
  7.    
  8.   // See if we've already loaded this library.  If we have, and the class loader  
  9.   // matches, return successfully without doing anything.  
  10.   // TODO: for better results we should canonicalize the pathname (or even compare  
  11.   // inodes). This implementation is fine if everybody is using System.loadLibrary.  
  12.   SharedLibrary* library;  
  13.   Thread* self = Thread::Current();  
  14.   {  
  15.     // TODO: move the locking (and more of this logic) into Libraries.  
  16.     MutexLock mu(self, *Locks::jni_libraries_lock_);  
  17.     library = libraries_->Get(path);  
  18.   }  
  19.   void* class_loader_allocator = nullptr;  
  20.   {  
  21.     ScopedObjectAccess soa(env);  
  22.     // As the incoming class loader is reachable/alive during the call of this function,  
  23.     // it's okay to decode it without worrying about unexpectedly marking it alive.  
  24.     mirror::ClassLoader* loader = soa.Decode<mirror::ClassLoader*>(class_loader);  
  25.    
  26.     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();  
  27.     if (class_linker->IsBootClassLoader(soa, loader)) {  
  28.       loader = nullptr;  
  29.       class_loader = nullptr;  
  30.     }  
  31.    
  32.     class_loader_allocator = class_linker->GetAllocatorForClassLoader(loader);  
  33.     CHECK(class_loader_allocator != nullptr);  
  34.   }  
  35.   if (library != nullptr) {  
  36.     // Use the allocator pointers for class loader equality to avoid unnecessary weak root decode.  
  37.     if (library->GetClassLoaderAllocator() != class_loader_allocator) {  
  38.       // The library will be associated with class_loader. The JNI  
  39.       // spec says we can't load the same library into more than one  
  40.       // class loader.  
  41.       StringAppendF(error_msg, "Shared library \"%s\" already opened by "  
  42.           "ClassLoader %p; can't open in ClassLoader %p",  
  43.           path.c_str(), library->GetClassLoader(), class_loader);  
  44.       LOG(WARNING) << error_msg;  
  45.       return false;  
  46.     }  
  47.     VLOG(jni) << "[Shared library \"" << path << "\" already loaded in "  
  48.               << " ClassLoader " << class_loader << "]";  
  49.     if (!library->CheckOnLoadResult()) {  
  50.       StringAppendF(error_msg, "JNI_OnLoad failed on a previous attempt "  
  51.           "to load \"%s\"", path.c_str());  
  52.       return false;  
  53.     }  
  54.     return true;  
  55.   }  
  56.    
  57.   // Open the shared library.  Because we're using a full path, the system  
  58.   // doesn't have to search through LD_LIBRARY_PATH.  (It may do so to  
  59.   // resolve this library's dependencies though.)  
  60.    
  61.   // Failures here are expected when java.library.path has several entries  
  62.   // and we have to hunt for the lib.  
  63.    
  64.   // Below we dlopen but there is no paired dlclose, this would be necessary if we supported  
  65.   // class unloading. Libraries will only be unloaded when the reference count (incremented by  
  66.   // dlopen) becomes zero from dlclose.  
  67.    
  68.   Locks::mutator_lock_->AssertNotHeld(self);  
  69.   const char* path_str = path.empty() ? nullptr : path.c_str();  
  70.   void* handle = android::OpenNativeLibrary(env,  
  71.                                             runtime_->GetTargetSdkVersion(),  
  72.                                             path_str,  
  73.                                             class_loader,  
  74.                                             library_path);  
  75.    
  76.   bool needs_native_bridge = false;  
  77.   if (handle == nullptr) {  
  78.     if (android::NativeBridgeIsSupported(path_str)) {  
  79.       handle = android::NativeBridgeLoadLibrary(path_str, RTLD_NOW);  
  80.       needs_native_bridge = true;  
  81.     }  
  82.   }  
  83.    
  84.   VLOG(jni) << "[Call to dlopen(\"" << path << "\", RTLD_NOW) returned " << handle << "]";  
  85.    
  86.   if (handle == nullptr) {  
  87.     *error_msg = dlerror();  
  88.     VLOG(jni) << "dlopen(\"" << path << "\", RTLD_NOW) failed: " << *error_msg;  
  89.     return false;  
  90.   }  
  91.    
  92.   if (env->ExceptionCheck() == JNI_TRUE) {  
  93.     LOG(ERROR) << "Unexpected exception:";  
  94.     env->ExceptionDescribe();  
  95.     env->ExceptionClear();  
  96.   }  
  97.   // Create a new entry.  
  98.   // TODO: move the locking (and more of this logic) into Libraries.  
  99.   bool created_library = false;  
  100.   {  
  101.     // Create SharedLibrary ahead of taking the libraries lock to maintain lock ordering.  
  102.     std::unique_ptr<SharedLibrary> new_library(  
  103.         new SharedLibrary(env, self, path, handle, class_loader, class_loader_allocator));  
  104.     MutexLock mu(self, *Locks::jni_libraries_lock_);  
  105.     library = libraries_->Get(path);  
  106.     if (library == nullptr) {  // We won race to get libraries_lock.  
  107.       library = new_library.release();  
  108.       libraries_->Put(path, library);  
  109.       created_library = true;  
  110.     }  
  111.   }  
  112.   if (!created_library) {  
  113.     LOG(INFO) << "WOW: we lost a race to add shared library: "  
  114.         << "\"" << path << "\" ClassLoader=" << class_loader;  
  115.     return library->CheckOnLoadResult();  
  116.   }  
  117.   VLOG(jni) << "[Added shared library \"" << path << "\" for ClassLoader " << class_loader << "]";  
  118.    
  119.   bool was_successful = false;  
  120.   void* sym;  
  121.   if (needs_native_bridge) {  
  122.     library->SetNeedsNativeBridge();  
  123.   }  
  124.   sym = library->FindSymbol("JNI_OnLoad", nullptr);  
  125.   if (sym == nullptr) {  
  126.     VLOG(jni) << "[No JNI_OnLoad found in \"" << path << "\"]";  
  127.     was_successful = true;  
  128.   } else {  
  129.     // Call JNI_OnLoad.  We have to override the current class  
  130.     // loader, which will always be "null" since the stuff at the  
  131.     // top of the stack is around Runtime.loadLibrary().  (See  
  132.     // the comments in the JNI FindClass function.)  
  133.     ScopedLocalRef<jobject> old_class_loader(env, env->NewLocalRef(self->GetClassLoaderOverride()));  
  134.     self->SetClassLoaderOverride(class_loader);  
  135.    
  136.     VLOG(jni) << "[Calling JNI_OnLoad in \"" << path << "\"]";  
  137.     typedef int (*JNI_OnLoadFn)(JavaVM*, void*);  
  138.     JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym);  
  139.     int version = (*jni_on_load)(this, nullptr);  
  140.    
  141.     if (runtime_->GetTargetSdkVersion() != 0 && runtime_->GetTargetSdkVersion() <= 21) {  
  142.       fault_manager.EnsureArtActionInFrontOfSignalChain();  
  143.     }  
  144.    
  145.     self->SetClassLoaderOverride(old_class_loader.get());  
  146.    
  147.     if (version == JNI_ERR) {  
  148.       StringAppendF(error_msg, "JNI_ERR returned from JNI_OnLoad in \"%s\"", path.c_str());  
  149.     } else if (IsBadJniVersion(version)) {  
  150.       StringAppendF(error_msg, "Bad JNI version returned from JNI_OnLoad in \"%s\": %d",  
  151.                     path.c_str(), version);  
  152.       // It's unwise to call dlclose() here, but we can mark it  
  153.       // as bad and ensure that future load attempts will fail.  
  154.       // We don't know how far JNI_OnLoad got, so there could  
  155.       // be some partially-initialized stuff accessible through  
  156.       // newly-registered native method calls.  We could try to  
  157.       // unregister them, but that doesn't seem worthwhile.  
  158.     } else {  
  159.       was_successful = true;  
  160.     }  
  161.     VLOG(jni) << "[Returned " << (was_successful ? "successfully" : "failure")  
  162.               << " from JNI_OnLoad in \"" << path << "\"]";  
  163.   }  
  164.    
  165.   library->SetResult(was_successful);  
  166.   return was_successful;  
  167. }  

此方法异常复杂,我们不做深入分析,该方法大致做以下几步:

    1) 调用android::OpenNativeLibrary打开lib库

    2) 调用library->FindSymbol("JNI_OnLoad", nullptr)找到lib中的JNI_OnLoad这个方法

    3) 执行JNI_OnLoad方法。

至此,java层真正调到lib库中,接下来的一些方法就需要jni层自己实现了。

原创粉丝点击