作者简介
刘徐兵(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 步骤
- 应用 Category 个性往类中增加用于拦挡的办法 SEL
- 应用零碎 runtime 的接口(Swizzle)替换办法实现体(IMP)
Hook 应用示例图
如图所示,开发者调用原有办法时,会转发到拦挡的办法里,因替换了原办法与拦挡办法的入口地址(IMP),在拦挡办法执行完结时能调回原办法,对原有业务没有影响。
Hook 回调函数
难点:不是类的实例形式,不能用 Category 个性。
优化前: 全工程扫描,再拦挡。
毛病:只能在主线程中操作,扫描文件数和耗费的工夫与 App 的规模大小成正比。
回调函数拦挡优化
步骤:
- 针对要应用 protocol 的零碎类应用 Category 个性增加拦挡办法
- 拦挡设置 delegate 的 setter 办法,获取到 delegate 的实例
- 针对获取到的 delegate 实例再进行回调办法拦挡
优化后
1、提早拦挡:在办法被调用时才被拦挡而且只拦挡一次
2、SDK 的启动操作跟 App 的业务和规模无关,对 App 的影响降到最低
解体解码实际
目标: 理解 iOS 解体解码原理
解体解码步骤
- 虚拟内存偏移量:145624->0x238d8->0x00000001000238d8
- 应用 dwarfdump 命令,将 dSYM 文件解析成可读文件
dwarfdum-e–debug-info 蕴含全副类和办法的代码和地址映射信息 ->信息文件
dwarfdum-e–debug-line 蕴含全副类的代码行号和地址映射信息 ->行号文件
- 在信息文件中查找偏移量所在的类和办法,失去解体的类和对应的办法
- 在行号文件中查找偏移量所在的行号,失去具体的解体行号
虚拟内存偏移量:
0x00000001000238d8
dSYM 文件解析命令
- symbolicatecrash->全文本解析
- 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 资讯,理解云智慧开源社区其余我的项目开源状况!