JS: too much recursion on Android

Sometimes after restoring the game from the background on Android the game stops responding to my JS event handlers and I get the following logcat output:

D/Cocos2dxActivity: onResume()
D/mali_winsys: new_window_surface returns 0x3000
D/mali_winsys: new_window_surface returns 0x3000
D/Cocos2dxActivity: onWindowFocusChanged() hasFocus=true
D/cocos2d-x debug info: reload all texture
D/cocos2d-x debug info: Dirty Uniform and Attributes of GLProgramState
D/cocos2d-x debug info: Dirty Uniform and Attributes of GLProgramState
D/cocos2d-x debug info: Dirty Uniform and Attributes of GLProgramState
D/cocos2d-x debug info: Dirty Uniform and Attributes of GLProgramState
D/cocos2d-x debug info: JS: :0:too much recursion
D/cocos2d-x debug info: JS: :0:too much recursion

All game items are drawn OK after restore, but on every tap on game UI buttons the last line “D/cocos2d-x debug info: JS: :0:too much recursion” is added to the log.

I googled this problem but all I could find is about thread problems in SpiderMonkey.

I also tried to build using different sdk targets in project.properties but the results are the same.

I use the following environment:
Cocos2d-x: 3.14
android:minSdkVersion=“13”
android:targetSdkVersion=“19”
Tested on Samsung Galaxy S5 (Android 6.0.1) and Huawei Honor 5C (Android 6.0)

Hey,
I am facing the same issue, any progress about it?

I thought the crash is random, now I know how to reproduce it 100% of the times:

  1. launch app via “Open” button at google play
  2. Minimize the app (pause)
  3. launch the app again via the app’s icon

A new GLThread is created, and spidermonkey call crashes

alonlevylll, thank you for replying.

In my case the cause was a sort of different. There were no any crashes, JS code just stopped to execute but C++ part of the game were completely OK.

Anyway I will describe my solution, maybe it will be useful for someone.

I found the cause and this was a surprise for me because my knowledge of Android is limited.

So the real cause of my problem was a method of launching of the app on a real device via

cocos run -p android

I found out that the cocos console utility uses the following adb command to launch the app after reinstalling it:

adb shell am start -n <package name>/.activityname

And after putting the app to the background and moving it back, cocos2d-x code was not able to correctly restore some states of JSB and any execution of JS code did generate the error “JS: :0:too much recursion”

But if I kill the app on the device and launch it form home screen again, it works without any problems.

So my solution was to replace “cocos run -p android” command to the following sequence:

cocos compile -p android
adb uninstall app.package.name
adb install -r simulator/android/appname-debug.apk
adb shell monkey -p app.package.name 1

The last last line is a key. After launching the app using this method, my problem disappears.

1 Like

Thank you very much axln,
You installation and launch process is a way for reproducing the issue.
In android the GLThread can be recreated when OnSurfaceCreated callback get called.

So it looks that in your case you just ignored the problem, but I think it still exists.
When you will publish the application to Google Play, or launch from notifications Android creates a new GLThread.
The spidermonkey crashes when running from another thread.

I did some prints of the GLThread ID at onDrawFrame, and notice that when it keeps the same, all works great.
However, randomly Android calls OnSurfaceCreated.

alonlevylll, sorry for the late reply.

You’re absolutely right. My app isn’t published yet. but I tried to build the release version of the app and got the same problem. When I install it via the apk file located on SD card then move it to the background and launch it again from the launcher screen, I also get the message “app has stopped.”.

Did you post the issue on cocos2d-x github’s page?

Yeah I post the issue:

1 Like

Hey alonlevylll,

Maybe it’s a dirty hack but I found a workaround. Just add the attribute android:launchMode="singleTask" to the activity in AndroidManifest.xml, so now it is:

<activity android:name="org.cocos2dx.javascript.AppActivity"
            android:label="@string/app_name"
            android:launchMode="singleTask"
            android:screenOrientation="portrait"
            android:theme="@style/AppTheme"
            android:configChanges="orientation|keyboardHidden|screenSize">
      <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
</activity>

After this Android will no longer kill the main activity and it is just resumed after process moved back from the background.