当未处置处罚的JS非常导致应用意外退出时,应用会生成对应的JS瓦解日记文件,开发者可通过错误日记查看引起瓦解的代码位置及分析应用瓦解的缘故原由。本文将分别介绍JS瓦解分析思路以及典型分析案例。
一、日记信息
以下是瓦解日记信息中对应字段解释。
- `Device info:emulator // 设备信息
- Build info:emulator 5.0.0.31(SP37DEVC00E31R4P11log) // 版本信息
- Fingerprint:983250ec758a62f9a6c4049e5d22210791fa49c6c91c321e619425045de615b1
- Module name:com.shijing.zijin // 模块名
- Version:1.0.0 // 版本名称
- VersionCode:1000000 // 版本号
- PreInstalled:No
- Foreground:Yes // 前后台
- Pid:9827 // 进程id
- Uid:20020036
- Reason:SyntaxError // 异常原因
- Error name:SyntaxError // 异常名称
- Error message:Unexpected Text in JSON // 异常信息
- Cannot get SourceMap info, dump raw stack: // 应用安装包为release包安装时不包含sourcemap文件,JS栈通过sourcemap行列号解析会失败
- SourceCode:
- JSON.parse(''); // 异常代码位置
- ^
- Stacktrace:
- 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调用栈可直接通过超链接跳转到对应错误代码行,栈顶即为问题第一现场,如下样例所示
- `Device info:emulator
- Build info:emulator 5.0.0.31(SP37DEVC00E31R4P11log)
- Fingerprint:983250ec758a62f9a6c4049e5d22210791fa49c6c91c321e619425045de615b1
- Module name:com.shijing.zijin
- Version:1.0.0
- VersionCode:1000000
- PreInstalled:No
- Foreground:Yes
- Pid:9827
- Uid:20020036
- Reason:SyntaxError
- Error name:SyntaxError
- Error message:Unexpected Text in JSON
- SourceCode:
- JSON.parse('');
- ^
- Stacktrace:
- at anonymous (entry/src/main/ets/pages/Index.ets:18:13)
复制代码 2、非常代码调用栈包含 SourceMap is not initialized yet ,表示因SourceMap转换非常耗时,改为通过异步线程去举行初始化,导致会出现SourceMap没初始化完成绩有非常产生的情况。针对这种情况增加这行日记来提示开发者。eTS栈对应编译后产物中代码行号,可通过超链接跳转到对应错误代码行。如下样例所示。
- `Device info:xxx
- Build info:xxx-xxx x.x.x.xxx(xxxx)
- Fingerprint:377ef8529301363f373ce837d0bf83aacfc46112502143237e2f4026e86a0510
- Module name:com.xxx.xxx
- Version:1.0.0
- Versioncode:1000000
- PreInstalled:No
- Foreground:Yes
- Pid:6042
- Uid:20020145
- Reason:Error
- Error name:Error
- Error message:JSERROR
- Sourcecode:
- throw new Error("JSERROR");
- ^
- Stacktrace:
- SourceMap is not initialized yet
- at anonymous (entry/src/main/ets/pages/Index.ets:49:49)
复制代码 3、非常代码调用栈中打印native栈,栈顶一般为libark_jsruntime.so动态库,这是因为JS非常末了都会颠末虚拟机抛出。从瓦解栈从上往下找,libace_napi.z.so的上一帧一般是抛出非常的现场。如下样例所示。
- `Device info:xxx
- Build info:xxx-xxx x.x.x.xxx(xxxx)
- Fingerprint:89f2b64b24d642b0fc64e3a7cf68ca39fecaa580ff5736bb9d6706ea4cdf2c93
- Module name:com.xxx.xxx
- Version:1.0.0
- VersionCode:1000000
- PreInstalled:No
- Foreground:No
- Pid:14325
- Uid:20020145
- Reason:ReferenceError
- Error name:ReferenceError
- Error message:Cannot find module 'com.xxx.xxx/entry/EntryAbility' , which is application Entry Point
- Stacktrace:
- SourceMap is not initialized yet
- #01 pc 000000000028ba3b /system/libó4/platformsdk/libark_jsruntime.so(bf6ea8e474ac3e417991f101e062fa90)
- #02 pc 00000000001452ff /system/libó4/platformsdk/libark_jsruntime.so(bf6ea8e474ac3e417991f101e062fa90)
- #03 pC 0000000000144c9f /system/libó4/platformsdk/libark_jsruntime.so(bf6ea8e474ac3e417991f101e062fa90)
- #04 pc 00000000001c617b /system/libó4/platformsdk/libark_jsruntime.so(bf6ea8e474ac3e417991f101e062fa90)
- #05 pc 00000000004c3cb7 /system/libó4/platformsdk/libark_jsruntime.so(bf6ea8e474ac3e417991f101e062fa90)
- #06 pc 00000000004c045f /system/libó4/platformsdk/libark_jsruntime.so(bf6ea8e474ac3e417991f101e062fa90)
- #07 pc 000000000038034f /system/libó4/platformsdk/libark_jsruntime.so(bf6ea8e474ac3e417991f101e062fa90)
- #08 pc 00000000004b2d9b /system/libó4/platformsdk/libark_jsruntime.so(bf6ea8e474ac3e417991f101e062fa90)
- #09 pc 0000000000037e7f /system/libó4/platformsdk/libace_napi.z.so(10ceafd39b5354314d2fe3059b8f9e4f)
- #10 pc 00000000000484cf /system/lib64/platformsdk/libruntime.z.so(3f6305a3843fae1de148a06eec4bd014) <- 异常抛出位置
- #11 pc 000000000004fce7 /system/libó4/platformsdk/libruntime.z.so(3f6305a3843fae1de148a06eec4bd014)
- #12 pc 000000000004e9fb /system/libó4/platformsdk/libruntime.z.so(3f6305a3843fae1de148a06eec4bd014)
- #13 pc 000000000004eb7b /system/libó4/platformsdk/libruntime.z.so(3f6305a3843fae1de148a06eec4bd014)
- #14 pc 000000000004f5c7 /system/libó4/platformsdk/libruntime.z.so(3f6305a3843fae1de148a06eec4bd014)
- #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中点击链接会跳转到不正确的代码位置或不存在的代码行位置。如下样例所示。
- `Device info:xxx
- Build info:xxx-xxx x.x.x.xxx(xxxx)
- Fingerprint:a370fceb59011d96e41e97bda139b1851c911012ab8c386d1a2d63986d6d226d
- Module name:com.xxx.xxx
- Version:1.0.0
- Versioncode:1000000
- PreInstalled:No
- Foreground:Yes
- Pid:39185
- Uid:20020145
- Reason:Error
- Error name:Error
- Error message:JSERROR
- Stacktrace:
- Cannot get SourceMap info, dump raw stack:
- 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
so
带调试信息的so数据,产物位置:ProjectName/ModuleName/build/default/intermediates/libs libs:带debug信息的so。 stripped_native_libs:移除调试信息等冗余数据后的so。
nameCache
反肴杂映射表,release模式编译产物,产物位置:ProjectName/ModuleName/build/default/cache/default/default@CompileArkTS/esmodule/release/obfuscation
四、DevEco Studio还原堆栈
DevEco Studio提供了Release应用堆栈解析功能,开发者可以利用构建产物中包含Debug信息的文件(so文件、sourcemap文件、nameCache文件等),对Release应用中C++堆栈、ArkTS堆栈以及ArkTS堆栈中肴杂的方法名和文件名举行还原。
1、单击菜单栏Code > Analyze Stack Trace,或在FaultLog页面非常堆栈信息处右键选择Analyze Stack Trace。
2、在弹出的Analyze Stack Trace对话框中,粘贴Release应用的非常堆栈信息。
3、如果当前工程为堆栈所在应用对应的工程,且存在Release构建产物,点击Start Analyze即可举行解析。如果当前工程不是堆栈所在应用对应的工程,则需要设置应用对应构建产物:勾选Unscramble stack trace, 在下方的文件选择框中,分别添加应用对应的sourcemap文件、so文件以及nameCache文件,点击Start Analyze举行转换。DevEco Studio将解析后的堆栈信息表现在右侧的输出框中。
在构建Release应用时,so文件默认不包含符号表信息,还原so的时候,需要使用包含符号表信息的so。在构建Release应用时生成包含符号表的so文件,需要在工程的模块级build-profile.json5文件的buildOption属性中,设置如下信息:
- `"buildOption": {
- "externalNativeOptions": {
- "arguments": "-DCMAKE_BUILD_TYPE=RelWithDebInfo"
- }
- }
复制代码 五、hstack还原堆栈
hstack依赖Node情况, 需要将Node.js设置到情况变量中,还需要将SDK中的native\llvm\bin目录设置到情况变量中。 使用如下下令,-i指定瓦解文件所在目录,-o指定输出目录,-s指定sourcemap文件所在目录,–so指定so文件所在目录,-n指定nameCache文件所在目录。解析完成后,输出目录下会生成对应的解析文件,文件以原始crash文件名加“_”前缀举行命名。
- `hstack -i crashDir -o outputDir -s sourceMapDir --so soDir -n nameCacheDir
复制代码 需要注意的是,对于so文件,肯定要使用包含符号表的so。在构建Release应用时,so文件是默认不包含符号表信息的,在构建Release应用时生成包含符号表的so文件,需要在工程的模块级build-profile.json5文件的buildOption属性中,设置如下信息:
- `"buildOption": {
- "externalNativeOptions": {
- "arguments": "-DCMAKE_BUILD_TYPE=RelWithDebInfo"
- }
- }
复制代码 六、JS瓦解案例解析
Java有个折磨人的空指针非常,JS同样有个雷同空指针的非常,那就是undefined,undefined在错误日记中多表现为如下:
- `Error name:TypeError
- Error message:Cannot read property xxx of undefined
复制代码 办理方式也简单,增加掩护性判定,判定对象是否为undefined,或者在访问前增加 ‘?’ 操纵符。
写在末了
●如果你以为这篇内容对你还蛮有帮助,我想邀请你帮我两个小忙:
●点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
●关注小编,同时可以等待后续文章ing |