Display name
Display name

Reputation: 730

C++ library causing crash in native Android

I am learning how to implement C++ projects into native Android and found myself a C++ library to import. Everything works great, but the problem is when onBackPressed() is called, the user is directed to the previous fragment as expected, but when they re-enter the Activity which is populated by the C++ library, a crash happens.

The only error I am given is A/libc: Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x8 in tid 9408 (GLThread 27055), pid 9296 (fluidSimulation)

I started to do some digging in the gl_code.cpp file where I pass values to exposed C++ methods and I believe I have identified the issue, but I am stuck on a fix...

There is the following C++ method that is called each time the Activity is created:

//This is global as it is used in other methods
void *fluid; 

extern "C" JNIEXPORT void JNICALL
Java_com_android_ui_fluidSimulation_FluidLib_init(JNIEnv *env, jobject obj, jint width,
                                                  jint height) {
    fluid = fluidCreate((int) width, (int) height);
} 

Now, I have figured out that the fluid pointer is being held in memory after the activity is exited when onBackPressed() is called. I have worked out that this method needs to be called each time the activity starts, but I need to understand how to reset the pointer.

I have tried delete fluid; before calling fluidCreate, but this doesn't work. Is there a work around for this problem or am I at the mercy of the library and better off abandoning it?

UPDATE 1

So, every frame the below method is called and I have noticed the crash happens when the fluid is added to the frame.

static double now_ms(void) {

    struct timespec res;
    clock_gettime(CLOCK_REALTIME, &res);
    return 1000.0 * res.tv_sec + (double) res.tv_nsec / 1e6;

}

extern "C" JNIEXPORT void JNICALL
Java_com_android_ui_fluidSimulation_FluidLib_step(JNIEnv *env, jobject obj) {

    double t = now_ms();
    //Below is printed
    __android_log_write(ANDROID_LOG_ERROR, "Tag", "Gets before fluidOnFrame");
    fluidOnFrame(fluid, t);
    //Below is is not printed
    __android_log_write(ANDROID_LOG_ERROR, "Tag", "Gets after fluidOnFrame");
}

These methods are called in Native Android as follows:

private class Renderer : GLSurfaceView.Renderer {

    override fun onDrawFrame(gl: GL10) {
        FluidLib.step()
    }

    override fun onSurfaceChanged(gl: GL10, width: Int, height: Int) {

        FluidLib.init(width, height)

    }

    override fun onSurfaceCreated(gl: GL10, config: EGLConfig) {
        // Do nothing.
    }
}

The methods used are defined as follows:

object FluidLib {
/**
 * @param width the current view width
 * @param height the current view height
 */
external fun init(width: Int, height: Int)
external fun destroy()
external fun step()

init {
    System.loadLibrary("gl_code")
  }
}

My file to interact with the C++ library:

/**
 * C-Style API to enable the fluid component to be used with C-based clients (i.e. Swift)
 */

#ifndef Fluid_h
#define Fluid_h

enum PointerType {
    MOUSE = 0,
    TOUCH = 1,
    PEN = 2
};

#ifdef __cplusplus
extern "C" {
#endif

    void* fluidCreate(int width, int height);  
    void fluidOnFrame(void* fluidPtr, double frameTime_ms);

#ifdef __cplusplus
}
#endif

#endif /* Fluid_h */

UPDATE 2

To try to understand the cause of the problem better, I ended up creating an if statement around my fluidCreate method to see if it was the pointer or some other issue as follows:

void *fluid;
void *newFluid;

extern "C" JNIEXPORT void JNICALL

Java_com_android_ui_fluidSimulation_FluidLib_init(JNIEnv *env, jobject obj, jint width,
                                                  jint height) {

    if(fluid == 0) {
        fluid = fluidCreate((int) width, (int) height);
    }else{
        newFluid = fluidCreate((int) width, (int) height);
    }

}

Then did the following on my method that's called each frame:

extern "C" JNIEXPORT void JNICALL
Java_com_android_ui_fluidSimulation_FluidLib_step(JNIEnv *env, jobject obj) {

    double t = now_ms();

    if(newFluid == 0) {
        __android_log_write(ANDROID_LOG_ERROR, "Tag", "Original Fluid on Frame");
        fluidOnFrame(fluid, t);
    }else{
        __android_log_write(ANDROID_LOG_ERROR, "Tag", "New Fluid on Frame");
        fluidOnFrame(newFluid, t);
    }
}

Now, even though different pointers are used, the crash is still caused, which makes me think that there seems to be a bug in the C++ library fluidOnFrame method...

Upvotes: 1

Views: 237

Answers (1)

Reaz Murshed
Reaz Murshed

Reputation: 24211

I think you are in the right direction. The crash log looks like a memory exception to me as well and I think the memory is not properly freed.

The fluid pointer needs to be destructed while you are exiting your activity. I would like to recommend writing another function as follows.

extern "C" JNIEXPORT void JNICALL
Java_com_android_ui_fluidSimulation_FluidLib_destroy(JNIEnv *env) {
    delete fluid;
}

And call this function in your Activity's onPause or onDestroy function.

I hope that will destroy the memory reference and will avoid the Fatal signal 11 (SIGSEGV) crash issue that you are having.

Upvotes: 1

Related Questions