乐趣区

关于ios:iOS应用性能数据采集原理和优化实践-详细版

作者简介

刘徐兵(Alvin Liu),云智慧 / 开发经理。曾在高德、当当有多年大型 App 开发教训,在云智慧从事 APM SDK 研发工作 5 + 年。对 App 开发和性能优化有深刻的钻研和实际。

iOS 利用数据采集的根底 Objective-C Runtime

1、音讯转发

Objective- C 语言扩大了 C 语言,扩大的外围在于引入了 Runtime 库,使 Objective- C 语言领有了面向对象和动静运行时的个性。而动静运行时机制的外围和体现是音讯转发机制。

Objective- C 语言领有动静运行时的机制,办法的执行是在运行阶段决定的而不是在编译阶段决定的。而办法执行的本质是向对象发送了一个音讯,官网 API 为

objc_msgSend(void /* id self, SEL op, ... */)

objc_msgSend 有 2 个罕用参数:id self 和 SEL op,用于标识对象和办法,即向某个对象发送了某个音讯。因而 Objective- C 的 [instance method] 调用会被编译器转换成 C 语言 API objc_msgSend 的调用。

以下音讯转发机制原理图从官网文档翻译而来:

音讯转发机制示例图

如上图所示,Objective- C 的音讯转发流程中,在以后对象办法列表中找不到办法的实现时,运行时环境会顺次进行三个阶段的查找

第一阶段

对象在收到无奈解决的音讯时,首先调用所属类的下列类办法。

+(BOOL)resolveInstanceMethod:(SEL)sel{ 

    // 默认返回 NO 

    return NO;

} 

+(BOOL)resolveClassMethod:(SEL)sel{ 

    // 默认返回 NO 

    return NO;

}

如果在其中找到了办法的实现,则进行音讯解决;否则就进入第二阶段。

第二阶段

在以后类里找不到该办法的实现时,运行时零碎尝试更换调用的对象,会调用如下办法

-(id)forwardingTargetForSelector:(SEL)aSelector{}

如果在该办法中还找不到办法的实现,就进入第三阶段。

第三阶段

到这里是最初一个阶段,通过创立 NSInvocation 实例,将与未解决的音讯无关的细节封装起来,运行时零碎调用的接口为

-(void)forwardInvocation:(NSInvocation *)anInvocation{}

该办法会沿着类的继承链始终往上调用,直至在 NSObject 的该办法中抛出 doesNotRecognizeSelector: 异样。

2、函数指针

SEL 是 Objective- C 语言的办法选择器,也就是 selector 的指针。再往底层去,每个办法 SEL 还对应着一个 IMP 函数指针,指向办法实现的首地址。官网 API 为:

typedef id (*IMP)(id, SEL, ...); 

有了它就能够间接执行 IMP 指向的函数(办法)了。

以上介绍了实践根底,上面介绍下基于 Objective- C 语言动静运行时的办法拦挡(Hook)操作。

Hook 原理

Hook 步骤

  1. 应用 Category 个性往类中增加用于拦挡的办法 SEL
  2. 应用零碎 runtime 的接口(Swizzle)替换办法实现体(IMP)

Hook 应用示例图

如图所示,开发者调用原有办法时,会转发到拦挡的办法里,因替换了原办法与拦挡办法的入口地址(IMP),在拦挡办法执行完结时能调回原办法,对原有业务没有影响。

Hook 回调函数

难点:不是类的实例形式,不能用 Category 个性。

优化前: 全工程扫描,再拦挡。

毛病:只能在主线程中操作,扫描文件数和耗费的工夫与 App 的规模大小成正比。

回调函数拦挡优化

步骤:

  1. 针对要应用 protocol 的零碎类应用 Category 个性增加拦挡办法
  2. 拦挡设置 delegate 的 setter 办法,获取到 delegate 的实例
  3. 针对获取到的 delegate 实例再进行回调办法拦挡

优化后

1、提早拦挡:在办法被调用时才被拦挡而且只拦挡一次

2、SDK 的启动操作跟 App 的业务和规模无关,对 App 的影响降到最低

解体解码实际

目标: 理解 iOS 解体解码原理

解体解码步骤

  1. 虚拟内存偏移量:145624->0x238d8->0x00000001000238d8
  2. 应用 dwarfdump 命令,将 dSYM 文件解析成可读文件

dwarfdum-e–debug-info 蕴含全副类和办法的代码和地址映射信息 ->信息文件

dwarfdum-e–debug-line 蕴含全副类的代码行号和地址映射信息 ->行号文件

  1. 在信息文件中查找偏移量所在的类和办法,失去解体的类和对应的办法
  2. 在行号文件中查找偏移量所在的行号,失去具体的解体行号

虚拟内存偏移量:

0x00000001000238d8

dSYM 文件解析命令

  1. symbolicatecrash->全文本解析
  2. atos(mac)/atosl(linux)->单行解析

H5 页面监控原理

以上介绍了零碎原生接口的数据采集原理,上面介绍下 H5 页面数据采集实现原理。

H5 页面数据采集通过主动往 H5 页面注入 JS 代码实现。流程如下图所示

H5 页面注入 JS 代码示意图

如上图所示,在 UIWebView 时代,通过 NSURLProtocol 协定簇的接口,拦挡到加载页面数据的接口,获取到 H5 数据块,检测数据块中的 <head> 标签,将 JS 代码注入到 <head> 中。这样 JS 代码就和 H5 页面代码一起加载、工作,可能采集到 H5 页面的相干信息。JS 代码采集到信息后,通过 iframe 的形式触发 UIWebView 的回调将信息发送给原生 SDK 端存储、上报。

在 WKWebView 时代,因为 WKWebView 是独自的过程,在 App 里从零碎的网络协议簇无奈获取到 WKWebView 的数据,可通过拦挡 WKWebView 的回调函数去执行 JS 代码,能起到与 UIWebView 同样的数据采集成果。这里不再赘述。

PS:JS 代码的工作原理是另一个技术畛域的领域,不在这里赘述。

写在最初

近年来,在 AIOps 畛域疾速倒退的背景下,IT 工具、平台能力、解决方案、AI 场景及可用数据集的迫切需要在各行业爆发。基于此,云智慧在 2021 年 8 月公布了 AIOps 社区, 旨在树起一面开源旗号,为各行业客户、用户、研究者和开发者们构建沉闷的用户及开发者社区,独特奉献及解决行业难题、促成该畛域技术倒退。

社区先后 开源 了数据可视化编排平台 -FlyFish、运维治理平台 OMP 、云服务治理平台 - 摩尔平台、 Hours 算法等产品。

我的项目介绍:https://www.cloudwise.ai/flyF…

Github 地址:https://github.com/CloudWise-…

Gitee 地址:https://gitee.com/CloudWise/f…

请您通过下方链接理解咱们,增加小助手微信(xiaoyuerwie),备注:飞鱼。申请加入开发者交换群,可与业内大咖进行 1V1 交换!

也可分割咱们理解云智慧 AIOps 资讯,理解云智慧开源社区其余我的项目开源状况!

退出移动版