欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

android中的jni

时间:2023-06-15

https://www.jianshu.com/p/91321134207b

1基本要点

JavaVM:表示Java虚拟机。JNIEnv:表示JNI环境的上下文,例如注册、查找类、异常等。jclass:在JNI中表示的Java类。jmethodID:在JNI中表示的Java类中的方法。jfiledID:在JNI中表示的Java类中的属性。线程:JNI中通过AttachCurrentThread和DetachCurrentThread方法,实现和Java线程的结合。

它们都在一个叫jni.h的头文件中,这个头文件是JNI机制中很重要的一个头文件

/libnativehelper/include/nativehelper/jni.h

在libnativehelper目录下的源文件,编译后会生成一个libnativehelper.so的动态库。其实,jni.h是Android根据Java本地调用的标准写成的一个头文件,在它里面包括了基本类型(类型的映射),以及JavaVM,JNIEnv,jclass,jmethodID,jfiledID等数据结构的定义。

JavaVM对应于jni.h中JNIInvokeInterface结构体,表示虚拟机。JNIEnv对应于JNINativeInterface结构体,表示JNI的环境。在JNI的使用过程中,所调用的功能大都来自JNINativeInterface结构体。例如,处理Java属性和方法的查找,Java属性的访问,Java方法的调用等功能。另外,在JNINativeInterface结构体中,涉及到的一个JNINativeMethod结构体,它表示在本地实现的一个方法,即native方法,后面进行JNI注册的时候会用到。

在Android框架中,JNI库是一些普通的本地动态库,被放置在目标系统的/system/lib目录中。Java框架层,最主要的JNI内容源代码路径为:/frameworks/base/core/jni。 这里面的代码会生成一个libandroid_runtiem.so的动态库。接下来要分析的Log中JNI的使用,就在这个目录之中。

2、android 中的jni

在Android框架中,JNI库是一些普通的本地动态库,被放置在目标系统的/system/lib目录中。
Java框架层,最主要的JNI内容源代码路径为:/frameworks/base/core/jni。
这里面的代码会生成一个libandroid_runtiem.so的动态库。接下来要分析的Log中JNI的使用,就在这个目录之中。

2.1framework base/core/jni 机制

Java框架层,最主要的JNI内容源代码路径为:/frameworks/base/core/jni,编译生成libandroid_runtiem.so的动态库

以Log为例:

/frameworks/base/core/java/android/util/Log.java 都会走println_native->android_util_Log_println_native

//frameworks/base/core/jni/android_util_Log.cpp。static const JNINativeMethod gMethods[] = { { "isLoggable", "(Ljava/lang/String;I)Z", (void*) android_util_Log_isLoggable }, { "println_native", "(IILjava/lang/String;Ljava/lang/String;)I", (void*) android_util_Log_println_native }, { "logger_entry_max_payload_native", "()I", (void*) android_util_Log_logger_entry_max_payload_native },};//android_util_Log.htypedef struct { const char* name; //native方法名 const char* signature; //参数,返回值,jni签名为了支持函数重载 (参数1类型标示;参数2类型标示;参数3类型标示...)返回值类型标示 void* fnPtr;//函数指针,指向这个natve对应的jni函数} JNINativeMethod;

println_native------>jni实现函数android_util_Log_println_native()---->native 的liblog库 __android_log_buf_write()

jni注册

//android_util_Log.cppint register_android_util_Log(JNIEnv* env){ jclass clazz = FindClassOrDie(env, "android/util/Log"); levels.verbose = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "VERBOSE", "I")); levels.debug = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "DEBUG", "I")); levels.info = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "INFO", "I")); levels.warn = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "WARN", "I")); levels.error = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "ERROR", "I")); levels.assert = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "ASSERT", "I"));//RegisterMethodsOrDie()函数做了什么 后文分析 return RegisterMethodsOrDie(env, "android/util/Log", gMethods, NELEM(gMethods));}

register_android_util_Log 被谁调用?

cgrep register_android_util_Log 搜索

/frameworks/base/include/android_runtime/AndroidRuntime.h。
/frameworsk/base/core/jni/AndroidRuntime.cpp。

//AndroidRuntime.cpp ,gRegJNI数组static const RegJNIRec gRegJNI[] = { REG_JNI(register_com_android_internal_os_RuntimeInit), REG_JNI(register_android_os_SystemClock), REG_JNI(register_android_util_EventLog), REG_JNI(register_android_util_Log), REG_JNI(register_android_util_MemoryIntArray), //省略} int AndroidRuntime::startReg(JNIEnv* env){ ATRACE_NAME("RegisterAndroidNatives");...//gRegJNI if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) { env->PopLocalframe(NULL); return -1; } return 0;}//frameworks/base/core/jni/core_jni_helpers.hstatic inline int RegisterMethodsOrDie(JNIEnv* env, const char* className, const JNINativeMethod* gMethods, int numMethods) { int res = AndroidRuntime::registerNativeMethods(env, className, gMethods, numMethods); LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods."); return res;}//最终调用 libnativehelper/JNIHelp.cpp 的jniRegisterNativeMethods方法extern "C" int jniRegisterNativeMethods(C_JNIEnv* env, const char* className, const JNINativeMethod* gMethods, int numMethods){ JNIEnv* e = reinterpret_cast(env); ALOGV("Registering %s's %d native methods...", className, numMethods); return 0;}//startReg哪里来的呢zygote->AndroidRuntime::start()->AndroidRuntime::startReg()if (zygote) { runtime.start("com.android.internal.os.ZygoteInit", args, zygote);} else if (className) { runtime.start("com.android.internal.os.RuntimeInit", args, zygote);} else { fprintf(stderr, "Error: no class name or --zygote supplied.n"); app_usage(); LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied."); return 10;}

此外还有一种方式,

因为只在启动的时候注册必要的部分,其他部分在使用时随着加载过程进行动态注册。注意 registerNativeMethods JNI_OnLoad,且看后面详解。

//frameworks/base/service/core/jni/onload.cppextern "C" jint JNI_onLoad(JavaVM* vm, void* ){ JNIEnv* env = NULL; jint result = -1; if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { ALOGE("GetEnv failed!"); return result; } ALOG_ASSERT(env, "Could not retrieve the env!"); register_android_server_ActivityManagerService(env); register_android_server_PowerManagerService(env); register_android_server_SerialService(env); register_android_server_InputApplicationHandle(env); register_android_server_InputWindowHandle(env);。。。。。。。。。。。。。。。。。。。。。 register_android_server_HardwarePropertiesManagerService(env); return JNI_VERSION_1_4;}//frameworks/base/media/jni/android_media_MediaPlayer.cppjint JNI_onLoad(JavaVM* vm, void* ){ JNIEnv* env = NULL; jint result = -1; if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { ALOGE("ERROR: GetEnv failedn"); goto bail; } assert(env != NULL); if (register_android_media_ImageWriter(env) != JNI_OK) { ALOGE("ERROR: ImageWriter native registration failed"); goto bail; } if (register_android_media_ImageReader(env) < 0) { ALOGE("ERROR: ImageReader native registration failed"); goto bail; } if (register_android_media_MediaPlayer(env) < 0) { ALOGE("ERROR: MediaPlayer native registration failedn"); goto bail; } // 省略 result = JNI_VERSION_1_4;bail: return result;}

另外一种方式

先看下java框架组成

java框架库,framework.jar 系统核心,定义并实现andorid中大多数的java类,也提供作为标准

java服务库 service.jar,包含一些复杂服务,为框架层提供一部分功能的实现,服务库也具有java框架层中一个主要的程序入口,进入此入口运行后,服务库将形成java框架层一个在后台长时间运行的程序。

资源包 framework-res.apk 没有java代码,纯资源组成的包,资源包是java框架层唯一的包含资源和工程描述文件的包。框架层所有的资源和组件定义均包含在资源包中。

三个库之间耦合性比较像,且相互依赖。
总结下上一节。

framework.jar 系统核心,

framework/base/core是主要目录,core目录下,jni包是同目录下java包中对应的jni实现,

/frameworks/base/core/java/android/util/Log.java

/frameworks/base/core/jni/android_util_Log.cpp

frameworks/base/core/jni/android_util_Log.cpp 实现jni,会生成一个libandroid_runtime.so动态库。启动zygote时,实例化AndroidRuntime.cpp类,将其中jni函数注册到虚拟机,所以core,media(部分),opengl等相关的JNI会在系统启动的时候进行注册

service.jar

Java框架层服务库部分的目录为:frameworks/base/services/java,同级目录下的Android.mk会将这个包编译,生成services.jar

frameworks/base/services/java/com/android/server中只包含一个入口部分的类 SystemServer.java SystemConfigService.java

frameworks/base/services/core/java/com/android/server 其他类在这个目录下

service.jar的jni实现在frameworks/base/service/core/jni/com_android_server_xxx.cpp,其中内容生成libandroid_server.so的动态库。为service提供本地支持,这个库在frameworks/base/services/java/SystemServer.java类中被加载。注册示例:

//frameworks/base/services/core/jni/com_android_server_ConsumerIrService.cppnamespace android {static jboolean getHidlHalService(JNIEnv * , jobject ) {。。。。}static const JNINativeMethod method_table[] = { {"getHidlHalService", "()Z", (void *)getHidlHalService}, {"halTransmit", "(I[I)I", (void *)halTransmit}, {"halGetCarrierFrequencies", "()[I", (void *)halGetCarrierFrequencies},};int register_android_server_ConsumerIrService(JNIEnv *env) { return jniRegisterNativeMethods(env, "com/android/server/ConsumerIrService", method_table, NELEM(method_table));}。。。。}

生成libandroid_servers.so动态库,SystemServer main函数中加载libandroid_servers,调用其Onload,frameworks/base/service/core/jni/onload.cpp,将jni方法注册到java虚拟机中。

//frameworks/base/services/core/jni/onload.cppextern "C" jint JNI_onLoad(JavaVM* vm, void* ){ register_android_server_ConsumerIrService(env); }

此外,android框架层还包含其他jni实现库,比如,多媒体一部分jni实现在frameworks/base/media/jni/android_media_xxx.cpp,(一部分在libandroid_runtime.so中),生成libmedia.so,为framework.jar提供部分本地支持,(media目录划在了框架层的framework.jar部分)。这个动态库是在frameworks/base/media/java/android/media/MediaPlayer.java类中加载,加载本地库后,会执行其中的**JNI_onLoad()**函数,进行JNI方法的注册。也就是说,程序在使用的时候进行加载,并进行jni注册。谷歌这样么做,是因为想在启动时注册必要的部分(zygote启动时实例化AndroidRuntime.cpp),其他部分随着加载so过程进行动态注册。

//frameworks/base/media/jni/android_media_MediaPlayer.cpp jint JNI_onLoad(JavaVM* vm, void* ) { JNIEnv* env = NULL; jint result = -1; if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { ALOGE("ERROR: GetEnv failedn"); goto bail; } assert(env != NULL); if (register_android_media_ImageWriter(env) != JNI_OK) { ALOGE("ERROR: ImageWriter native registration failed"); goto bail; } // 省略 result = JNI_VERSION_1_4; bail: return result; } //frameworks/base/media/java/android/media/MediaPlayer.java static { System.loadLibrary("media_jni"); native_init(); }

Java层调用System.loadLibrary()方法加载动态函数库时,执行JNI_onLoad()函数,完成各个JNI方法的动态注册,这和前面Log相关的JNI方法注册稍有不同

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。