当前位置:  开发笔记 > 编程语言 > 正文

使用许多不同种类的表情符号和语言时,对C ++ JNI NewStringUTF的调用会使android应用程序崩溃(除了ascii,但仍然是有效的修改版utf-8)

如何解决《使用许多不同种类的表情符号和语言时,对C++JNINewStringUTF的调用会使android应用程序崩溃(除了ascii,但仍然是有效的修改版utf-8)》经验,为你挑选了1个好方法。

我试图解决从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输入)馈送到渲染端并存储以供以后检索,返回空字符串只是我们为转换失败提供线索的选择。

我希望这可以帮助某人找到一种方法...甚至正确的方法...



1> Hunter-Orion..:

我们通过在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输入)馈送到渲染端并存储以供以后检索,返回空字符串只是我们为转换失败提供线索的选择。

我希望这可以帮助某人找到一种方法...甚至正确的方法...

推荐阅读
我我檬檬我我186
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有