Android/Android Native
[Android Native] JNI 멀티스레드에서 함수 호출하기
2024. 8. 9. 01:31반응형
#include <jni.h>
#include <string>
#include <android/log.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
static JavaVM* gJavaVm;
static jclass gKeyboardClass;
#define LOG_TAG "TEST123"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved __attribute__((unused))) {
JNIEnv *env;
if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
LOGE("Failed to get JNI environment");
return -1;
}
gJavaVm = vm;
gKeyboardClass = env->FindClass("edu/gatech/seclass/sdpencryptor/Keyboard");
if (gKeyboardClass == NULL) {
return -1;
}
gKeyboardClass = (jclass) env->NewGlobalRef(gKeyboardClass);
// 반드시 return을 해주어야 한다. 그렇지 않으면 에러 발생한다.
return JNI_VERSION_1_6;
}
extern "C" JNIEXPORT jstring JNICALL
Java_edu_gatech_seclass_sdpencryptor_MainActivity_stringFromJNI(JNIEnv* env, jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
extern "C"
JNIEXPORT void JNICALL
Java_edu_gatech_seclass_sdpencryptor_Keyboard_onClick(JNIEnv *env, jobject thiz) {
// 1. 정적 메서드 ID 얻기
jmethodID getInstanceMethod = env->GetStaticMethodID(gKeyboardClass, "getInstance",
"()Ledu/gatech/seclass/sdpencryptor/Keyboard;");
if (getInstanceMethod == NULL) {
printf("Failed to get getInstance method ID\n");
return; // 메서드가 존재하지 않으면 종료
}
// 2. 정적 메서드 호출 (객체를 얻기 위해)
jobject keyboardInstance = env->CallStaticObjectMethod(gKeyboardClass,
getInstanceMethod);
if (keyboardInstance == NULL) {
printf("Failed to call getInstance method\n");
return; // 메서드 호출 실패 시 종료
}
// 여기 까지 Single 객체 얻는 것이 완료.
// ---- ---- ---- ---- ---- ---- ---- ----
// 4. 해당 객체에서, onNotified 메서드 ID 얻기
jmethodID onNotifiedMethod = env->GetMethodID(gKeyboardClass, "onNotified", "(Ljava/lang/String;[B)V");
if (onNotifiedMethod == NULL) {
printf("Failed to get onNotified method ID\n");
return; // 메서드가 존재하지 않으면 종료
}
// type에 "SHIFT" 문자열 전달
jstring type = env->NewStringUTF("SHIFT");
// data에 "hello world" 문자열 바이트 배열로 전달
const char* helloWorld = "hello world";
jbyteArray data = env->NewByteArray(strlen(helloWorld));
env->SetByteArrayRegion(data, 0, strlen(helloWorld), (const jbyte*)helloWorld);
// onNotified 메서드 호출
env->CallVoidMethod(keyboardInstance, onNotifiedMethod, type, data);
// 예외 체크
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
}
}
void* run(void* arg) {
JNIEnv* env;
JavaVM* jvm;
jclass cls;
jmethodID mid;
jobject globalObj = (jobject)arg;
// 현재 JVM 인스턴스를 가져옵니다.
extern JavaVM* gJavaVm;
jvm = gJavaVm;
// 현재 스레드를 JVM에 연결
if (jvm->AttachCurrentThread(&env, NULL) != 0) {
LOGE("Failed to attach thread to JVM\n");
return NULL;
}
// Find the Java class and method
cls = env->GetObjectClass(globalObj);
if (cls == NULL) {
fprintf(stderr, "Failed to find class\n");
jvm->DetachCurrentThread();
return NULL;
}
mid = env->GetMethodID(cls, "onAlarm", "()V");
if (mid == NULL) {
fprintf(stderr, "Failed to find method ID\n");
jvm->DetachCurrentThread();
return NULL;
}
// Call the Java method
env->CallVoidMethod(globalObj, mid);
// Clean up and detach the thread
env->DeleteGlobalRef(globalObj);
jvm->DetachCurrentThread();
}
extern "C"
JNIEXPORT void JNICALL
Java_edu_gatech_seclass_sdpencryptor_Keyboard_onStartThread(JNIEnv *env, jobject thiz) {
LOGE("onStartThread called");
pthread_t t;
jobject globalObj = env->NewGlobalRef(thiz);
if (pthread_create(&t, NULL, &run, globalObj)) {
LOGE("pthread_create failed");
}
}
반응형
'Android > Android Native' 카테고리의 다른 글
[Android Native] 예제: JNI에서 Singleton 객체의 메서드 함수 호출하기 (0) | 2024.08.09 |
---|---|
[Android Native][JNI] CMakeLists.txt에 원하는 CPP파일 추가하기 (0) | 2024.08.09 |
[Android Native] Abort message: 'JNI DETECTED ERROR IN APPLICATION: JNI ERROR (app bug): jclass is an invalid local reference: XXXX (0) | 2024.08.09 |
[Android] JNI method signature에 대한 고찰 (0) | 2024.08.09 |
[Android][JNI] 멀티쓰레드 관련 Stack overflow 정리 (0) | 2024.08.05 |