Android系统JNI的实现方式

Android系统JNI的实现方式

All rights reserved

JNI(Java Native Interface)定义了一种Java代码调用C或者C++代码等其他代码的方式。

Android系统中,JNI通过JNINativeMethod结构体进行描述,该结构体定义于jni.h,如下所示:

?
1
2
3
4
5
typedef struct {
     const char * name;
     const char * signature;
     void *       fnPtr;
} JNINativeMethod;

第一个参数name:是Java代码中的函数名。

第二个参数signature:用于描述函数的参数和返回值。

第三个参数fnPtr:C代码中函数的指针。

其中,第二个参数为一个描述函数参数和返回值的字符串,字符串的格式如下:

(XX..)X

X的取值和定义如下所示:

字符

Java类型

C类型

V

void

void

Z

jboolean

unsigned char

B

jbyte

signed char

C

jchar

unsigned short

S

jshort

short

I

jint

int

J

jlong

long

F

jfloat

float

D

jdouble

double

另外,从jni.h中对于变量类型的定义中也可以看到这些字符的意义,如下所示:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
typedef unsigned char   jboolean;       /* unsigned 8 bits */
typedef signed char     jbyte;          /* signed 8 bits */
typedef unsigned short  jchar;          /* unsigned 16 bits */
typedef short           jshort;         /* signed 16 bits */
typedef int             jint;           /* signed 32 bits */
typedef long long       jlong;          /* signed 64 bits */
typedef float           jfloat;         /* 32-bit IEEE 754 */
typedef double          jdouble;        /* 64-bit IEEE 754 */
 
typedef union jvalue {
     jboolean    z;
     jbyte       b;
     jchar       c;
     jshort      s;
     jint        i;
     jlong       j;
     jfloat      f;
     jdouble     d;
     jobject     l;
} jvalue;

例如,为一个驱动添加HAL层,并创建JNI层。仅就JNI层而言,创建frameworks/base/services/jni/com_android_server_DemoService.cpp文件,该文件中用于描述JNI接口的代码如下所示:

?
1
2
3
4
5
static const JNINativeMethod method_table[] = {
                 { "init_native" , "()I" , ( void *)demo_init},
                 { "setVal_native" , "(II)V" , ( void *)demo_setVal},
                 { "getVal_native" , "(I)I" , ( void *)demo_getVal},
         };

其中“(II)V”,表示函数的有两个整形参数,返回值为void。

注意:由参数二指定的函数参数和返回值类型一定要和C函数的参数和返回值保持一致,否则虽然编译能够通过,但在Android系统加载过程中,会报如下所示的错误,导致Android系统无法正常运行。

?
1
2
3
4
5
E/dalvikvm( 1737 ): ERROR: couldn't find native method
E/dalvikvm( 1737 ): Requested: Lcom/android/server/DemoService;.init_native:()Z
E/dalvikvm( 1737 ): Candidate: Lcom/android/server/DemoService;.init_native:()I
E/JNIHelp ( 1737 ): RegisterNatives failed for 'com/android/server/DemoService' , aborting
F/libc    ( 1737 ): Fatal signal 11 (SIGSEGV) at 0xdeadbaad (code= 1 ), thread 1737 (system_server)

以上错误通发生在frameworks/base/services/jni/onload.cpp文件中的JNI_OnLoad()函数中,如下所示:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
extern "C" jint JNI_OnLoad(JavaVM* vm, void * reserved)
{
     JNIEnv* env = NULL;
     jint result = - 1 ;
 
     if (vm->GetEnv(( void **) &env, JNI_VERSION_1_4) != JNI_OK) {
         ALOGE( "GetEnv failed!" );
         return result;
     }
     ALOG_ASSERT(env, "Could not retrieve the env!" );
     ……  
     <strong>register_android_server_DemoService(env);</strong>
     ……
     return JNI_VERSION_1_4;
}

另外,ProGuard对程序的优化也可能导致上述运行错误的发生。此时,可以在makefile文件中添加“LOCAL_PROGUARD_ENABLED:=disabled”宏来关闭ProGuard的优化。

关于ProGuard,可以参考其官方网站:http://proguard.sourceforge.net/

ProGuard是一个免费的Java类文件压缩器、优化器、混淆器和预校验器。它会检测并删除没有用到的类、域、方法以及属性。它最大限度的优化字节码并且删除无用的指令。它用很短的没有意义的名字对剩余的类、域和方法进行重命名。最后,它对处理过的代码进行预校验。

ProGuard的一些用途如下:

A.为了更小的代码档案、更快的网络传输、更快的加载速度和更小的内存占用创建更紧凑的代码;

B.使程序和库难于进行反向工程;

C.列出死代码,这样就能将其删除;

D.为Java 6或更高的版本对存在的类文件进行重定位和预校验,以充分利用其快速加载类的性能。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dxmcu

谢谢鼓励!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值