2013-10-17 1 views
19

나는 내 자신의 jni 소스를 작성하려고합니다. 일부 NDK 샘플을 보면, 나는 그들이 종종 내가 봤하지만 이해할 수없는 경우이Android NDK에서 JNIEXPORT 및 JNICALL을 사용하는 경우는?

JNIEXPORT void JNICALL Java_com_example_plasma_PlasmaView_renderPlasma(JNIEnv * env, jobject obj, jobject bitmap, jlong time_ms)

같은 자바 패키지의 이름으로 follewed 그 매크로 JNIEXPORT 및 JNICALL를 사용하는 것이 발견이를 사용하는 방법 매크로

답변

23

JNIEXPORT 및 JNICALL은 NDK_ROOT/platforms/android-9/arch-arm/usr/include/jni.h에 정의되어 있습니다. 설정에 따라이 경로는 달라 지지만 대부분 유사합니다.

#define JNIIMPORT 
#define JNIEXPORT __attribute__ ((visibility ("default"))) 
#define JNICALL 

JNIEXPORT는 빌드 된 바이너리 (* .so 파일)의 동적 테이블에 기본 함수를 표시하는 데 사용됩니다. "숨김"또는 "기본"으로 설정할 수 있습니다 (추가 정보 here). 이러한 함수가 동적 테이블에없는 경우 JNI는 호출 할 함수를 찾을 수 없으므로 런타임에 RegisterNatives 호출이 실패합니다.

모든 기능이 기본적으로 동적 테이블에 저장되므로 누구나 쉽게 네이티브 코드를 디 컴파일 할 수 있습니다. JNI가 그것을 찾아야하는 경우를 대비하여 모든 함수 호출은 바이너리에 내장되어 있습니다. 이 옵션은 컴파일러 옵션 -fvisibility을 사용하여 변경할 수 있습니다. 모든 사람들이 코드를 안전하게 유지하기 위해 이것을 -fvisibility=hidden으로 설정 한 다음 JNIEXPORT를 사용하여 함수에 외부 공개 여부를 표시하는 것이 좋습니다.

strip 명령을 사용하면 디버그 기호가 제거되고 동적 테이블은 분리됩니다. objdump로 놀아서 사람이 .so 파일에서 얼마나 벗어날 수 있는지 확인하십시오.

최근에 우리는이 문제로 인해 어려움에 처했습니다.

EDIT : 우리는 사용자 정의 빌드 시스템을 사용하므로 가시성 옵션이 다른 빌드 설정을 위해 기본적으로 설정 될 수 있습니다. 자세한 내용은 this SO answer에서 확인할 수 있습니다. 간단한 측면에서

+0

JNICALL은 무엇을 의미합니까? – Lealo

+1

JNICALL은 (위와 같이) 안드로이드에서 비어있는 정의이지만 플랫폼 호환성을 위해 존재합니다. Windows JDK JNICALL은'__stdcall' (https://msdn.microsoft.com/en-us/library/zxk0tw93.aspx)로 정의되어 있습니다. –

0

네이티브 클래스에서 'javah'를 실행하고 생성 한 모든 것을 사용하십시오. 100 % 신뢰도로 공구를 생산할 수있는 경우에는이 기능에 대해 알 필요가 없습니다.

+0

이 명령에 대해서는 잘 모릅니다. NDS 빌드 전에 사용합니까? – nawara

+0

나는 ndk-build에 대한 아이디어가 없지만 15 년 동안 JNI를 해왔다. 나는 javah와 javap 없이는 아무데도 가지 않을 것이다. 너는 항상 그것을 볼 수 있었다. – EJP

4

해당 매크로의 정의는 JNI의 기계 종속 부분 (일반적으로 $JAVA_HOME/include/<arch>/jni-md.h)에서 찾을 수 있습니다.

간단히 말해서 JNIEXPORT에는 주어진 함수를 올바르게 내보내는 데 필요한 컴파일러 지시문이 포함되어 있습니다. 안드로이드 (및 기타 리눅스 기반 시스템)에서는 비어 있습니다.

JNICALL에는 주어진 함수가 적절한 호출 규칙으로 처리되도록하기 위해 필요한 컴파일러 지시문이 포함되어 있습니다. 아마 안드로이드에서도 비어있을 것입니다 (w32에서는 __stdcall입니다).

일반적으로 비어 있어도 그대로 두어야합니다 (#define).

+1

Android의 일부 아키텍처에서는 JNICALL이 비어 있지 않습니다. JNICALL을 항상 사용해야합니다. registerNatives 계열의 함수를 사용하지 않는 경우에는 JNIEXPORT를 사용해야합니다. –

0

: 당신이 기능의 registerNatives 제품군을 사용하는 경우는

  • JNIEXPORT 당신은 JNIEXPORT을 사용할 수 없습니다. 그렇지 않으면 반드시 사용해야합니다.
  • JNICALL은 항상 사용해야합니다.

JNIEXPORT는 기호 테이블에 함수가 표시되는지 확인합니다. JNICALL은 함수가 올바른 호출 규칙을 사용하도록합니다. Android에서 JNICALL은 아키텍처에 따라 다른 가치를 가지고 있습니다. ARM은 비어있어 당신을 속여서 포함시키지 않습니다. 그러나 JNICALL을 사용해야합니다.

registerNatives을 사용하면 기능을 프로그래밍 방식으로 JNI_onLoad에 연결하거나 나중에 언젠가 연결할 수 있습니다. registerNatives은 이전에 잘못된 함수 이름을 포착 할 수 있으므로이 경로를 권장합니다.

관련 문제