温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

android内核剖析系列---JNI调用机制分析

发布时间:2020-07-21 02:10:41 来源:网络 阅读:419 作者:3542534801 栏目:移动开发

为什么需要JNI?

android这个庞大的系统从下到上主要由linux内核,C/C++库,java应用程序框架,java应用程序组成。这就涉及到一个问题,C/C++库如何与java应用有交集,或者说能相互调用,要解决这个问题,就需要JNI登场了。


JNI调用机制分析

JNI--java native interface,翻译成中文是java本地接口,所谓的“本地”是指C/C++库一层的C/C++语言(以下统称C)。

上文提到,JNI是为解决C和Java相互调用的问题而诞生的。C和Java相互调用无非就是两个方面,Java调用C和C调用Java。


Java调用C函数

如果你只定义了一个函数,而将它的实现交给C,那么就将它定义为native类型好了。你或许会问了,我用Java定义了一个函数,但我却没用Java实现之,当我调用这个函数的时候,Java编译器不会报错吗?答案是否定的,Java编译器在遇到native类型的函数时,不会关心该函数的具体实现,相当于native类型告诉Java编译器,“喂,老兄,我实现了,只不过我不是用你的语言(Java)实现的,我是用别的语言(C)实现的”,所以编译时Java编译器不会报错,只不过在调用native类型的函数前,程序员必须把C生成的动态库装载进内存,否则程序会因为找不到相应的native方法而出错。

Java和C本不是同种语言,硬要让它们能相互调用的话,我们就要遵循某种规范(就像ARM汇编和C相互调用时也要遵循某种规范一样)。

规范:methodname_C = Packagename + methodname_Java。什么意思呢?在C中定义的函数名称 = 包名 + 在Java中定义的函数名称。还不明白?我们来举个例子来看一下。

java:private native final void init()

C:static void android_content_AssetManager_init(JNIEnv *env,jobject clazz)

可以看到对应的C函数多了两个参数,看起来莫名其妙,但这其实能让C访问Java对象或函数,JNIEnv对象是一个Java虚拟机所运行的环境,jobject是调用该函数的对象。我们稍后会讲到。

为什么C中的函数要加上包名呢?这不是多此一举吗?

这是有必要的,这是为了区分开不同包的两个同名函数,能够让Java编译器找到正确的那个函数。事实上,Java调用native函数时,编译器会向native引擎传递调用者的包名,以及函数名称,还有参数类型,以便可以根据这些信息找到正确的本地的那个函数。


C调用Java函数或者访问Java变量

正如Java调用C函数一样,Java把类名、函数名称和参数类型传递给native引擎,然后由native引擎处理(正确找到并调用)C函数。同理,C调用Java时,也需要把想要访问的类名、函数名称和参数传递给Java引擎。步骤如下:

1)获取Java对象的类

jclass cls = env->GetObjectClass(jobject),还记得env和jobject吗?没错,就是那两个参数。现在知道那两个参数的重要性了吧。不过,这也意味着C调用Java函数只能在Java调用C函数体中进行。

2)获取Java函数的id值

jmethodId mid = env->GetMethodId(cls,"methodname","(Ljava/lang/String;)V"),前两个参数不必说,第三个参数值得注意,它代表了Java函数的参数和返回值,参数在括号之中,返回值在括号之外。

3)找到了函数后,就可以调用该函数了

env->CallXXXMethod(jobject,mid,ret),其中XXX代表了返回值的类型,


向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI