Calling native code from Java: 'MagicLeapNativeAppGlue' notes?

Our problem in a nutshell is this: when we call our native code from Java, we don't execute the normal 'android_main', which normally receives app state. We can manually instantiate our methods, as shown in the code attached, but in that case app state is a null pointer since apparently we're missing something about polling the 'MagicLeapNativeAppGlue' to use the app state. We're trying to get the native app state for a global instance via the following. This compiles and links but triggers an exception when run on ML2:

extern "C" JNIEXPORT void JNICALL
Java_org_pytorch_demo_revok_MainActivity_00024pollRGBCamera_initializeCamera(JNIEnv *env, jobject /* this */, jlong nativeAppState) {
    // Initialization code here
    ALOGI("Initializing gCameraPhotoApp");
    gCameraPhotoApp = CameraPhotoApp::getInstance(reinterpret_cast<android_app *>(nativeAppState));

    if (gCameraPhotoApp != nullptr) {
        gCameraPhotoApp->InitializeCamera();
    } else {
        if (env->ExceptionCheck()) {
            env->ExceptionDescribe();
            env->ExceptionClear();
        }
    }
}

Any advice on how to get app state via 'MagicLeapNativeAppGlue' or another method?

I take it Magic Leap provides 'MagicLeapNativeAppGlue' as its own mechanism for launching native code from a Java activity. If that's the case, it would be great to confirm that. We would need to follow the Magic Leap-specific guidelines for initializing native code from Java, so any reference would be very helpful.

In the ML world, I believe Android activity life cycle is controlled in Java and that android_main is called by AppGlue, not called by the OS. I believe ML AppGlue pairs android.app.NativeActivity in Java with android_native_app_glue.c in the main library which launches proxy events to a separate thread(s) in our native .so libraries.

to illustrate, here are snippets of our code to call initialization for the ML2 RGB camera using JNI:

extern "C" JNIEXPORT void JNICALL
Java_org_pytorch_demo_revok_MainActivity_00024pollRGBCamera_initializeCamera(JNIEnv *env, jobject /* this */, jlong nativeAppState) {

    if (gCameraPhotoApp != nullptr) {
        gCameraPhotoApp->InitializeCamera();
    } else {
        if (env->ExceptionCheck()) {
            env->ExceptionDescribe();
            env->ExceptionClear();
        }
    }
}

In C++ we compile to libraries which we load in Java and access through the entry points illustrated above:

// Declare native methods
public native void initializeNative(long nativeAppState);

public class pollRGBCamera {
    public pollRGBCamera() {
        System.loadLibrary("camera_photo");
    }

    // Declare native method
    public native void initializeCamera();
    public native void captureImage();

Hi @kevincain,

Thank you for bringing this to our attention. I am more than happy to help solve this issue. Would you mind sharing the version of the ML C SDK that you are using if applicable? I have reached out to our team and I will report back as soon as I learn more.

Best,

El

Thanks @etucker, to answer you we have tested against both the native v1.3.0-dev1 and v1.3.0-dev2 releases. However, I don't think the ML camera capture functions have meaningfully changed for some time, so any recent build is likely to be sufficient to duplicate our results.

Hi @kevincain,

This is not the case. MagicLeapNativeAppGlue is just a helper library for developers who want to write purely Native (c++) code using the app_framework we ship in the MLSDK. Devs should use the standard Android JNI mechanism to invoke native APIs from the Java land.

Is there any documentation for 'MagicLeapNativeAppGlue'?

In particular, how does MagicLeapNativeAppGlue transfer app state between Java and C++ methods?

The code excerpts I gave show I'm calling native routines from Java in the typical way: state is not being handling as I expect, and it seems if there is nothing special about MagicLeapNativeAppGlue

It's best not to rely on the 'MagicLeapNativeAppGlue' for your production apps. The glue code was only meant for demonstration purposes and we do not plan on supporting it. Instead, we recommend that you follow standard android practices to invoke JNI code from java apps. If you understand the risks and still want to know how it is done then I can share it with you privately upon your request.

Best,

El

Thanks @etucker, but I'm surprised. On inspection 'MagicLeapNativeAppGlue' is a cmake wrapper -- I'm not sure there's any code in there to be unsupported.

Do you know of any demonstration that runs on ML calling native code from Kotlin/Java? That would be a big help.

I have shared an example with you privately.