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加载器。
这下这节真结束了
- Android JNI/Hardware 加载(二)
- Android JNI/Hardware 加载(一)
- Android图形---硬件加速(Hardware Acceleration)(二)
- Android图形---硬件加速(Hardware Acceleration)(二)
- Android JNI调用(二)
- Android JNI调用(二)
- Android JNI调用(二)
- Android与JNI(二)
- Android与JNI(二)
- android jni 动态加载
- android - hardware
- Android硬件抽象Hardware库加载过程源码分析
- Android JNI知识简介(二)
- android之 JNI 详解(二)
- Android JNI使用总结(二)
- android JNI 系列 二
- android JNI学习二
- android jni 编程 二
- Linux中make命令详解
- 建造者模式应用场景
- java selenium (一) selenium 介绍
- Min Stack
- facenet_train.py代码注释
- Android JNI/Hardware 加载(二)
- 欢迎使用CSDN-markdown编辑器
- Java 容器类
- Java中的接口
- jQuery的基本过滤选择器
- java8 lambda表达式教程
- APP开发究竟需要多少钱?
- Java语言中的修饰符
- Centos下Apache遇到/usr/lib64/libnsssysinit.so: undefined symbol: PR_GetEnvSecure错误