Android总结-JNI原理及静态、动态注册

大家知道在JNI开发过程中,JAVA代码中调用SO动态库中的函数时,需要找到JAVA接口映射的Native函数。因此JNI就需要对JAVA代码中可能要访问的函数进行事先注册。目前有两种方法注册:静态注册和动态注册。


一、JNI概述

JNI(Java Native Interface,Java本地接口),用于打通Java层与Native(C/C++)层。这不是Android系统所独有的,而是Java所有。众所周知,Java语言是跨平台的语言,而这跨平台的背后都是依靠Java虚拟机,虚拟机采用C/C++编写,适配各个系统,通过JNI为上层Java提供各种服务,保证跨平台性。

二、JNI原理

Jni对于应用本身来说,可以看做一个代理模式。对于开发者来说,需要使用c/c++来实现一个代理程序(jni程序)来实际操作目标原生函数,java程序中则是jvm通过加载并调用此jni程序来间接地调用目标原生函数。

三、静态注册

静态注册的原理是先由JAVA代码编写需要调用的接口什么,然后通过JNI实现这些声明方法。
比较通用的做法是先创建一个java文件,声明需要使用JNI实现的接口,然后使用javah命令生成对应的C/C++头文件。再一一实现头文件中的函数即可。JAVA层调用JIN函数时,会从对应的JNI文件中查找该函数,因此需要把JAVA层接口和Native函数建立一层关联,静态注册的实现方法就是在Native函数命名上遵守特定的格式,否侧就会找不到对应函数而报错。
举个例子:

1. JAVA层接口声明

定义一个JniTest.java类,其中有两个方法。

package com.luoxudong;

public class JniTest {
    static {
        System.loadLibrary("TesJnitLib");//需要加载的动态库名称
    }

    public native int test1(int val);//测试接口1
    public native String test2(String val);测试接口2
}
    

2.生成.h文件

声明JAVA层接口以后,使用javah命令生成C/C++的都文件。

#include <jni.h>

#ifndef _Included_com_luoxudong_JniTest
#define _Included_com_luoxudong_JniTest
#ifdef __cplusplus
extern "C" {
#endif

JNIEXPORT jint JNICALL Java_com_luoxudong_JniTest_test1
  (JNIEnv *, jobject, jint);
JNIEXPORT jstring JNICALL Java_com_luoxudong_JniTest_test2
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

大家应该注意到了,生成的Native函数名称是有一定规则的:包名_类名_方法名称,其中JAVA包名中的“.”替换成“_”了。参数对应的JAVA参数类型换成了对应JNI的参数类型。

3.定义.c/.cpp文件

剩下要做的就是在Native层实现.h定义的函数业务逻辑了。
JNI静态注册有一些缺点,如:

  • native函数名称特别长,不利于书写
  • 每次新增或删除接口时需要重新生成.h文件,比较繁琐
  • 第一次调用时需要根据函数名建立索引,影响效率
  • JNI层的函数名是由java接口名生成,很容易通过hook调用动态库中的函数。

四、动态注册

动态注册的原理是在JNI层通过重载JNI_OnLoad()函数来实现。
针对静态注册的缺点,动态注册方法就可以避免。动态注册的原理是通过RegisterNatives方法把C/C++函数映射到JAVA定义的方法,不需要通过JAVA方法名查找匹配Native函数名,也就不需要遵循静态注册的命名规则。
使用方法如下:

1.定义函数映射表

static JNINativeMethod method_table[] = {
        {"test1", "(I)I", (void *)n_test1},
        {"test2", "(Ljava/lang/String;)Ljava/lang/String;", (void *)n_test2}
};

JNINativeMethod的结构体定义为

typedef struct {  
   const char* name;  
   const char* signature;  
   void* fnPtr;  
} JNINativeMethod;

属性说明:

  • name:JAVA中的方法名称
  • signature:描述JAVA方法的参数和返回值
  • fnPtr:JAVA接口映射的Native函数指针。

其中signature字符串描述分为两部“()”中的表示方法参数类型,“()”后面表述返回值类型。数据类型分为两种:基本数据类型和对象类型:

基本数据类型:

对象类型:

示例:
()V”表示void func()
(I)V”表示void func(int param)
“(Ljava/lang/String;I)Ljava/lang/String;”表示String func(String param1, int param2)

2.重写注册入口函数

so加载时会先调用JNI_OnLoad函数,重写该函数,在里面实现动态注册JNI方法。

JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    JNIEnv* env = NULL;
    jint result = -1;

    if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_4) != JNI_OK)
    {
        return -1;
    }

    if (!registerNatives(env)) //注册
    {
        return -1;
    }

    result = JNI_VERSION_1_4;

    return result;
}

static int registerNatives(JNIEnv* env)
{
    if (!registerNativeMethods(env, JNIREG_CLASS, method_table, sizeof(method_table) / sizeof(method_table[0])))
    {
        return JNI_FALSE;
    }

    return JNI_TRUE;
}

static int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMethod* gMethods, int numMethods)
{
    jclass clazz;
    clazz = (*env)->FindClass(env, className);
    if (clazz == NULL)
    {
        return JNI_FALSE;
    }

    if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0)
    {
        return JNI_FALSE;
    }

    return JNI_TRUE;
}

这样函数动态注册就完成了,JAVA层调用和静态注册中使用方法一样。

五、总结

以上哪里写的不对或者有待改进,欢迎大家提意见,谢谢!
转载请注明出处:http://www.luoxudong.com/?p=360

有121人对 “Android总结-JNI原理及静态、动态注册”留言了

  1. Hello superb blog! Does running a blog like this require a large amount of work?
    I have no expertise in programming but I was hoping
    to start my own blog in the near future. Anyhow, if you have any ideas or techniques for new blog owners please share.

    I understand this is off topic nevertheless I simply wanted
    to ask. Thanks a lot!

  2. Gambling can be of several forms, with every type requiring its own legal structure.

    In Nevada, for instance, there is what’s called a”lawsuit” A suit is an agreement
    or a contract involving a individual placing a bet and the individual or
    group placing the cash at stake. In certain states, a”gaming accounts”
    is created in which cash deposited to the account is kept by means of a bookmaker and isn’t accessible to gamers; others allow
    online gambling but do not permit offline gaming. Finally, you will find”rollover” transactions in which the cash
    in a player’s account is withdrawn before it’s used.

    This way, the term gambling covers a vast range of trades and may refer to every one of them, as each has its own set of circumstances under which it may occur.

  3. [url=http://viagrawcialis.com/]viagra for women in india[/url] [url=http://buycialisviagra.com/]cialis 200mg price[/url] [url=http://viagrampro.com/]how to buy viagra online safely[/url] [url=http://tospharmacy.com/]pharmacy online australia free shipping[/url] [url=http://viagraitab.com/]price for viagra 100mg[/url] [url=http://pharmacygrand.com/]pharmacy com[/url] [url=http://viagracialisale.com/]cialis for women[/url]

  4. Do you have a spam issue on this site; I also am a blogger, and I was wanting to
    know your situation; many of us have developed some nice practices and we are looking to swap solutions
    with others, why not shoot me an e-mail if interested.

  5. Betting can be of several forms, with every type requiring its own legal structure.
    In Nevada, for instance, there is what is called a”suit.” A lawsuit is
    an agreement or a contract involving a individual placing a wager and the person or group putting the cash at stake.
    In certain states, a”betting account” is created in which money deposited into the account is retained by a bookmaker and is not available to players; others let
    online gambling but do not allow offline gaming. Finally, you
    will find”rollover” transactions where the money in a participant’s account is removed before it is used.
    In this manner, the expression gambling covers a wide range of trades and may refer to all
    of these, as each has its own set of circumstances under which it may occur.

  6. Hello! This is my first comment here so I just wanted to give a quick shout out and say
    I truly enjoy reading through your blog posts.
    Can you recommend any other blogs/websites/forums that deal
    with the same topics? Thank you so much!

  7. Its like you read my mind! You seem to know a lot about this, like you wrote the
    book in it or something. I think that you can do with
    some pics to drive the message home a bit, but instead
    of that, this is great blog. An excellent read. I’ll definitely be back.

  8. Thank you for any other informative website. Where else
    may just I get that kind of information written in such an ideal way?
    I have a undertaking that I am just now operating on,
    and I’ve been on the glance out for such info.

  9. Thanks a bunch for sharing this with all people you really know what you are talking about!
    Bookmarked. Kindly additionally discuss with my site =).
    We will have a hyperlink alternate agreement among us

  10. I’ve been exploring for a little for any high quality articles or weblog posts
    on this kind of house . Exploring in Yahoo I at last stumbled
    upon this web site. Studying this info So i am glad to
    show that I’ve an incredibly good uncanny feeling I came upon exactly what I needed.
    I so much for sure will make sure to do not overlook this website and give it a glance on a continuing basis.

发表评论

邮箱地址不会被公开。