在看framework层代码时,经常会看到native方法,这是往往需要查看所对应的C++方法在哪个文件,对应哪个方法?下面从一个实例出发带大家如何查看java层方法所对应的native方法位置。
实例(一)
当分析Android消息机制源码,遇到MessageQueue.java中有多个native方法,比如:
private native void nativePollOnce(long ptr, int timeoutMillis);
register_[包名]_[类名]
那么MessageQueue.java所定义的jni注册方法名应该是register_android_os_MessageQueue,的确存在于gRegJNI数组,说明这次JNI注册过程是有开机过程完成的。 该方法在AndroidRuntime.cpp申明为extern方法:
extern int register_android_os_MessageQueue(JNIEnv* env);
这些extern方法绝大多数位于/framework/base/core/jni/目录,大多数情况下native文件命名方式:
[包名]_[类名].cpp [包名]_[类名].h
Tips: MessageQueue.java ==> android_os_MessageQueue.cpp
打开android_os_MessageQueue.cpp文件,搜索android_os_MessageQueue_nativePollOnce方法,这便找到了目标方法:
static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj, jlong ptr, jint timeoutMillis) { NativeMessageQueue* nativeMessageQueue = reinterpret_cast
(ptr); nativeMessageQueue->pollOnce(env, obj, timeoutMillis); }
到这里完成了一次从Java层方法搜索到所对应的C++方法的过程。
实例(二)
对于native文件命名方式,有时并非[包名]_[类名].cpp,比如Binder.java
Binder.java所对应的native文件:android_util_Binder.cpp
public static final native int getCallingPid();
根据实例(一)方式,找到getCallingPid ==> android_os_Binder_getCallingPid(),并且在AndroidRuntime.cpp中的gRegJNI数组中找到register_android_os_Binder。
按实例(一)方式则native文名应该为android_os_Binder.cpp,可是在/framework/base/core/jni/目录下找不到该文件,这是例外的情况。其实真正的文件名为android_util_Binder.cpp,这就是例外,这一点有些费劲,不明白为何google要如此打破规律的命名。
static jint android_os_Binder_getCallingPid(JNIEnv* env, jobject clazz) { return IPCThreadState::self()->getCallingPid(); }
有人可能好奇,既然如何遇到打破常规的文件命令,怎么办?这个并不难,首先,可以尝试在/framework/base/core/jni/中搜索,对于binder.java,可以直接搜索binder关键字,其他也类似。如果这里也找不到,可以通过grep全局搜索android_os_Binder_getCallingPid这个方法在哪个文件。
实例(三)
前面两种都是在Android系统启动之初,便已经注册过JNI所对应的方法。 那么如果程序自己定义的jni方法,该如何查看jni方法所在位置呢?下面以MediaPlayer.java为例,其包名为android.media:
public class MediaPlayer{
static { System.loadLibrary("media_jni"); native_init(); } private static native final void native_init(); ... }
通过static静态代码块中System.loadLibrary方法来加载动态库,库名为media_jni, Android平台则会自动扩展成所对应的libmedia_jni.so库。 接着通过关键字native加在native_init方法之前,便可以在java层直接使用native层方法。
接下来便要查看libmedia_jni.so库定义所在文件,一般都是通过Android.mk文件定义LOCAL_MODULE:= libmedia_jni,可以采用grep或者mgrep来搜索包含libmedia_jni字段的Android.mk所在路径。
搜索可知,libmedia_jni.so位于/frameworks/base/media/jni/Android.mk。用前面实例(一)中的知识来查看相应的文件和方法名分别为:
android_media_MediaPlayer.cpp android_media_MediaPlayer_native_init()
再然后,你会发现果然在该Android.mk所在目录/frameworks/base/media/jni/中找到android_media_MediaPlayer.cpp文件,并在文件中存在相应的方法:
static void android_media_MediaPlayer_native_init(JNIEnv *env) { jclass clazz; clazz = env->FindClass("android/media/MediaPlayer"); fields.context = env->GetFieldID(clazz, "mNativeContext", "J"); ... }
Tips:MediaPlayer.java中的native_init方法所对应的native方法位于/frameworks/base/media/jni/目录下的android_media_MediaPlayer.cpp文件中的android_media_MediaPlayer_native_init方法。
原文链接:http://gityuan.com/2016/05/28/android-jni/
欢迎关注微信公众号:DroidMind
精品内容独家发布平台
呈现与博客不一样的技术干货
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/213172.html原文链接:https://javaforall.net
