0


【HarmonyOS实战开发】鸿蒙JS崩溃分析

当未处理的JS异常导致应用意外退出时,应用会生成对应的JS崩溃日志文件,开发者可通过错误日志查看引起崩溃的代码位置及分析应用崩溃的原因。本文将分别介绍JS崩溃分析思路以及典型分析案例。

一、日志信息

以下是崩溃日志信息中对应字段解释。

  1. `Device info:emulator // 设备信息
  2. Build info:emulator 5.0.0.31(SP37DEVC00E31R4P11log) // 版本信息
  3. Fingerprint:983250ec758a62f9a6c4049e5d22210791fa49c6c91c321e619425045de615b1
  4. Module name:com.shijing.zijin // 模块名
  5. Version:1.0.0 // 版本名称
  6. VersionCode:1000000 // 版本号
  7. PreInstalled:No
  8. Foreground:Yes // 前后台
  9. Pid:9827 // 进程id
  10. Uid:20020036
  11. Reason:SyntaxError // 异常原因
  12. Error name:SyntaxError // 异常名称
  13. Error message:Unexpected Text in JSON // 异常信息
  14. Cannot get SourceMap info, dump raw stack: // 应用安装包为release包安装时不包含sourcemap文件,JS栈通过sourcemap行列号解析会失败
  15. SourceCode:
  16. JSON.parse(''); // 异常代码位置
  17. ^
  18. Stacktrace:
  19. at anonymous (entry/src/main/ets/pages/Index.ets:18:13) // 异常代码调用栈
二、异常类型

JS异常根据不同的异常场景,在 Reason 字段进行了分类,分为Error、TypeError、SyntaxError、RangeError等错误类型。

  • 自定义 Error 类:Error 是最基本的错误类型,其他的错误类型都继承自该类型。Error 对象主要有两个重要属性 message 和 name 分别表示错误信息和错误名称。程序运行过程中抛出的异常一般都有具体的类型,Error 类型一般都是开发人员自己抛出的异常。
  • TypeError(类型错误)类:运行时最常见的异常,表示变量或参数不是预期类型。
  • SyntaxError(语法错误)类:语法错误也称为解析错误。语法错误在任何编程语言中都是最常见的错误类型,表示不符合编程语言的语法规范。
  • RangeError(边界错误)类:表示超出有效范围时发生的异常,主要的有以下几种情况: 数组长度为负数或超长 数字类型的方法参数超出预定义范围 函数堆栈调用超过最大值
  • ReferenceError —— 引用错误:引用一个不存在的变量时发生的错误,每当我们创建一个变量时,变量名称都会写入一个变量存储中心中,这个变量存储中心就像键值存储一样,每当我们引用变量时,它都去存储中找到 key并提取并返回 value,如果我们要找的变量不在存储中,就会抛出 ReferenceError。
  • URI Error —— URL错误:在调用 URI 相关的方法中 URL 无效时抛出的异常,主要包括 encodeURI()、decodeURI()、encodeURIComponent()、decodeURIComponent()、escape() 和 unescape() 。
三、堆栈

StackTrace字段存放的是JS异常的调用栈信息,StackTrace的显示分为以下几种场景。

1、JS调用栈可直接通过超链接跳转到对应错误代码行,栈顶即为问题第一现场,如下样例所示

  1. `Device info:emulator
  2. Build info:emulator 5.0.0.31(SP37DEVC00E31R4P11log)
  3. Fingerprint:983250ec758a62f9a6c4049e5d22210791fa49c6c91c321e619425045de615b1
  4. Module name:com.shijing.zijin
  5. Version:1.0.0
  6. VersionCode:1000000
  7. PreInstalled:No
  8. Foreground:Yes
  9. Pid:9827
  10. Uid:20020036
  11. Reason:SyntaxError
  12. Error name:SyntaxError
  13. Error message:Unexpected Text in JSON
  14. SourceCode:
  15. JSON.parse('');
  16. ^
  17. Stacktrace:
  18. at anonymous (entry/src/main/ets/pages/Index.ets:18:13)

2、异常代码调用栈包含 SourceMap is not initialized yet ,表示因SourceMap转换非常耗时,改为通过异步线程去进行初始化,导致会出现SourceMap没初始化完成就有异常产生的情况。针对这种情况增加这行日志来提示开发者。eTS栈对应编译后产物中代码行号,可通过超链接跳转到对应错误代码行。如下样例所示。

  1. `Device info:xxx
  2. Build info:xxx-xxx x.x.x.xxx(xxxx)
  3. Fingerprint:377ef8529301363f373ce837d0bf83aacfc46112502143237e2f4026e86a0510
  4. Module name:com.xxx.xxx
  5. Version:1.0.0
  6. Versioncode:1000000
  7. PreInstalled:No
  8. Foreground:Yes
  9. Pid:6042
  10. Uid:20020145
  11. Reason:Error
  12. Error name:Error
  13. Error message:JSERROR
  14. Sourcecode:
  15. throw new Error("JSERROR");
  16. ^
  17. Stacktrace:
  18. SourceMap is not initialized yet
  19. at anonymous (entry/src/main/ets/pages/Index.ets:49:49)

3、异常代码调用栈中打印native栈,栈顶一般为libark_jsruntime.so动态库,这是因为JS异常最后都会经过虚拟机抛出。从崩溃栈从上往下找,libace_napi.z.so的上一帧一般是抛出异常的现场。如下样例所示。

  1. `Device info:xxx
  2. Build info:xxx-xxx x.x.x.xxx(xxxx)
  3. Fingerprint:89f2b64b24d642b0fc64e3a7cf68ca39fecaa580ff5736bb9d6706ea4cdf2c93
  4. Module name:com.xxx.xxx
  5. Version:1.0.0
  6. VersionCode:1000000
  7. PreInstalled:No
  8. Foreground:No
  9. Pid:14325
  10. Uid:20020145
  11. Reason:ReferenceError
  12. Error name:ReferenceError
  13. Error message:Cannot find module 'com.xxx.xxx/entry/EntryAbility' , which is application Entry Point
  14. Stacktrace:
  15. SourceMap is not initialized yet
  16. #01 pc 000000000028ba3b /system/libó4/platformsdk/libark_jsruntime.so(bf6ea8e474ac3e417991f101e062fa90)
  17. #02 pc 00000000001452ff /system/libó4/platformsdk/libark_jsruntime.so(bf6ea8e474ac3e417991f101e062fa90)
  18. #03 pC 0000000000144c9f /system/libó4/platformsdk/libark_jsruntime.so(bf6ea8e474ac3e417991f101e062fa90)
  19. #04 pc 00000000001c617b /system/libó4/platformsdk/libark_jsruntime.so(bf6ea8e474ac3e417991f101e062fa90)
  20. #05 pc 00000000004c3cb7 /system/libó4/platformsdk/libark_jsruntime.so(bf6ea8e474ac3e417991f101e062fa90)
  21. #06 pc 00000000004c045f /system/libó4/platformsdk/libark_jsruntime.so(bf6ea8e474ac3e417991f101e062fa90)
  22. #07 pc 000000000038034f /system/libó4/platformsdk/libark_jsruntime.so(bf6ea8e474ac3e417991f101e062fa90)
  23. #08 pc 00000000004b2d9b /system/libó4/platformsdk/libark_jsruntime.so(bf6ea8e474ac3e417991f101e062fa90)
  24. #09 pc 0000000000037e7f /system/libó4/platformsdk/libace_napi.z.so(10ceafd39b5354314d2fe3059b8f9e4f)
  25. #10 pc 00000000000484cf /system/lib64/platformsdk/libruntime.z.so(3f6305a3843fae1de148a06eec4bd014) <- 异常抛出位置
  26. #11 pc 000000000004fce7 /system/libó4/platformsdk/libruntime.z.so(3f6305a3843fae1de148a06eec4bd014)
  27. #12 pc 000000000004e9fb /system/libó4/platformsdk/libruntime.z.so(3f6305a3843fae1de148a06eec4bd014)
  28. #13 pc 000000000004eb7b /system/libó4/platformsdk/libruntime.z.so(3f6305a3843fae1de148a06eec4bd014)
  29. #14 pc 000000000004f5c7 /system/libó4/platformsdk/libruntime.z.so(3f6305a3843fae1de148a06eec4bd014)
  30. #15 pc 00000000000303cf /system/lib64/platformsdk/libuiabilitykit_native.z.so(3203F4CCe84a43b519d0a731dfOdb1a3)

4、如出现Cannot get Source Map info, dump raw stack信息,表示该应用为release包安装,JS栈转换eTS行列号失败,在DevEco Studio中点击链接会跳转到不正确的代码位置或不存在的代码行位置。如下样例所示。

  1. `Device info:xxx
  2. Build info:xxx-xxx x.x.x.xxx(xxxx)
  3. Fingerprint:a370fceb59011d96e41e97bda139b1851c911012ab8c386d1a2d63986d6d226d
  4. Module name:com.xxx.xxx
  5. Version:1.0.0
  6. Versioncode:1000000
  7. PreInstalled:No
  8. Foreground:Yes
  9. Pid:39185
  10. Uid:20020145
  11. Reason:Error
  12. Error name:Error
  13. Error message:JSERROR
  14. Stacktrace:
  15. Cannot get SourceMap info, dump raw stack:
  16. at anonymous (entry/src/main/ets/paqes/Index.ts:49:49)

Release应用都会混淆代码,去除其中的debug信息。因此无法直接通过Release应用的堆栈信息定位到源码的具体文件和行位置。对于这种情况,可以使用DevEco Studio还原堆栈,也可以通过hstack命令还原堆栈

四、release模式编译产物

在进行堆栈还原之前,我们需要拿到一些文件,这些文件只在构建release包才会有,构建debug包不会有这些文件。

sourcemap文件

release模式编译产物,文件位置:ProjectName/ModuleName/build/default/cache/default/default@CompileArkTS/esmodule/release/sourceMaps.map
image.png

so

带调试信息的so数据,产物位置:ProjectName/ModuleName/build/default/intermediates/libs libs:带debug信息的so。 stripped_native_libs:移除调试信息等冗余数据后的so。
image.png

nameCache

反混淆映射表,release模式编译产物,产物位置:ProjectName/ModuleName/build/default/cache/default/default@CompileArkTS/esmodule/release/obfuscation
image.png

四、DevEco Studio还原堆栈

DevEco Studio提供了Release应用堆栈解析功能,开发者可以利用构建产物中包含Debug信息的文件(so文件、sourcemap文件、nameCache文件等),对Release应用中C++堆栈、ArkTS堆栈以及ArkTS堆栈中混淆的方法名和文件名进行还原。   
1、单击菜单栏Code > Analyze Stack Trace,或在FaultLog页面异常堆栈信息处右键选择Analyze Stack Trace。image.png

2、在弹出的Analyze Stack Trace对话框中,粘贴Release应用的异常堆栈信息。image.png

3、如果当前工程为堆栈所在应用对应的工程,且存在Release构建产物,点击Start Analyze即可进行解析。如果当前工程不是堆栈所在应用对应的工程,则需要配置应用对应构建产物:勾选Unscramble stack trace, 在下方的文件选择框中,分别添加应用对应的sourcemap文件、so文件以及nameCache文件,点击Start Analyze进行转换。DevEco Studio将解析后的堆栈信息显示在右侧的输出框中。image.png

在构建Release应用时,so文件默认不包含符号表信息,还原so的时候,需要使用包含符号表信息的so。在构建Release应用时生成包含符号表的so文件,需要在工程的模块级build-profile.json5文件的buildOption属性中,配置如下信息:

  1. `"buildOption": {
  2. "externalNativeOptions": {
  3. "arguments": "-DCMAKE_BUILD_TYPE=RelWithDebInfo"
  4. }
  5. }
五、hstack还原堆栈

hstack依赖Node环境, 需要将Node.js配置到环境变量中,还需要将SDK中的native\llvm\bin目录配置到环境变量中。   使用如下命令,-i指定崩溃文件所在目录,-o指定输出目录,-s指定sourcemap文件所在目录,–so指定so文件所在目录,-n指定nameCache文件所在目录。解析完成后,输出目录下会生成对应的解析文件,文件以原始crash文件名加“_”前缀进行命名。

  1. `hstack -i crashDir -o outputDir -s sourceMapDir --so soDir -n nameCacheDir

需要注意的是,对于so文件,一定要使用包含符号表的so。在构建Release应用时,so文件是默认不包含符号表信息的,在构建Release应用时生成包含符号表的so文件,需要在工程的模块级build-profile.json5文件的buildOption属性中,配置如下信息:

  1. `"buildOption": {
  2. "externalNativeOptions": {
  3. "arguments": "-DCMAKE_BUILD_TYPE=RelWithDebInfo"
  4. }
  5. }
六、JS崩溃案例解析

Java有个折磨人的空指针异常,JS同样有个类似空指针的异常,那就是undefined,undefined在错误日志中多表现为如下:

  1. `Error name:TypeError
  2. Error message:Cannot read property xxx of undefined

解决方式也简单,增加保护性判断,判断对象是否为undefined,或者在访问前增加 ‘?’ 操作符。

写在最后

●如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我两个小忙:
●点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
●关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。

在这里插入图片描述


本文转载自: https://blog.csdn.net/niumadeshijie/article/details/141112656
版权归原作者 代码越多头发越少001 所有, 如有侵权,请联系我们删除。

“【HarmonyOS实战开发】鸿蒙JS崩溃分析”的评论:

还没有评论