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_runtime.so的动态库。接下来要分析的Log中JNI的使用,就在这个目录之中。
2. android 中的jni
在Android框架中,JNI库是一些普通的本地动态库,被放置在目标系统的/system/lib目录中。
Java框架层,最主要的JNI内容源代码路径为:/frameworks/base/core/jni。
这里面的代码会生成一个libandroid_runtime.so的动态库。接下来要分析的Log中JNI的使用,就在这个目录之中。
2.1Framework base/core/jni 机制
-
Java框架层,最主要的JNI内容源代码路径为:/frameworks/base/core/jni,编译生成libandroid_runtime.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。 /* * JNI registration. */ static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "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.h typedef 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.cpp int 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), //省略 } /* * Register android native functions with the VM. */ /*static*/ 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.h static 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<JNIEnv*>(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.cpp
extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
{
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.cpp
jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
{
JNIEnv* env = NULL;
jint result = -1;
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
ALOGE("ERROR: GetEnv failed\n");
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 failed\n");
goto bail;
}
// 省略
/* success -- return valid version number */
result = JNI_VERSION_1_4;
bail:
return result;
}
2.2 service的jni (另外一种方式)
先看下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.cpp namespace android { static jboolean getHidlHalService(JNIEnv * /* env */, jobject /* obj */) {。。。。} static const JNINativeMethod method_table[] = { /* name, signature, funcPtr */ {"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.cpp extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) { 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* /* reserved */)
{
JNIEnv* env = NULL;
jint result = -1;
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
ALOGE("ERROR: GetEnv failed\n");
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方法注册稍有不同
下一篇jni详解