강좌 & 팁
JNI_OnLoad() 함수를 이용하여 직접 native 함수를 등록하는 방법을 지난 시간에 알아보았습니다.
android 에서 잘 정리해 놓은 jniRegisterNativeMethods() 함수같은 형태만 잘 사용해도 큰 불편함없이 구현할 수 있습니다.
그 중에 JNINativeMethod 구조체에 대한 내용만 좀 더 정확히 알아보겠습니다.
1. 선언
/usr/lib/jvm/java-6-openjdk/include/jni.h
/* typedef struct { |
jni.h 에 위와 같이 선언되어 있습니다. 멤버를 살펴보면
name : java 에 선언되 함수의 이름. 문자열
signature : argumet 와 return value 에 대한 기호 문자열.
fnPtr : c / c++ 단에서 실제로 구현한 함수의 포인터.
위와 같습니다.
name 과 fnPtr 은 별도의 설명이 필요없고, signature 는 다음과 같은 규칙으로 적으면 됩니다.
Field Descriptor | Java Language Type |
---|---|
Z |
boolean |
B |
byte |
C |
char |
S |
short |
I |
int |
J |
long |
F |
float |
D |
double |
배열 : 앞에 "["를 붙임
객체 : L + class path + ;
Field Descriptor | Java Language Type |
---|---|
"Ljava/lang/String;" |
String |
"[I" |
int[] |
"[Ljava/lang/Object;" |
Object[] |
위 규칙을 바탕으로 () 안에 argument 를 순서대로 적고 그 이 후에 return value 를 적으면 됩니다.
그럼 Method signature 에 대한 예를 몇가지 보겠습니다.
Method Descriptor | Java Language Type |
---|---|
"()Ljava/lang/String;" |
String
f(); |
"(ILjava/lang/Class;)J" |
long f(int i, Class
c); |
"([B)V" |
String(byte[]
bytes); |
지난 시간에 예로 사용했던 com_android_server_AlarmManagerService.cpp 의 내용을 해석해 보면 다음과 같습니다.
static JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ {"init", "()I", (void*)android_server_AlarmManagerService_init}, {"close", "(I)V", (void*)android_server_AlarmManagerService_close}, {"set", "(IIJJ)V", (void*)android_server_AlarmManagerService_set}, {"waitForAlarm", "(I)I", (void*)android_server_AlarmManagerService_waitForAlarm}, {"setKernelTimezone", "(II)I", (void*)android_server_AlarmManagerService_setKernelTimezone}, }; |
=> int init();
void close(int);
void set(int, int, long, long);
int waitForAlarm(int);
int setKernelTimezone(int, int);
처음보면 암호같이 알 수 없는 문자들이지만, 알고나면 간단합니다.
이 기호는 JNI 에서 class 를 연동해서 사용할 때도 똑같은 적용되기 때문에, 알고 있으면 도움이 많이 됩니다.