原文在这:http://www.cnblogs.com/hyddd/p/5329608.html

前言

已很少写文章,不过这次感觉有必要写一下。因为:

  1. 这个方案通过 debug 逆向得来,很有参考意义。
  2. iOS 这方面资料非常少,做这块时,无论国内外,翻遍了 google,baidu 都没太多合适的资料。 故此,我觉得把整个流程记录下来,你可以认为,这是一次 iOS 的 debug 之旅。

问题起因

最近做 iOS 性能测试,要监控一段时间内 App 的 CPU 占用和网络流量。遗憾的是,iOS instruments 提供的 Activity Monitor 和 Network 模板并不满足我的需求。在 UI 工具中,Activity Monitor 只提供了 CPU 瞬时值,Network 也只提供了总流量,它们均不提供采集样本值。

由于 iOS 闭源,放出的资料又少,故解决此问题的方案屈指可数:

(1). 设备越狱,通过后台守护进程采集数据。
缺陷:新设备无法越狱。

(2). 在产品中嵌入性能数据采集模块。
缺陷:我不倾向在产品中嵌入测试模块;另外,该方案对第三方产品也失效。

(3). 从 instruments 结果文件(.trace)中尝试获取样本值。
缺陷:能不能做都不知道…

因方案 1,2 有硬伤,故选方案 3 尝试。

其实,我开始时也并不确定 trace 文件包含样本数据,但 instruments 可通过 trace 文件恢复监控过程的柱状图,它给了我继续这个方向的信心。

而从 trace 文件获取样本值,有 2 个方向:

(1)分析 trace 结构,获取明文数据
trace 其实是文件夹,但里面文件内容均为二进制,遂放弃......

(2)通过 Undocumented API 解析 trace 文件
由于 instruments 可以解析 trace 文件,那么(2)方法是一定可行的,问题是怎么找到相关的 Undocumented API。

Undocumented API 可行性确认

Lucky,我同事发现了这玩意:TraceUtility,它一个是获取 Time Profiler 样本值的工具(那作者也和我一样遇到这种蛋疼问题......),并且 Readme 中找到重要线索:

(1)所需的 Undocumented API 在/Applications/Xcode.app/Contents/Applications/Instruments.app/Contents/Frameworks:

(2)Instruments 模板以 PlugIns 形式存在于
/Applications/Xcode.app/Contents/Applications/Instruments.app/Contents/PlugIns

TraceUtility 源码分析

项目就 2 个文件:

InstrumentsPrivateHeader.h: Undocumented API 和 Undocumented 数据结构声明。

main.m:样本数据提取主流程。

深入 Debug 分析

然而 TraceUtility 仅用于获取 Time Profiler 样本数据,并不能满足我获取 CPU 和网络流量样本的要求。

我需要解决的问题是:

(1)确定 instruments 处理类。
(2)从处理类中读出样本数据。

1. 确定 instruments 处理类

方式很简单,在 loadDocument 后,debug 变量 trace._baseInstruments


对比图 1、2

在另一个 github 项目class-dump-o-tron, 搜到了相关信息:XRSamplerRun.h,然而在 ActivityPlugin.xrplugin 下却没找到 XRActivityRun.h,而是 XRActivityInstrumentRun.h(大 Apple 的命名能统一点嘛……);在 XRNetworkingPlugIn.xrplugin 下,找到了 XRNetworkingRun.h;

2. 读取 trace 样本数据

(1)CPU 样本结果

debug 变量 run._data,发现了样本数据

TraceUtility 使用了 Undocumented API 获取数据,而我在 XRActivityInstrumentRun.h 没找到相关 API,直接通过反射获取吧。


至此,CPU 样本数据获取完成。

(2)网络流量样本结果

XRNetworkRun 和 XRActivityInstrumentRun 对象属性不一样,没有_data,但_saveActivityQueries 中有段 sql,初步预估这玩意用了 localdb,但 db 类型未明。另外,估计_saveInstrumentUUID 应该 db 文件。

然后 cat 2A183EAD-5B9C-45DD-B2BA-D63DCD1165D4 看下,因为文件可能会在头部加注类型信息,cat 结果如下:

捕获 SQLite 文件一个……接下来的事情就是分析表结构了,没什么难度,不作详述了。至此,网络流量样本数据获取完成。


↙↙↙阅读原文可查看相关链接,并与作者交流