Android native调用分析(JNI)

1. 为什么需要native?

2. java层(或者说dalvik)如何识别native函数?

3. java层到native的调用是如何实现的?

4. java和native工作在同一进程吗?

5. native 受dalvik管理吗?


带着这些问题,接下来逐步去分析总结,相信是会有收获的。


一、为什么需要native。

       1.  不可反编译。native 编译出来的是目标代码,不可反编译。java编译出来的中间代码可反编译,可反编译可能会导致自己设计思想或者设计算法泄露,很多商业公司是极力避免的。

       2. 执行速度快。native 代码一般用c/c++ 实现,执行速度上要比java快些。

       3. 方便移植。有些应用在没有android之前,都是用c/c++ 开发的,那么现在要移植到android上,直接移植到native层就不需要另外编写java代码,省时省力。


二、java(或者说dalvik)如何识别native函数

       native函数声明会带有native字符,如下例子:

             private static native long nativeInit(InputManagerService service,
            Context context, MessageQueue messageQueue);

       这样编译的时候就把这个native标志位加入到java 函数符号表里,这样就可以和普通的函数区分开了,运行过程虚拟机执行到native函数时就会切换到native执行环境。执行环境是如何切换的呢?还没研究过。

            

三、java到native的调用是如何实现的

     1. 每个虚拟机进程都对应一个JNI环境(JNIEnv)

     2. 每个native方法都需要向这个JNI环境测试注册

     3. 这些native方法及实现会被编译成一个动态库

     4.java层在执行到native代码前需要把这个动态库load进来。之后整个虚拟机进程的JNI环境就包含了native方法入口。

     5. java层在执行到native代码时就能通过JNI环境知道native层对应实现。


     接下以事件输入系统为例做下分析:

    1. native 方法定义数组,格式如下,第一个字段对应的是在java层函数名,第二个是函数形式参数缩写,第三个是native层对应的函数名。

     

        java 层函数形参和native层是有区别的,需要做转换。下面是基本类型转换

缩写native 层java 层
Vvoidvoid
Zjbooleanboolean
Ijintint
Jjlonglong
Djdoubledouble
Fjfloatfloat
Bjbytebyte
Cjcharchar
Sjshortshort
[IjintArrayint[]
[FjfloatArrayfloat[]
[BjbyteArraybyte[]
[CjcharArraychar[]
[SjshortArrayshort[]
[DjdoubleArraydouble[]
[JjlongArraylong[]
[ZjbooleanArrayBoolean[]
对象类型转换:

如下 (JLandroid/view/InputEvent 表示转下来的是一个java 对象类型
{ "nativeInjectInputEvent", "(JLandroid/view/InputEvent;IIIIII)I",
(void*) nativeInjectInputEvent },

如下Ljava/lang/String 是java字符串类型
"processDirectory",
"(Ljava/lang/String;Landroid/media/MediaScannerClient;)V",
(void *)android_media_MediaScanner_processDirectory
在native中需要做如下转换 const char *pathStr = env->GetStringUTFChars(path, NULL);

2. 注册方法
第一行把gInputManagerMethods 方法注册到JNI环境里,jniRegisterNativeMethods 函数第二个参数意思是这些方法和java层com/android/server/input/InputManagerService 类对应,也就是说将在java层的 InputManagerService 类调用这些native方法。
第四行开始做java层到native层的映射,因为消息不仅仅从java层传递到native层,还有可能从native层传到java层。
FIND_CLASS用来找到java层对应的类;
GET_METHOD_ID 用来找到java层这个类里对应的方法,并保存起来,如gServiceClassInfo.notifyConfigurationChanged。之后native层就可以直接通过gServiceClassInfo.notifyConfigurationChanged 给java层专递消息了,其实就是调用java层代码。

3. 编译成动态库
InputManager native层最终会被编译到libandroid_servers里面,并放在system/lib下。
4. 加载动态库。
libandroid_servers 在systemServer里面加载。这里只需要提供模块名就可以了,系统会自动搜索应用lib 目录下和 vendor/lib system/lib 下是否有对应的库。
四、 java和native工作在同一进程,一个应用对应一个进程,native是由应用进程load的进来并启动的,所以肯定都是在同一个进程运行,在同一个进程空间。
五、 native 受dalvik管理吗
我理解native和dalvik是同一等级的东西,不受dalvik管理。dalvik是用来对java代码进行解析执行,同时负责堆栈管理,线程管理,对象生命周期管理,内存分配垃圾回收等。dalvik 虚拟机本身也是基于c/c++ 编写的,是可执行的目标文件,native 层同样也是可执行的目标文件,所以它们应该是平级的,由linux系统管理运行。因此native层的内存管理,线程管理也是由linux系统管理的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值