반응형
#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");
    }
}
반응형