iOS闪退监控方案

实现方案

基本思路:日志捕获采用 KSCrash,捕获的日志上传服务器,然后在服务器对日志进行符号化。

KSCrash 的上传日志需要注意启动闪退的情况,一般是应用启动如果存在日志,需要先 hold 主线程,等上传完再释放。

基本模型如下:

//防止在登录前就必闪情况
__block BOOL finished = NO;
[self uploadIfExistWithCompleteHandler:^{
    finished = YES;
}];
//防止上传失败
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    finished = YES;
});
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSRunLoopCommonModes];
while (!finished) {
    [runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
}

符号化方案

以下主要讨论的是服务端通过脚本自动符号化日志需求

方案一:通过修改配置,不需要自主符号化日志,也能看到日志堆栈类和函数名

通过在 Xcode 中设置 Build Settings -> Strip Style -> Debugging Symbols

Strip Style 有三个选项如下

  • All Symbols:剥离所有符号表和重定向信息
  • Non-Global Symbols:剥离非全局的符号(包括调试符号),保留外部符号
  • Debugging Symbols:剥离调试符号,保留局部符号和全局符号

开启设备符号化需要在最终版本中包含基本符号,所以要在 build settings 中设置 Strip StyleDebugging Symbols。也会造成最终的二进制文件大小增加 5% 左右,这也是之前 PLCrashReporter 中提到的,不过当时查到的数据是 30-50%,确实测试后没有如此大的差距,也算是解了疑惑,由于打包包含了基本符号表导致的二进制大小增加。

注意:系统库无法符号化,需要 symbolicatecrash 来符号化

方案二:通过 symbolicatecrash 自主符号化日志

atos 是苹果提供的符号化工具,在 Mac OS 系统下默认安装,他的缺点是只能一个地址一个地址逐个翻译。

symbolicatecrash 是 Xcode 自带的一个程序,他是对 atos 的封装,可以翻译整个 crash 文件。

接下来通过使用 symbolicatecrash 进行符号化日志

第一步:获取 symbolicatecrash 文件,通过使用以下命令搜索,找到之后拷到闪退日志目录下

find /Applications/Xcode.App -name symbolicatecrash -type f

第二步:设置路径

export DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer"

第三步:符号化日志,cd 到闪退日志目录下,然后运行下面命令

./symbolicatecrash log.txt -d xxx.App.dSYM > result.txt  

获取符号文件

获取项目符号文件

iOS 的打包一般有两种方式,Xcode 打包或者脚本打包。

不过哪种方式都会生成 xxx.xcarchive 文件,打开就可以看到 dSYMs 符号文件。

  1. Xcode 打包:在 Xcode 中工具栏上 Window -> Organizeer -> 选择相应的App -> Archives -> 选择对应的包进入就可以看到 xxx.xcarchive 文件
  2. 脚本打包:一般ipa包生成同时旁边也会生成 xxx.xcarchive 文件

这里有个问题,闪退日志必须和符号化文件匹配才能解析,我们可以通过 UUID 来匹配

dSYM 的 UUID 获取方式

命令:dwarfdump --uuid appName.app.dSYM

例如:dwarfdump --uuid /Users/xxx/Desktop/Demo.app.dSYM
结果:UUID: 35E34DE0-4C45-36CF-8F11-1F33BA40F3ED (arm64)

日志自动带上了 UUID

image.png

此时符号化的日志如下

image-1.png

获取系统符号文件

系统符号文件会根据不同 CPU 架构(armv7,armv7s,arm64,arm64e),以及不同系统对应的文件都不一样。通过 symbolicatecrash 工具进行符号化时,工具会自动会在 /Users/xxx/Library/Developer/Xcode/iOS DeviceSupport 目录下进行匹配解析。

方式一:从真机上获取

当你用 Xcode 第一次连接某台设备进行真机调试时,会看到 Xcode 显示 Processing symbol files ,这时候就是在拷贝真机上的符号文件到 Mac OS 系统的 /Users/xxx/Library/Developer/Xcode/iOS DeviceSupport 目录下。

image-2.png

14.6 (18F72) arm64e 就是对应的系统符号文件

如果仅通过真机来获取系统的符号化文件,比较局限,把不同系统版本以及不同 CPU 架构类型的手机准备齐全比较难。

方式二:从固件中提取符号文件

下面以获取 iPhone12 系统为 iOS 14.6 为例。

第一步:下载对应的固件,从中获取 dyld_shared_cache_xxx 可执行文件,其中 xxx 是 CPU 架构类型。

www.theiphonewiki.com 下载。优点整理的齐全,缺点下载速度有点慢。

image-3.png

下载完解压得到,获取最大的 dmg 文件

image-4.png

运行 018-17771-088.dmg 获取 dyld_shared_cache_arm64e,路径 System -> Library -> Caches -> com.apple.dyld

image-5.png

第二步:通过 dyld 生成 dsc_extractor 可执行文件。

在苹果的开源网站下载 dyld 源码,例子中下载了 dyld-750.6.tar.gz 解压

image-6.png

修改 dsc_extractor.cpp 文件,把 #if 0 改成 #if 1,屏蔽其他代码

#if 1
// test program
#include <stdio.h>
#include <stddef.h>
#include <dlfcn.h>


typedef int (*extractor_proc)(const char* shared_cache_file_path, const char* extraction_root_path,
                              void (^progress)(unsigned current, unsigned total));

int main(int argc, const char* argv[])
{
    if ( argc != 3 ) {
        fprintf(stderr, "usage: dsc_extractor <path-to-cache-file> <path-to-device-dir>\n");
        return 1;
    }

    //void* handle = dlopen("/Volumes/my/src/dyld/build/Debug/dsc_extractor.bundle", RTLD_LAZY);
    void* handle = dlopen("/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/usr/lib/dsc_extractor.bundle", RTLD_LAZY);
    if ( handle == NULL ) {
        fprintf(stderr, "dsc_extractor.bundle could not be loaded\n");
        return 1;
    }

    extractor_proc proc = (extractor_proc)dlsym(handle, "dyld_shared_cache_extract_dylibs_progress");
    if ( proc == NULL ) {
        fprintf(stderr, "dsc_extractor.bundle did not have dyld_shared_cache_extract_dylibs_progress symbol\n");
        return 1;
    }

    int result = (*proc)(argv[1], argv[2], ^(unsigned c, unsigned total) { printf("%d/%d\n", c, total); } );
    fprintf(stderr, "dyld_shared_cache_extract_dylibs_progress() => %d\n", result);
    return 0;
}
#endif

修改 dsc_iterator.cpp 文件,屏蔽头文件 #include "SupportedArchs.h"

在终端上 cd 到 dyld 源码目录 launch-cache 下,在终端命令行编译并生成 dsc_extractor 可执行文件

clang++ -o dsc_extractor dsc_extractor.cpp dsc_iterator.cpp

第三步:通过 dyld_shared_cache_xxxdsc_extractor 获取系统符号文件

新建一个文件夹把 dsc_extractordyld_shared_cache_arm64e 两个可执行文件放入其中

通过以下命令就可以生成系统符号文件

dsc_extractor <path-to-cache-file> <path-to-device-dir>

比如:

./dsc_extractor ./dyld_shared_cache_arm64e ./Symbols

新建一个文件夹 14.6 (18F72) arm64e,把 Symbols 拖入其中,然后拖入 /Users/xxx/Library/Developer/Xcode/iOS DeviceSupport 目录下。

此时符号化的日志如下

image-7.png

参考资料

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容