Призыв к C++ JNI NewStringUTF приводит к сбою приложения для Android при использовании множества различных типов эмодзи и языков (кроме ascii, но все еще действующий измененный utf-8)
Я пытаюсь решить проблему сбоя ввода с клавиатуры Cocos2d-x на Android 5.x, когда я создаю CCImage из текста с множеством смайликов, найденных на клавиатуре (некоторые работают, но большинство не работает). На Android 4.x несколько из устройства просто отображают искаженный текст / дополнительные символы. Источником сбоя является вызов JNI NewStringUTF(). Он просто не поддерживает все 2, 3 и 4-байтовые символы utf-8 в Android 5/Lollipop.
Этот сбой происходит на cocos2d-x v2.2.6 (и подтвержден на 3.x) с использованием NDK 10e с Toolchain 4.8 (не уверен, что что-то из этого имеет большое значение, мы использовали 9d до перехода на Android Studio и я Я уверен, что у нас была эта проблема, но было гораздо меньше пользы для леденцов.)
Если вы никогда не нажмете ни один из неизмененных символов 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<char, std::__1::char_traits<char> >&, 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<char, std::__1::char_traits<char> >&) 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)
Stack Trace (из другого теста, но тот же сбой)
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
1 ответ
Мы нашли решение, отправив содержимое std::string в массиве jbyte, и пусть сторона java будет java и вернет jstring, которую мы могли бы использовать на стороне j ++ C++. Для нас эти строки исходят от клавиатуры пользователя, и у меня есть 170 тыс. Сбоев за одну неделю, которые говорят, что они используют эмодзи в именах персонажей и общаются как сумасшедшие... и называние их аватаров само по себе также вызывает сбои. Таким образом, любое лобби, к которому присоединился пользователь 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://stackru.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) передавал на сторону рендеринга и сохранял для последующего извлечения, возвращая пустую строку, был просто выбор, который мы сделали, чтобы указать нам, что преобразование не удалось.
Я надеюсь, что это помогает кому-то найти способ... может быть, даже правильный путь...