Android JNI/Hardware 加载(二)

来源:互联网 发布:音效软件 编辑:程序博客网 时间:2024/05/16 09:52

前文提到,AdapterApp里面,一来就用system.loadLibrary(bluetooth_jni)加载JNI库。来看看具体实现。
System.java路径:libcore/luni/src/main/java/java/lang/System.java
Android M是这样的, Android N 都没找到这个路径,鬼晓得在哪点,反正不是我关注的重点。

1072    /**1073     * See {@link Runtime#loadLibrary}.1074     */1075    public static void loadLibrary(String libName) {1076        Runtime.getRuntime().loadLibrary(libName, VMStack.getCallingClassLoader());1077    }

简单粗暴,直接丢给Runtime. 后面那个参数,class loader,虽然我不明白,但结合注释“// Returns the defining class loader of the caller’s caller.”,我大胆的猜,算了,最后再来猜,继续看,万一猜错得太远,就不好意思了。

好了,来到了Runtime : libcore/luni/src/main/java/java/lang/Runtime.java

323    /*324     * Loads the given shared library using the given ClassLoader.325     */326    void load(String absolutePath, ClassLoader loader) {327        if (absolutePath == null) {328            throw new NullPointerException("absolutePath == null");329        }330        String error = doLoad(absolutePath, loader);331        if (error != null) {332            throw new UnsatisfiedLinkError(error);333        }334    }
423        if (loader == null) {424            // We use the given library path for the boot class loader. This is the path425            // also used in loadLibraryName if loader is null.426            ldLibraryPath = System.getProperty("java.library.path");427        } else if (loader instanceof BaseDexClassLoader) {428            BaseDexClassLoader dexClassLoader = (BaseDexClassLoader) loader;429            ldLibraryPath = dexClassLoader.getLdLibraryPath();430        }431        // nativeLoad should be synchronized so there's only one LD_LIBRARY_PATH in use regardless432        // of how many ClassLoaders are in the system, but dalvik doesn't support synchronized433        // internal natives.434        synchronized (this) {435            return nativeLoad(name, loader, ldLibraryPath);436        }

通过loader得到 ldLibraryPath参数,看名字,应该是/system/lib,应该是了。

进入到Runtime对应的native 函数:
路径:art/runtime/native/java_lang_Runtime.cc

105static JNINativeMethod gMethods[] = {106  NATIVE_METHOD(Runtime, freeMemory, "!()J"),107  NATIVE_METHOD(Runtime, gc, "()V"),108  NATIVE_METHOD(Runtime, maxMemory, "!()J"),109  NATIVE_METHOD(Runtime, nativeExit, "(I)V"),110  NATIVE_METHOD(Runtime, nativeLoad, "(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/String;"),111  NATIVE_METHOD(Runtime, totalMemory, "!()J"),112};//下面的宏定义来自于JniConstants.h99#define NATIVE_METHOD(className, functionName, signature) \100    { #functionName, signature, reinterpret_cast<void*>(className ## _ ## functionName) }
70static jstring Runtime_nativeLoad(JNIEnv* env, jclass, jstring javaFilename, jobject javaLoader,71                                  jstring javaLdLibraryPathJstr) {72  ScopedUtfChars filename(env, javaFilename);73  if (filename.c_str() == nullptr) {74    return nullptr;75  }7677  SetLdLibraryPath(env, javaLdLibraryPathJstr);7879  std::string error_msg;80  {81    JavaVMExt* vm = Runtime::Current()->GetJavaVM();82    bool success = vm->LoadNativeLibrary(env, filename.c_str(), javaLoader, &error_msg);83    if (success) {84      return nullptr;85    }86  }8788  // Don't let a pending exception from JNI_OnLoad cause a CheckJNI issue with NewStringUTF.89  env->ExceptionClear();90  return env->NewStringUTF(error_msg.c_str());91}

此处通过JavaVMExt 去真枪实干。为什么是javaVMExt? 为什么不是javaVM?Ext是啥?external、extra?理解不了。

据不完整调查,度娘里面就一个解释,重复了N遍:
JavaVMExt:JavaVM在JNI编程中代表虚拟机本身。在Dalvik中,这个虚拟机本身真正的数据类型是此处的JavaVMExt。

那就是说这个虚拟机在JNI中的一个代表,JavaVM已经被dalvik用了,所以这点用JavaVMExt来表示,如果不出意外的话,Ext应该为External,因为之前大部分的hardware都在external目录下。我猜的。

596bool JavaVMExt::LoadNativeLibrary(JNIEnv* env, const std::string& path, jobject class_loader,597                      std::string* error_msg) {     ...645  void* handle = dlopen(path_str, RTLD_NOW);646  bool needs_native_bridge = false;647  if (handle == nullptr) {648    if (android::NativeBridgeIsSupported(path_str)) {649      handle = android::NativeBridgeLoadLibrary(path_str, RTLD_NOW);650      needs_native_bridge = true;651    }652  }     ...690  void* sym;691  if (needs_native_bridge) {692    library->SetNeedsNativeBridge();693    sym = library->FindSymbolWithNativeBridge("JNI_OnLoad", nullptr);694  } else {695    sym = dlsym(handle, "JNI_OnLoad");696  }    ...697  if (sym == nullptr) {698    VLOG(jni) << "[No JNI_OnLoad found in \"" << path << "\"]";699    was_successful = true;700  } else {709    typedef int (*JNI_OnLoadFn)(JavaVM*, void*);710    JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym);711    int version = (*jni_on_load)(this, nullptr);718719    if (version == JNI_ERR) {730    } else {731      was_successful = true;732    }735  }

进到LoadNativeLibrary之后,先判断下libpath对不对,然后打开指定的lib库。然后找到以一个叫JNI_onLoad的函数,这也是为什么每个JNI里面的首要函数的JNI_onLoad了,这点就加载到JNI的入口函数了。
问题还有,就是如果sym==nullptr之后,还是要设置was_successful = true?这不是吃多了吗??

好了,就这样吧,到了BT JNI了。
后面再说吧。

对了,说了要猜一下那个loader是啥的。后面有个这样的注释:

604  SharedLibrary* library;609  library = libraries_->Get(path);611  if (library != nullptr) {612    if (env->IsSameObject(library->GetClassLoader(), class_loader) == JNI_FALSE) {613      // The library will be associated with class_loader. The JNI614      // spec says we can't load the same library into more than one615      // class loader.616      StringAppendF(error_msg, "Shared library \"%s\" already opened by "617          "ClassLoader %p; can't open in ClassLoader %p",618          path.c_str(), library->GetClassLoader(), class_loader);619      LOG(WARNING) << error_msg;620      return false;621    }

大致认识为:通过loader去申请内存空间,且所有的动态库都应该是共享同一个loader实例。

还有个疑问就是:按照Android的写法的话,加载lib完成之后,就去判断别个的JNI_onLoader函数,那岂不是如果非JNI的第三方库,就不能使用System.loadLibrary来加载了?
目前我是这么理解,Android不支持loadLibrary来加载第三方库,且不支持第三方loader加载器。

这下这节真结束了

0 0
原创粉丝点击