此文背景:

      微信体验版和pc调试版本都没有问题,但是上了Android手机就有问题,百思不得其解。并且有的同事遇到,有的同事没遇到。后面定位之后才发现,不是其没遇到,而是还没到触发时机。

         引擎版本:

appIOS闪退日志关键字 安卓应用闪退日志_appIOS闪退日志关键字

         龙骨编辑器版本:

appIOS闪退日志关键字 安卓应用闪退日志_appIOS闪退日志关键字_02

动画导出版本:5.0,

 

appIOS闪退日志关键字 安卓应用闪退日志_android studio程序闪退_03

通用法则:收集日志,试图恢复现场。

1找一台Android手机,连接调试环境,开启开发者模式,尝试捞取闪退日志。比如pc上装有android开发环境,或者带有adb调试也可。

2按照他人反馈闪退的步骤操作,直到出现闪退。

3android闪退通常会有crash日志。比如下图:

appIOS闪退日志关键字 安卓应用闪退日志_android studio程序闪退_04

   --------- beginning of crash:明确指明了闪退日志开始了

pid: 7307, tid: 7421, name: GLThread1358  >>> com.qm.dwslh<<<:指明了包名,以此确认这段日志就是来自于当前游戏。

signal 11 (SIGSEGV), code 1 (SEGV_MAPERR),fault addr 0x8381103d2c:这是闪退常见的标记,signal ... 还有fault addr 0x... 错误的地址

【通常上述问题都是由于原生c++层出了问题,地址首先想到的是指针,比如野指针、空指针等;还有数组越界。这个数组越界非常典型。因为微信或pc上调试运行环境是js环境,容错能力比较强,比如数组 var a = [1, 2]; 取值a[-1] 也不会导致闪退,最多就是undefined。而c++这些原生层就不一样了,容不得半点沙子,数组越界这些问题必然导致崩溃。】

appIOS闪退日志关键字 安卓应用闪退日志_adb打开闪退_05

放大仔细看这个调用栈,似乎与龙骨动画解析有关。

4A》根据以上日志关键字_parse...,回顾这个游戏开发过程中,似乎在pc上也遇到过关于龙骨动画解析的问题。比如错误的内存释放,导致下一个即将产生的相同龙骨动画解析失败。凭着这点经验,因此先尝试排除内存错误释放所引发。因为这个内存释放是很容易出错的,风险较大,所以要首先排除。找到相应释放代码,临时注释掉,可以重新出包再测试。

B》顺便打上日志。根据游戏实际运行情况,在可疑地方打上日志。比如闪退都在花园中出现,并且花园中只有顾客事件和鸽子,还有飞翔宝箱才是龙骨动画,而后两者在铺子中已经正常出现过,因此在花园顾客产生时打上顾客id,以便知道是哪一个顾客出场引发的。如图:

appIOS闪退日志关键字 安卓应用闪退日志_adb运行闪退_06

由他人重新出包时,已经上晚上十一点多,我已经睡了。第二天打开微信一看,测试反馈还是有闪退,并且和之前没什么差异,还是花园中闪退。很奇怪,但是排除了内存释放导致的问题。

4随后其他人提供闪退日志,如下图:

appIOS闪退日志关键字 安卓应用闪退日志_adb一打开就闪退_07

这个日志更加详细,具体调用栈函数名都列的清清楚楚:

appIOS闪退日志关键字 安卓应用闪退日志_adb打开闪退_08

并且该日志显示和上述自己调试所得日志基本上一致。

由此比较肯定地得出一个结:龙骨动画解析出错了。

6接着自己再测试同一个包,看看补打的日志是否有用,结果比较符合预期,如图:

appIOS闪退日志关键字 安卓应用闪退日志_adb运行闪退_09

ok,不错,是期望值。16号顾客出厂时,接着就闪退了,因此自然而然想到是不是这个顾客动画文件有问题?因为已经排除了内存释放了,还有错那就应该是动画本身有错。于是再想法测试。

7好在动态调整配置即可达到测试,不用再出包。基本思路如下:

        A、花园顾客只配置少量,比如一两个。且只能配置店铺1中出现过的骨骼动画;若是出错,那就不是骨骼动画的问题,因为店铺1中都出现过,很正常,那就应该花园相关代码有问题;若是没出错,ok,这和预期很接近,可以再做下一波配置测试。

        B、 花园顾客只配置16号顾客,重新测试。若是出错,并且百分百出错,那就定位了,就是这个动画本身有问题。若是没出错,ok,冤枉了16号,只能再做下一波配置测试。

        C、花园顾客配置其他店铺会出现但是目前还没出现过的顾客。若是出错,麻烦了,问题到底在哪?若是不出错,嗯,这是理想的情况。

         根据以上思路让策划调整配置,测试在B步骤就停止了,因为只配置16号顾客是百分百出错,并且多人都能复现,日志和上述日志一模一样,还是继续输出了id为16。

8好吧,到这基本上看似要结束了,因为直接让美术重新出个16号顾客就可以了,也不用花费太多时间纠结。但是并没有这么做,作为一个程序员,有必要刨根问底,防止下一次再出现,这到底是怎么出现的。骨骼动画好几十个,这个有问题,那其他的能没有问题吗?不可能一个一个去打开检查吧。应该要精确定位到这个骨骼动画到底哪里出了错。

9要来16号骨骼动画源文件,打开检查,顺便也让美术自查和其他没错的骨骼动画的差异性。结果查看编辑属性和导出属性,没什么诡异之处。

10问百度问论坛。带着dragonBones、JSONDataParser、_parseZOrderFrame等这些关键字搜索:

appIOS闪退日志关键字 安卓应用闪退日志_adb一打开就闪退_10

搜搜结果还有点启发:

第一帖:https://forum.cocos.org/t/creator2-0-9/77284

appIOS闪退日志关键字 安卓应用闪退日志_android studio程序闪退_11

第二贴:https://forum.cocos.org/t/ios/75811

appIOS闪退日志关键字 安卓应用闪退日志_android studio程序闪退_12

appIOS闪退日志关键字 安卓应用闪退日志_appIOS闪退日志关键字_13

根据第二贴哥们的描述,有了启发:若是真是越界,那么和上面的报错很相似。既然同一个动画有错,那么微信或pc上调试时动画数据是不会发生变化的,那么调试一下看是不是真的会越界。因为js上容错比较ok,所以可能没有因此闪退,但是在原生环境上肯定会闪退,那么这就是想要的答案。

       带着这样思路,找到引擎js和c++源代码,就是上述调用栈所示源文件:

c++:

appIOS闪退日志关键字 安卓应用闪退日志_adb运行闪退_14

js:

appIOS闪退日志关键字 安卓应用闪退日志_appIOS闪退日志关键字_15

11并在pc上调试:

appIOS闪退日志关键字 安卓应用闪退日志_appIOS闪退日志关键字_16

zOrders最后的结果:

appIOS闪退日志关键字 安卓应用闪退日志_adb一打开就闪退_17

appIOS闪退日志关键字 安卓应用闪退日志_adb打开闪退_18

这样在js上不会导致闪退的。

ok,根据上述调试,在反推到c++代码中,必然触发断言:

appIOS闪退日志关键字 安卓应用闪退日志_android studio程序闪退_19

引擎这么做,可能希望开发者在开发调试时就能触发,及时发现动画数据有问题。但是实际是我们在微信和pc调试没问题就直接输出app版本,没有经过模拟器验证,因此没有在开发中就触发。锅是谁的,就不纠结了。继续排查,为什么会出现这个情况,则继续调试:

appIOS闪退日志关键字 安卓应用闪退日志_adb一打开就闪退_20

rawZOrder为[0, -1],这个是来自动画输出文件:

appIOS闪退日志关键字 安卓应用闪退日志_appIOS闪退日志关键字_21

12打开动画原始文件,查看:

appIOS闪退日志关键字 安卓应用闪退日志_adb打开闪退_22

绘制顺序被k了两帧,意图是想要在动画中调整渲染层级。

这个很奇怪,为什么这有,那其他动画中是不是也有这个操作。于是随便打开几个没有出现问题的动画,惊讶的发现,没错的都没有这个k帧。

13于是写了个脚本(见tools下check_role_dragbones.js)搜索查找所有骨骼动画,结果很惊喜,还好只有这一个动画:

appIOS闪退日志关键字 安卓应用闪退日志_appIOS闪退日志关键字_23

14再看修改前后参数对比,左前右后:

appIOS闪退日志关键字 安卓应用闪退日志_appIOS闪退日志关键字_24

 vs 

appIOS闪退日志关键字 安卓应用闪退日志_android studio程序闪退_25

根据上述对照,已经引擎源码解析算法所示,有-1肯定会触发断言而闪退。

此时,你肯定会问,这个动画师是怎么调整的呢?问得好!我也正想问他,他的名字叫cj!

15标题虽然是android上触发的,但是实际上不改的话,ios上必然出现。正好符合上述第二贴那哥们所述。

16

这个过程虽然比较长,但是非常有价值,踩坑经验值++!

——DF 流闻名 scott 2020.4.15、4.16

_____________更正______________查阅龙骨官方数据说明,如图所示:

appIOS闪退日志关键字 安卓应用闪退日志_adb打开闪退_26

zorder的说明:

appIOS闪退日志关键字 安卓应用闪退日志_appIOS闪退日志关键字_27

也就是说,上面提到的zOder=[0, -1] 中的-1是被允许的,标识偏移量。由此再根据cocos引擎的解析算法得出:当zOrder这个数组长度为2,且最后一个元素为-1时,那么是必然触发断言,如图:

appIOS闪退日志关键字 安卓应用闪退日志_appIOS闪退日志关键字_28

因此可以认定cocos这么解析是不妥的,没有考虑到上述情况,实属bug:

appIOS闪退日志关键字 安卓应用闪退日志_adb运行闪退_29

更正完毕!

——DF 流闻名 scott 2020.4.1621:58