我试图解决从Android 5.x上的Cocos2d-x键盘输入崩溃的问题,这是因为我从带有在键盘上找到的许多表情符号的文本创建CCImage的(尽管有些工作,但是大多数却没有。)在Android 4.x上,设备仅显示乱码的文本/其他字符。崩溃的根源是JNI的NewStringUTF()调用。它根本不支持Android 5 / Lollipop中的所有2、3、4字节utf-8字符。
此崩溃发生在使用带有工具链4.8的NDK 10e的cocos2d-x v2.2.6(并在3.x上得到确认)(不确定其中是否有太大的不同,我们在使用Android Studio和I之前使用了9d)可以肯定我们遇到了这个问题,但棒棒糖的使用量却少得多。)
如果您从不按任何未经修改的utf-8符号(即坚持使用ascii),则可能永远不会看到此问题。
Log Cat: 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] string: '' 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] in call to NewStringUTF 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] from void org.cocos2dx.lib.Cocos2dxHelper.nativeSetEditTextDialogResult(byte[]) 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] "GLThread 45716" prio=5 tid=14 Runnable 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] | group="main" sCount=0 dsCount=0 obj=0x12c0c6c0 self=0xf442bc00 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] | sysTid=10959 nice=0 cgrp=default sched=0/0 handle=0xf450c380 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] | state=R schedstat=( 0 0 0 ) utm=1164 stm=188 core=2 HZ=100 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] | stack=0xeed4e000-0xeed50000 stackSize=1036KB 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] | held mutexes= "mutator lock"(shared held) 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] native: #00 pc 00004e64 /system/lib/libbacktrace_libc++.so (UnwindCurrent::Unwind(unsigned int, ucontext*)+23) 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] native: #01 pc 00003665 /system/lib/libbacktrace_libc++.so (Backtrace::Unwind(unsigned int, ucontext*)+8) 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] native: #02 pc 00271461 /system/lib/libart.so (art::DumpNativeStack(std::__1::basic_ostream>&, int, char const*, art::mirror::ArtMethod*)+84) 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] native: #03 pc 002534d7 /system/lib/libart.so (art::Thread::Dump(std::__1::basic_ostream >&) const+158) 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] native: #04 pc 000b7f5b /system/lib/libart.so (art::JniAbort(char const*, char const*)+610) 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] native: #05 pc 000b8681 /system/lib/libart.so (art::JniAbortF(char const*, char const*, ...)+68) 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] native: #06 pc 000bac4f /system/lib/libart.so (art::ScopedCheck::Check(bool, char const*, ...) (.constprop.129)+922) 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] native: #07 pc 000c474d /system/lib/libart.so (art::CheckJNI::NewStringUTF(_JNIEnv*, char const*)+44) 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] native: #08 pc 002a6324 /data/app/com.appsomniacs.da2.debug-1/lib/arm/libcocos2dcpp.so (_JNIEnv::NewStringUTF(char const*)+40) 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] native: #09 pc 0076eb6c /data/app/com.appsomniacs.da2.debug-1/lib/arm/libcocos2dcpp.so (cocos2d::BitmapDC::getBitmapFromJavaShadowStroke(char const*, int, int, cocos2d::CCImage::ETextAlign, char const*, float, float, float, float, bool, float, float, float, float, bool, float, float, float, float)+312) 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] native: #10 pc 0076f12c /data/app/com.appsomniacs.da2.debug-1/lib/arm/libcocos2dcpp.so (cocos2d::CCImage::initWithStringShadowStroke(char const*, int, int, cocos2d::CCImage::ETextAlign, char const*, int, float, float, float, bool, float, float, float, float, bool, float, float, float, float)+216) 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] native: #11 pc 007aeb14 /data/app/com.appsomniacs.da2.debug-1/lib/arm/libcocos2dcpp.so (cocos2d::CCTexture2D::initWithString(char const*, cocos2d::_ccFontDefinition*)+1188) 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] native: #12 pc 0072cd6c /data/app/com.appsomniacs.da2.debug-1/lib/arm/libcocos2dcpp.so (cocos2d::CCLabelTTF::updateTexture()+120) 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] native: #13 pc 0072c804 /data/app/com.appsomniacs.da2.debug-1/lib/arm/libcocos2dcpp.so (cocos2d::CCLabelTTF::setString(char const*)+260) 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] native: #14 pc 00523140 /data/app/com.appsomniacs.da2.debug-1/lib/arm/libcocos2dcpp.so (cocos2d::extension::CCEditBoxImplAndroid::setText(char const*)+344) 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] native: #15 pc 00523474 /data/app/com.appsomniacs.da2.debug-1/lib/arm/libcocos2dcpp.so (???) 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] native: #16 pc 0076fb2c /data/app/com.appsomniacs.da2.debug-1/lib/arm/libcocos2dcpp.so (Java_org_cocos2dx_lib_Cocos2dxHelper_nativeSetEditTextDialogResult+208) 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] native: #17 pc 001dfeb1 /data/dalvik-cache/arm/data@app@com.appsomniacs.da2.debug-1@base.apk@classes.dex (Java_org_cocos2dx_lib_Cocos2dxHelper_nativeSetEditTextDialogResult___3B+100) 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] at org.cocos2dx.lib.Cocos2dxHelper.nativeSetEditTextDialogResult(Native method) 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] at org.cocos2dx.lib.Cocos2dxHelper.access$000(Cocos2dxHelper.java:41) 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] at org.cocos2dx.lib.Cocos2dxHelper$1.run(Cocos2dxHelper.java:267) 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1501) 12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1278)
堆栈跟踪(来自不同的测试,但崩溃相同)
Build fingerprint: 'samsung/zerofltetmo/zerofltetmo:5.1.1/LMY47X/G920TUVU3DOJ7:user/release-keys' Revision: '11' ABI: 'arm' pid: 18460, tid: 18534, name: GLThread 28670 >>> com.appsomniacs.da2 <<< signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr -------- r0 00000000 r1 00004866 r2 00000006 r3 00000000 r4 f33a4db8 r5 00000006 r6 00000000 r7 0000010c r8 88476100 r9 f442c800 sl 00000000 fp 12f61070 ip 00004866 sp f33a4960 lr f6f01cf9 pc f6f25c30 cpsr 600b0010 backtrace: #00 pc 0003bc30 /system/lib/libc.so (tgkill+12) #01 pc 00017cf5 /system/lib/libc.so (pthread_kill+52) #02 pc 00018907 /system/lib/libc.so (raise+10) #03 pc 000151a5 /system/lib/libc.so (__libc_android_abort+36) #04 pc 00012fec /system/lib/libc.so (abort+4) #05 pc 0075a275 /data/app/com.appsomniacs.da2-2/lib/arm/libcocos2dcpp.so (__gnu_cxx::__verbose_terminate_handler()+220) #06 pc 0072a10b /data/app/com.appsomniacs.da2- 2/lib/arm/libcocos2dcpp.so (__cxxabiv1::__terminate(void (*)())+2) #07 pc 0072a13b /data/app/com.appsomniacs.da2-2/lib/arm/libcocos2dcpp.so (std::terminate()+10) #08 pc 0072a4ab /data/app/com.appsomniacs.da2-2/lib/arm/libcocos2dcpp.so (__cxa_pure_virtual+14) #09 pc 0041ecc5 /data/app/com.appsomniacs.da2-2/lib/arm/libcocos2dcpp.so #10 pc 005977ab /data/app/com.appsomniacs.da2-2/lib/arm/libcocos2dcpp.so (Java_org_cocos2dx_lib_Cocos2dxHelper_nativeSetEditTextDialogResult+110) #11 pc 001dfe39 /data/dalvik-cache/arm/data@app@com.appsomniacs.da2-2@base.apk@classes.dex
Hunter-Orion.. 5
我们通过在jbyte数组中发送std :: string的内容,并让Java端为java并返回可在C ++ jni端使用的jstring,找到了一种解决方案。对我们来说,这些字符串来自用户键盘,一周内我有170k崩溃,说他们在字符名称中使用emoji表情并像疯了似的聊天...并且自己命名化身本身也导致崩溃。因此,Android 5.x用户加入的任何游说区都会导致其崩溃,一旦他们的客户端尝试使用相关字符渲染其他玩家名称时,它们就会崩溃。在Android 4.x中,这不是问题,因为它仅打印了一些垃圾字符。
在c ++方面,您可以执行以下操作来实现此功能:
jstring JniHelper::getjString(const char *input) { JniMethodInfo minfo; // JniHelper bool hasMethod = JniHelper::getStaticMethodInfo (minfo, APPTAG_JNI_PACKAGE_NAME, "convertCStringToJniSafeString", "([B)Ljava/lang/String;"); if (!hasMethod) { return minfo.env->NewStringUTF(""); // TODO Tune your response to fit your needs... } else { string nativeString = std::string(input); // has a bit of a code smell, there is probably a better way. // cite: http://stackoverflow.com/questions/27303316/c-stdstring-to-jstring-with-a-fixed-length jbyteArray array = minfo.env->NewByteArray(nativeString.length()); minfo.env->SetByteArrayRegion(array,0,nativeString.length(),(jbyte*)nativeString.c_str()); // cite: http://discuss.cocos2d-x.org/t/jni-return-string/9982/3 jstring str = (jstring)minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID, array); minfo.env->DeleteLocalRef(array); return str; } }
在Java方面,将其转换为Java字符串并以相同的方法返回:
public static String convertCStringToJniSafeString(byte[] input) { try { String nativeString = new String(input, "UTF-8"); // please debate what the safest charset should be? return nativeString; } catch (UnsupportedEncodingException e) { // TODO Simplistic Error handling, tune to your needs. Log.e(APPTAG, "Couldn't convert the jbyteArray to jstring"); return ""; //JSTRING_CONVERT_FAIL } }
在我们的例子中,我们希望一个jstring(作为修改的UTF8输入)馈送到渲染端并存储以供以后检索,返回空字符串只是我们为转换失败提供线索的选择。
我希望这可以帮助某人找到一种方法...甚至正确的方法...
我们通过在jbyte数组中发送std :: string的内容,并让Java端为java并返回可在C ++ jni端使用的jstring,找到了一种解决方案。对我们来说,这些字符串来自用户键盘,一周内我有170k崩溃,说他们在字符名称中使用emoji表情并像疯了似的聊天...并且自己命名化身本身也导致崩溃。因此,Android 5.x用户加入的任何游说区都会导致其崩溃,一旦他们的客户端尝试使用相关字符渲染其他玩家名称时,它们就会崩溃。在Android 4.x中,这不是问题,因为它仅打印了一些垃圾字符。
在c ++方面,您可以执行以下操作来实现此功能:
jstring JniHelper::getjString(const char *input) { JniMethodInfo minfo; // JniHelper bool hasMethod = JniHelper::getStaticMethodInfo (minfo, APPTAG_JNI_PACKAGE_NAME, "convertCStringToJniSafeString", "([B)Ljava/lang/String;"); if (!hasMethod) { return minfo.env->NewStringUTF(""); // TODO Tune your response to fit your needs... } else { string nativeString = std::string(input); // has a bit of a code smell, there is probably a better way. // cite: http://stackoverflow.com/questions/27303316/c-stdstring-to-jstring-with-a-fixed-length jbyteArray array = minfo.env->NewByteArray(nativeString.length()); minfo.env->SetByteArrayRegion(array,0,nativeString.length(),(jbyte*)nativeString.c_str()); // cite: http://discuss.cocos2d-x.org/t/jni-return-string/9982/3 jstring str = (jstring)minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID, array); minfo.env->DeleteLocalRef(array); return str; } }
在Java方面,将其转换为Java字符串并以相同的方法返回:
public static String convertCStringToJniSafeString(byte[] input) { try { String nativeString = new String(input, "UTF-8"); // please debate what the safest charset should be? return nativeString; } catch (UnsupportedEncodingException e) { // TODO Simplistic Error handling, tune to your needs. Log.e(APPTAG, "Couldn't convert the jbyteArray to jstring"); return ""; //JSTRING_CONVERT_FAIL } }
在我们的例子中,我们希望一个jstring(作为修改的UTF8输入)馈送到渲染端并存储以供以后检索,返回空字符串只是我们为转换失败提供线索的选择。
我希望这可以帮助某人找到一种方法...甚至正确的方法...