[SOLVED] Game crashes when calling Lua method from Java

I am building a game with Cocos2d-x v3.4 beta0. I have experienced this crash from version 3.2, 3.3 rc1 as well.

I am having issues with my game crashing whenever I attempt to call a Lua method from Java (Android platform). Please note that the same issue does not occur on iOS.

Here is the order of operation:

  1. Lua makes a call to the main Java activity. This is done via a custom C binding; similar to how the auto Lua C bindings are done.
  2. The custom C binding then makes a call to an NDKHelper method SendMessageWithParams.
  3. The Java activity receives the message and responds by calling a native call (a C function).
  4. The native call invokes a static method on another custom library that provides a thin layer between the Java code and the Lua state. All it does is call a method on the Lua state.
  5. The Lua state responds to the message by having the respective function invoked and continues processing.

Everything works. Even step 5 continues to process until it crashes after performing a few Lua operations. In many cases I get very strange errors. These being the most common:

W/Adreno-ES20( 4011): <core_glBufferSubData:1234>: GL_INVALID_VALUE
D/cocos2d-x debug info( 4011): OpenGL error 0x0501 in /Users/eric/git/BlobfishEvolution/Cocos2d-x/frameworks/runtime-src/proj.android/../../cocos2d-x/cocos//./renderer/CCTextureAtlas.cpp drawNumberOfQuads 689
D/cocos2d-x debug info( 4011):
W/Adreno-ES20( 4011): <gl_draw_error_checks:575>: GL_INVALID_OPERATION
D/cocos2d-x debug info( 4011): OpenGL error 0x0502 in /Users/eric/git/BlobfishEvolution/Cocos2d-x/frameworks/runtime-src/proj.android/../../cocos2d-x/cocos//./renderer/CCTextureAtlas.cpp drawNumberOfQuads 689

It never crashes at the same spot. In fact, sometimes, it continues to process once the action is invoked. However, because of the GL issues, it fails to render fonts that are created during the callback. In most cases, however, the app simply crashes. In almost every case it crashes when the action is taken more than once (a button is clicked to display ads).

I feel like I’m doing something wrong. The iOS version works perfectly. No issues. But Android, it always crashes when calling this native method to update the state of the view after a callback from Java.

After digging around for hours I discovered it may have been that I was calling the native method on a thread. I went ahead and called the native method, using the code below, on the Activity’s UI thread. Same issue.

this.runOnUiThread(new Runnable() {
    @Override
    public void run() {
        VideoAdsEnabled(isAdColonyAvailable);
    }
});

I feel like I have exhausted every avenue. The only thing that I can think of is that, because I’m returning immediately after receiving the call from Lua, I’m somehow invalidating the Lua state. Essentially, Lua hasn’t finished whatever it was doing when it called the Java’s Activity, and by calling the method (back to Lua) directly after receiving the message from Lua, it’s causing an issue. I feel like that idea was debunked with the above code… but it could just be my complete misunderstanding of how this works.

Really, all I want to do is send messages to and from Lua. On iOS I want to do it from Objective-C to Lua and back. On Android I want to do it from Java to Lua and back. It seems like this problem has been solved already, but I simply can not find any documentation that might suggest otherwise.

One thing I did see that there is a Lua Plugin manager. I really wish I would have found that earlier; as I might have just modeled this API using the plugin manager.

Is it possible that I’m not making the lib call on the same thread that Cocos2d is running on? I realize that Cocos2d is not thread-safe. How do I know if I’m calling Cocos2d on the right thread?

Moving on; It looks like there is an option of passing messages using CCCallFunc and then running it with CCSequence. Some of the libraries, that do something similar to what I’m trying to do, go this route. I’ll research this a bit. Still, I’m worried that by making any Cocos2d lib call on the wrong thread won’t solve this issue.

Figured it out. The call MUST be made on the GL thread; which is what Cocos2d appears to be running on. I was always running it on the UI thread. This is exactly what I thought the problem was. All of the behaviour had the hallmarks of state becoming “undefined” and would never crash in the same spot of code. This is how I ended up making the callback in Java.

public void IsVideoEnabled(JSONObject params)
{
    Log.d(TAG, ">>> IsVideoEnabled <<<");
    this.runOnGLThread(new Runnable() {
        @Override
        public void run() {
            VideoAdsEnabled(isAdColonyAvailable);
        }
    });
}
1 Like