在 cocos2d-x 3.4 上遇到了一个诡异的问题,记录如下。
原文:http://zengrong.net/post/2242.htm
[hr][size=6]平台和版本[/size]
[list][li]框架: cocos2d-x 3.4 final[/li][li]设备: Nexus 4/5/7 with Android 5.0.1/5.0.2[/li][li]NDK version: r9d[/li][/list][size=6]问题描述[/size]
一个 dragonbonesCPP 骨骼动画,在 iOS、Windows、Mac OS X、Android with 4.x 上表现完全正常,但在 Android 5.x 下表现不正常。
具体表现为解析骨骼动画数据的时候,既不 crash,也没有任何报错信息,整个程序就停住了。
[size=6]问题追溯[/size]
通过加入 log 信息,发现问题处在 XMLDataParser::parserDragonBonesData 方法中,如下所示:
//.............DragonBonesData* XMLDataParser::parseDragonBonesData(const void *rawDragonBonesData, float scale) const{ CCLOG("Start parse dragonbones data."); _armatureScale = scale; const XMLElement *dragonBonesXML = static_cast<const XMLElement*>(rawDragonBonesData); std::string version = dragonBonesXML->Attribute(ConstValues::A_VERSION.c_str()); CCLOG("Start parse A_VERSION."); // TODO /* switch(version) { } */ CCLOG("A_FRAME_RATE: %s .", ConstValues::A_FRAME_RATE.c_str()); //打印了上面一行log 之后,整个程序就停住了 _frameRate = dragonBonesXML->IntAttribute(ConstValues::A_FRAME_RATE.c_str()); CCLOG("Start parse A_FRAME_RATE %d.", _frameRate); DragonBonesData *dragonBonesData = new DragonBonesData(); //................
IntAttribute 是 tinyxml2 提供的解析方法,继续追溯,发现程序在 tinyxml2 中的 XMLUtil::ToInt 方法中停住。
//.............bool XMLUtil::ToInt(const char *str, int *value){ CCLOG("XMLUtil::ToInt str: %s, value: %d", str, *value); //打印了上面一行 log 之后,整个程序就停住了 if (DBTIXML_SSCANF(str, "%d", value) == 1) { CCLOG("XMLUtil::ToInt SSCANF true"); return true; } CCLOG("XMLUtil::ToInt SSCANF false"); return false;}//.............
而 DBTIXML_SSCANF 是一个宏,在 NDK 中被指向 sscanf 。
我本以为是 tinyxml2 的问题,但换了 github 最新版本的 tinyxml2 依然有同样问题,于是开始怀疑 NDK。
Google 一番之后,找到了一个关键的 issue 77988 。这里说到的情况和我碰到的几乎一模一样,看来这是 NDK 的 BUG 没错了:
[blockquote]
[quote]I have found that any call into the standard library sscanf function will cause the application to lockup. My device is the Nexus 5 running Android 5.0 preview version hammerhead-lpx13d-preview-f7596f51.tgz
Steps to recreate the problem:
– Make any call to sscanf, for example:
int v1 = 0;
sscanf(“1″, “%d”, &v1);
[list][li]Notice that the application will not return from the call to sscanf and completely freeze without any error message generated[/li][/list][/quote][list][li] [/li][/list][/blockquote][size=6]解决方案[/size]
[size=5]方案1[/size]
升级 NDK 到 r10d ,该版本已经解决了这个问题:
[blockquote][quote]Documented a fix to a libc++ sscanf/vsscanf hang that occurred in API level 21. The fix itself had been implemented in r10c. (Issue 77988)[/quote]
[/blockquote]但进行 NDK 连接的时候,我碰到了这样的报错信息:
[blockquote][quote]/Volumes/HD1/Android/android-ndk-r10d/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/…/lib/gcc/arm-linux-androideabi/4.9/…/…/…/…/arm-linux-androideabi/bin/ld: error: /Volumes/HD1/Android/android-ndk-r10d/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/…/lib/gcc/arm-linux-androideabi/4.9/libgcc.a(pr-support.o): multiple definition of ‘_Unwind_GetRegionStart’
/Volumes/HD1/Android/android-ndk-r10d/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/…/lib/gcc/arm-linux-androideabi/4.9/…/…/…/…/arm-linux-androideabi/bin/ld: /Volumes/HD1/Android/android-ndk-r10d/sources/cxx-stl/llvm-libc++/libs/armeabi/thumb/libc++_static.a(Unwind-EHABI.o): previous definition here
/Volumes/HD1/Android/android-ndk-r10d/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/…/lib/gcc/arm-linux-androideabi/4.9/…/…/…/…/arm-linux-androideabi/bin/ld: error: /Volumes/HD1/Android/android-ndk-r10d/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/…/lib/gcc/arm-linux-androideabi/4.9/libgcc.a(pr-support.o): multiple definition of ‘_Unwind_GetLanguageSpecificData’
/Volumes/HD1/Android/android-ndk-r10d/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/…/lib/gcc/arm-linux-androideabi/4.9/…/…/…/…/arm-linux-androideabi/bin/ld: /Volumes/HD1/Android/android-ndk-r10d/sources/cxx-stl/llvm-libc++/libs/armeabi/thumb/libc++_static.a(Unwind-EHABI.o): previous definition here
collect2: error: ld returned 1 exit status
make: *** [obj/local/armeabi/libcocos2dlua.so] Error 1[/quote]
[/blockquote]我没有去解决这个问题,因为还有下一个方案。
[size=5]方案2[/size]
如果担心 cocos2d-x 3.4 和 NDK r10d 的兼容性,也可以修改 Android 的编译参数:
编辑 android 项目中的 Application.mk 文件:
[pre]vim frameworks/runtime-src/proj.android/jni/Application.mk
[/pre]将第一行:
[pre]APP_STL := c++_static
[/pre]改为:
[pre]APP_STL := gnustl_static
[/pre]