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 机制
因为只在启动的时候注册必要的部分,其他部分在使用时随着加载过程进行动态注册。注意 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;
}
另外一种方式
先看下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方法注册稍有不同
|