如何查找native方法

在看framework层代码时,经常会看到native方法,这是往往需要查看所对应的C++方法在哪个文件,对应哪个方法?下面从一个实例出发带大家如何查看java层方法所对应的native方法位置。

实例(一)

当分析Android消息机制源码,遇到MessageQueue.java中有多个native方法,比如:

 private native void nativePollOnce(long ptr, int timeoutMillis);

步骤1:
MessageQueue.java的全限定名为android.os.MessageQueue.java,方法名:android.os.MessageQueue.nativePollOnce(),而相对应的native层方法名只是将点号替换为下划线,可得android_os_MessageQueue_nativePollOnce()。
Tips: nativePollOnce ==> android_os_MessageQueue_nativePollOnce()

步骤2:
有了native方法,那么接下来需要知道该native方法所在那个文件。Android系统启动时就已经注册了大量的JNI方法,见AndroidRuntime.cpp的gRegJNI数组。这些注册方法命令方式:

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<NativeMessageQueue*>(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
精品内容独家发布平台


呈现与博客不一样的技术干货

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Native.loadLibrary 是 Java Native Interface (JNI) 的一个方法,用于加载本地库文件,使 Java 程序能够调用本地库中的函数。该方法需要传入本地库文件的路径和一个接口类,接口类中定义了需要调用的本地函数。使用该方法需要注意本地库文件的路径和接口类的定义必须与本地库中的函数一致。 ### 回答2: Native.loadLibrary 是Java Native Interface (JNI) 中的一个方法,用于加载本地动态链接库(DLL、SO 等)。 在Java中,如果需要调用本地方法,即使用其他语言(如C、C++等)编写的库,就需要使用JNI。而Native.loadLibrary 就是JNI提供的一个方法,用于加载本地动态链接库,以便在Java程序中调用本地方法。 使用Native.loadLibrary 的步骤如下: 1. 首先,需要确保本地动态链接库已经存在,并且可以被操作系统加载。如果没有相应的库文件,可以通过其他语言编写并编译成库文件,然后进行加载。 2. 在Java代码中,使用 Native.loadLibrary 方法来加载本地动态链接库。这个方法接收两个参数:库文件的名称(不带路径和后缀)和包含库文件的类。通常情况下,库文件的名称应该与平台相关,在不同的操作系统上可能有不同的后缀名。 3. 在加载库文件之后,可以通过JNI来调用本地方法。通常情况下,需要提供 native 关键字来声明一个本地方法,在Java代码中编写native方法的实现,在本地动态链接库中实现具体的功能。 总结来说,Native.loadLibrary 方法用于在Java程序中加载本地动态链接库,以便调用其他语言编写的库中的本地方法。通过加载本地库,Java程序可以实现与其他语言的交互,扩展Java的功能和性能。 ### 回答3: Native.loadLibrary 是 Java 中用于加载本地库的方法。本地库通常是由其他编程语言编写的动态链接库(DLL或SO文件)或操作系统的库文件。 Native.loadLibrary 方法的使用需要两个参数:库的名称和包含该库的接口的 Class 对象。该方法会尝试在系统的标准库路径中查找和加载库,如果找不到则会抛出异常。 加载本地库后,可以通过接口中定义的方法来调用库中的函数。通过与本地库的交互,可以调用底层操作系统或其他编程语言的特定功能,扩展 Java 的功能。 使用 Native.loadLibrary 方法的一般步骤如下: 1. 确保本地库文件已存在,并位于系统的标准库路径中或者设置了正确的库路径。 2. 创建一个 Java 接口,定义需要调用的本地库函数的方法签名。 3. 使用 Native.loadLibrary 方法加载库,并传入库的名称和接口的 Class 对象。 4. 通过接口对象调用本地库函数。 需要注意的是,Native.loadLibrary 方法在跨平台开发时可能存在一些限制。不同的操作系统和架构可能有不同的库文件格式和命名约定,如果要在不同的平台上运行,需要针对每个平台提供相应的本地库。 总之,Native.loadLibrary 是 Java 提供的用于加载本地库的方法,通过与本地库的交互,可以扩展 Java 的功能,调用底层操作系统或其他编程语言的特定功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值