Nomad Engineer

[Android NDK] Kotlin 객체와 C++ object 1:1 바인딩 하는방법 본문

개발/안드로이드

[Android NDK] Kotlin 객체와 C++ object 1:1 바인딩 하는방법

universehan 2021. 2. 28. 15:32

NDK문서를 찾아봐도 딱 내가 찾는 설명을 찾을 수가 없었다. 그래서 Android 코드를 찾아보기로 했다. 참고한 코드는 MediaRecord의 Native 코드.

 

MediaRecorder.java

우선 아래의 코드와 같이 자바의 MediaRecorder 클래스가 초기화 되는 순간에 네이티브 라이브러리를 로드하고 native_init() 라는 네이티브 함수를 호출한다. 그리고 생성자에서 packageName을 얻고 이것을 사용해서 또다른 네이티브 함수인 native_setup(...) 이라는 함수를 호출하는것을 볼 수 있다.

class MediaRecorder {
	// ...
    static {
        System.loadLibrary("media_jni");
        native_init();
    }
    
    public MediaRecorder() {
        // ...

        String packageName = ActivityThread.currentPackageName();
        /* Native setup requires a weak reference to our object.
         * It's easier to create it here than in C++.
         */
        native_setup(new WeakReference<MediaRecorder>(this), packageName,
                ActivityThread.currentOpPackageName());
    }

    // ...
    private static native final void native_init();   
    private native final void native_setup(Object mediarecorder_this,
            String clientName, String opPackageName) throws IllegalStateException;
}

android_media_MediaRecorder.cpp

네이티브 코드에는 실제 MediaRecorder를 생성하고 이를 자바 객체와 바인딩 하는 코드가 들어있다.

static void
android_media_MediaRecorder_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
                                         jstring packageName, jstring opPackageName)
{
    ALOGV("setup");

    ScopedUtfChars opPackageNameStr(env, opPackageName);

    sp<MediaRecorder> mr = new MediaRecorder(String16(opPackageNameStr.c_str()));
    if (mr == NULL) {
        jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
        return;
    }
    if (mr->initCheck() != NO_ERROR) {
        jniThrowException(env, "java/lang/RuntimeException", "Unable to initialize media recorder");
        return;
    }

    // create new listener and give it to MediaRecorder
    sp<JNIMediaRecorderListener> listener = new JNIMediaRecorderListener(env, thiz, weak_this);
    mr->setListener(listener);

    // Convert client name jstring to String16
    const char16_t *rawClientName = reinterpret_cast<const char16_t*>(
        env->GetStringChars(packageName, NULL));
    jsize rawClientNameLen = env->GetStringLength(packageName);
    String16 clientName(rawClientName, rawClientNameLen);
    env->ReleaseStringChars(packageName,
                            reinterpret_cast<const jchar*>(rawClientName));

    // pass client package name for permissions tracking
    mr->setClientName(clientName);

    setMediaRecorder(env, thiz, mr);
}

setMediaRecorder() 함수

static sp<MediaRecorder> setMediaRecorder(JNIEnv* env, jobject thiz, const sp<MediaRecorder>& recorder)
{
    Mutex::Autolock l(sLock);
    sp<MediaRecorder> old = (MediaRecorder*)env->GetLongField(thiz, fields.context);
    if (recorder.get()) {
        recorder->incStrong(thiz);
    }
    if (old != 0) {
        old->decStrong(thiz);
    }
    env->SetLongField(thiz, fields.context, (jlong)recorder.get());
    return old;
}

References

 

반응형