常用术语
1 异常
App在运行过程中发生的崩溃、ANR、错误,统称为异常。
2 崩溃
用户在使用App过程中发生一次闪退,计为一次崩溃。
3 ANR
用户在使用App过程中出现弹框,提示应用无响应,计为一次ANR,ANR仅用于Android平台应用。
4 错误
主动上报的Exception、Error,或脚本(如C#、Lua、JS等)错误,统称为错误。
5 发生次数
一个异常发生且被记录上报,计为一次异常发生。
6 设备的唯一标识(Device ID)
用于唯一标识一个设备的标记,由sdk自己默认生成,并在应用卸载前一直保持不变和有效。
CrashSight使用Device ID来识别设备,即,如果有X条问题上报的Device ID相同,那么这X条上报会使问题发生次数+X,但是影响设备数+1。联网和问题上报都会带有Device ID信息,以下是一些常用平台上CrashSight SDK生成Device ID的默认方式。
平台 | 默认的Device ID生成方式 |
---|---|
Android | 首次启动时生成UUID |
iOS | IDFV |
Windows | MAC地址 |
7 问题上报
当触发CrashSight SDK的问题上报机制(对于崩溃是自动捕获,对于错误是调用接口,详情可参考CrashSight帮助文档),CrashSight会自动收集信息并进行上报。
8 联网
CrashSight SDK初始化时,将会立即进行一次上报,它被称作联网。联网产生的数据可以用于统计启动次数。
9 联网设备
以设备为判断指标,每一个发生联网的设备或者发生一次上报,即为一个联网设备。 在指定时间范围内,若一个设备重复发生联网行为,只算一个联网设备。(设备去重以设备的唯一标识为准)
10 影响设备
一台设备发生异常,计为一个影响设备。 在指定时间范围内,若一个设备发生多次异常,只算一个影响设备,(设备去重以设备的唯一标识为准)
11 设备异常率
诸如设备崩溃率、设备卡顿率、设备ANR率、设备错误率等 即影响设备/联网设备 比值。
12 次数异常率
诸如次数崩溃率、次数卡顿率、次数ANR率、次数错误率 即发生次数/联网次数的比值。
13 启动次数
应用完全退出后重新启动,计为一次启动(总启动次数具体是启动上报+异常上报中携带启动次数来累计,具体由sdk来进行启动判定)。
14 今日设备异常率
当日时间内的 异常影响设备/联网设备。
15 首次上报时间
问题第一次上报系统的时间。
16 问题累积影响设备
问题第一次上报系统之后,截止当前时间,一共影响设备的总数。
17 问题累积影响次数
问题第一次上报系统之后,截止当前时间,发生总次数。
18 小时/累计
小时窗口是,对应当前小时的00分00秒 到 当前小时 59分59秒之间。 累计窗口是,对应当天00时00分00秒 到 当前小时 59分59秒之间。
19 真机/模拟器
真机:真实的移动物理设备。 模拟器:能在个人计算机运行并模拟安卓手机系统的模拟器(大多数模拟器,每次启动app会产生新的设备唯一标识,同时云游戏设备也有这样的特点,也会标记为模拟器)。
20 数据更新时间
统计结果数据后台刷新的时间(数据更新是后台异步更新,默认崩溃趋势间隔10分钟左右更新一次)。
21 问题ID
异常在上报后会进行归类(同一类异常归为一个集合,称为一个问题),对应问题的唯一的UUID叫做问题ID,同问题一一对应。
22 上报ID
一个异常在上报的时候,产生一个唯一uuid叫做上报ID,同该次上报一一对应。
23 崩溃时访问地址
当发生坏内存访问时,程序实际访问的地址会和预期不符,CrashSight能上报崩溃时程序访问的地址。一般来说,崩溃时访问0x0为空指针,而崩溃时访问大地址则是野指针。
24 客户端侧上报ID
CrashSight SDK会在处理崩溃/错误时生成一个随机的UUID,并随崩溃/错误一同上报,这个UUID被称为客户端侧上报ID。客户端侧上报ID是每条上报的唯一标识,可以用来查找和定位上报信息。开发者可以在客户端的日志中搜索“expuid”来找到客户端侧上报ID。
25 二次上报
当崩溃发生时,CrashSight会尝试立即将错误信息上报到后台,但是因为种种不可抗因素(例如用户强杀程序,网络错误等),崩溃信息的处理和上报可能无法立即完成。在下次启动时,CrashSight会检查上次是否有未上报的崩溃信息,如果有,则会进行上报,这一过程被称为二次上报。值得注意的是,由于上次崩溃信息处理的过程可能没有完整进行,二次上报的崩溃信息有时会有所缺失。
26 符号表
CrashSight需要符号表才能对堆栈进行还原,上传符号表请参考符号表使用处理相关说明。
为了保证数据安全,CrashSight不会要求您直接上传原始符号表文件(so、dsym、pdb等),而是使用我们的符号表工具提取出stif文件再进行上传。
每个符号表拥有一个唯一的UUID,如果上传的符号表UUID与之前的一样,CrashSight认为这份符号表是重复的,将会使用新的符号表替代旧的(换言之,如果您上传了错误的符号表,您可以利用这个机制来修正错误)。在还原堆栈时,CrashSight会优先使用UUID匹配符号表,如果匹配失败,则会使用版本号+库名来查找符号表。
上传Android符号表时,请务必保证您的so文件带有调试信息。您可以通过stif文件的大小来简单判断,如果生成的stif文件很小(<=1kb),则可能是您使用了不带调试信息的so来制作符号表,这样的符号表并不能成功还原堆栈。获取带调试信息的so的方法可参考各平台符号表文件格式,及在unity、unreal引擎中的生成方法。
27 搜索维度
CrashSight页面中提供了丰富的问题筛选功能,以下是可选搜索维度的含义。
搜索维度 | 含义 | 搜索维度 | 含义 |
---|---|---|---|
问题最后上报时间 | 问题最近一次上报的时间 | 问题首次上报时间 | 问题初次上报的时间 |
问题首次上报版本 | 问题初次上报时的版本号 | 异常类型 | CrashSight对异常上报的分类,如Native崩溃、C#错误等 |
异常大类 | 崩溃、ANR或错误 | 问题标签 | 可以在“问题列表”页设置的自定义标签 |
问题处理状态 | 问题处理状态,可在“问题列表”页配置 | 是否关联缺陷单 | 是否关联缺陷单,可在“问题列表”页配置 |
问题处理人 | 问题处理人,可在“问题列表”页配置 | 版本 | CrashSight SDK提取到的版本号,可通过接口设置 |
上报时间 | 问题上报时间 | 发生时间 | 问题发生时间 |
应用包名/Bundle ID | Android的包名,或iOS的Bundle ID | 应用分发渠道 | 应用分发渠道,可通过接口设置 |
问题ID | 问题列表中展示的问题ID,一类问题拥有同一个问题ID | 上报ID | 服务端生成的上报ID,每一次上报都有唯一的上报ID |
客户端侧上报ID | 客户端上报时生成的上报ID,可以在日志中搜索“expuid”查看,也可在上报详情中查看 | 用户ID | 用于标识用户,可通过接口设置,默认为“unknown” |
设备ID | 用于标识设备,详见Device ID | 异常名 | 异常名 |
异常消息 | 异常消息 | 设备原始Model | 从系统接口提取到的机型 |
应用位数 | 32位或64位 | 系统版本 | 系统版本 |
出错进程名 | 出错进程名 | 出错线程名 | 出错线程名 |
运行时长 | 运行时长 | 是否模拟器 | 是否模拟器 |
是否系统 退出 | CrashSight后台匹配到系统退出特征 | ROM | 系统固件名称(仅Android) |
自定义关键字 | 用户自定义的关键字,详见自定义数据 | 出错堆栈 | 出错线程的堆栈 |
出错堆栈(还原前) | 还原前的原始堆栈 |
28 系统退出关键字
在一些情况下,app会在退出时发生崩溃,这种崩溃对用户来说是无感知的,所以业务对这类崩溃的关注优先级不高。
CrashSight通过识别系统退出关键字来判断这类崩溃,它们不会被计入大盘统计,并在TOP问题排行中单独列出。
CrashSight将堆栈中匹配到以下关键字的崩溃识别为系统退出:
Android系统退出关键字 | 说明 |
---|---|
CleanupEngine | Unity引擎中的退出方法 |
Runtime.getRuntime().exit | Java系统库方法 |
System.exit | Java系统库方法 |
UnityCleanup | Unity引擎中的退出方法 |
iOS系统退出关键字 | 说明 |
---|---|
applicationWillTerminate | 用户手动杀进程退出 |
CleanupEngine | Unity引擎中的退出方法 |
FEngineLoop::Exit | Unreal引擎中的退出方法 |
StaticExit | Unreal引擎中的退出方法 |
terminateWithSuccess | iOS系统库中非公开的API |
The application did not terminate cleanly but no crash occured | CrashSight SDK 检测到App未知退出 |
UIAlertManager hideAlertsForTermination | iOS系统库中非公开的API,iOS 11之后已经消失 |
UIApplication _handleApplicationDeactivationWithScene:shouldForceExit:transitionContext:completion | iOS系统库中非公开的API,iOS 11之后已经消失 |
UIApplication _handleApplicationDectivationWithScene:shouldForceExit:transitionContext:completion | iOS系统库中非公开的API,iOS 11之后已经消失 |
UIApplication _terminateWithStatus | iOS系统库中非公开的API |
UnityAppController applicationWillTerminate | Unity引擎中的退出方法 |
UnityCleanup | Unity引擎中的退出方法 |
_exitapp (exitgame.mm | 非系统库退出方法 |
_exitApp (exitGame.mm | 非系统库退出方法 |
__cxa_finalize_ranges | iOS系统库中的API,可参考源码 |
29 堆栈回溯
堆栈回溯是一种描述程序执行时函数调用顺序的技术。当程序运行时,函数调用将在内存中的堆栈上形成一个帧的序列。每个帧都包含了特定函数调用的上下文信息,如局部变量、参数和返回地址。堆栈回溯提供了一种方法,可以在程序执行过程中 查看这些帧,从而了解函数调用的历史和顺序。
CrashSight在不同平台上通过libunwind或minidump两种方式进行堆栈回溯,下面将介绍两种回溯方式的原理。
29.1 libunwind回溯
libunwind回溯在崩溃处理函数中执行。发生崩溃时,它需要立即在当前设备的当前进程中执行。libunwind回溯的处理流程如下:
- 根据pc或lr寄存器的值,访问栈内存,依次遍历每一帧,每一帧对应一行堆栈。
这一步可以获取到每一行堆栈的执行地址 - 根据地址找到对应的加载段。
这一步可以获取到加载的库名以及库文件的路径 - 读取本地的库文件。
这一步可以获取到库文件的UUID和架构,如果库中包含符号,还能获取到函数名 - 将执行地址、库文件路径、UUID、架构和函数名(如果有)拼接成字符串。
CrashSight Android SDK默认使用libunwind来进行回溯,iOS SDK中也实现了一套原理几乎一样的回溯机制。
29.2 minidump回溯
minidump回溯依赖minidump生成的dump文件。崩溃发生时,异常处理程序需要立即将栈内存信息写入dump文件;有了dump文件,回溯的过程可以在任意时间、任意设备上执行。minidump回溯的处理流程如下:
崩溃发生时,客户端上:
- 创建dump文件,其中包含崩溃发生时的栈内存信息、内存映射信息和寄 存器信息。
崩溃信息上传后,服务器上:
- 读取dump文件中的栈内存信息,依次根据CFI遍历栈帧,每一帧对应一行堆栈。
这一步可以获取到每一行堆栈的执行地址 - 根据地址找到加载段,并检索对应的内存映射信息。
这一步可以获取到加载的库名、UUID和架构 - 将执行地址、库名、UUID和架构拼接成字符串。
CrashSight Windows SDK默认使用minidump来上报崩溃信息,Android SDK也支持生成minidump(该功能需要手动开启)。
29.3 两种回溯方式的对比
两种回溯方式的一些主要区别如下表:
区别项 | libunwind | minidump |
---|---|---|
系统库信息 | 由于可以直接访问本地的库文件,能够获取系统库的路径、架构、buildID,与其它库无异 | 只能获取到地址和库名 |
非崩溃线程栈 | 只回溯崩溃线程的堆栈 | 栈扫描时dump了所有线程栈的信息,所以可以回溯其它非崩溃线程的堆栈 |
堆栈异常时的回溯能力 | 每一个栈帧的回溯依赖上一帧,所以回溯到异常的栈帧时会中断 | dump文件中有完整的栈内存信息,即使堆栈中出现异常,也可以获取后续的栈帧信息 |