Android 性能监控系列一(原理篇),闭关 60 天学懂 NDK+Flutter
但是项目上线后,到底有没有性能问题?用户体验到底怎么样?在用户的使用场景中到底会遇到哪些性能问题?我们项目的性能短板又在哪里?这些问题的答案我们都不得而知,因此开发一套完善的性能监控体系势在必行。我们团队在今年开始着手开发自己的性能监控组件 APM,希望通过它来采集线上性能数据,找到性能短板,针对性的优化用户体验。
APM 全称 Application Performance Management & Monitoring (应用性能管理/监控)
后面我会通过一系列的文章来介绍 APM 的原理、框架设计与实现等等。本篇就是这个系列的第一篇,主要从实现原理方面来介绍 APM。按照目前的计划,这个系列大致会从如下几个方面来展开:
原理篇:主要介绍 APM 的实现原理;
设计篇:介绍整个 APM 框架设计;
实现篇-Gradle Plugin:介绍 Gradle 插件在 APM 项目中的应用,以及如何开发一个 Gradle Plugin;
实现篇-Javassist/ASM:Javassist、ASM 等字节码操作库的介绍,以及如何使用它们在编译时插入代码来采集各项性能数据;
实现篇-数据存储及上报:介绍 APM 框架的存储上报机制及实现过程;
发布集成:最后会介绍如何将库发布到 jCenter() 以及如何在生产项目中集成。
这里要向大家交代一点是,之前的文章为了极力做到将复杂的问题用通俗易懂的方式解释清楚,又要面面俱到,往往篇幅过长;诸如之前写过的RxJava系列6(从微观角度解读RxJava源码) 、神兵利器Dagger2 、安居客 Android 项目架构演进 、Android 模块化探索与实践 、写给 Android 应用工程师的 Binder 原理剖析等文章,篇幅通常都在 8000~10000 字以上,通篇阅读下来可能需要近半个小时的时间,不太符合当下碎片化阅读的需求;因此在后面的写作上会控制篇幅,尽量控制在 10 分钟以内的长度。
这也是我为什么会将 APM 作为一个系列来介绍的原因,同时这也能保证后面在介绍 APM 的时候能够深入到实现细节,避免泛泛而谈。
二. Android APM 的基本原理
市场上有很多商业化的 APM 平台,比如著名的 NewRelic,还有国内的 听云、OneAPM 等等。这些平台的工作流程基本都是一致的:
首先在客户端(Android、iOS、Web 等)采集数据;
接着将采集到的数据整理上报到服务器;
服务器接收到数据后建模、存储、挖掘分析,让后将数据可视化,供用户使用。
如下图:
我们介绍的 Android APM 框架其实就是在 Android 平台上应用的一个数据采集上报 SDK。主要包含三大模块:
数据采集
数据存储
数据上报
其中数据采集是整个 APM 框架的核心。
数据采集我们可以通过手动埋点的方式,但这种方式工作量巨大、不灵活,而且无法覆盖到所有场景;因此只能通过自动化的方式来采集数据。在应用构建期间,通过修改字节码的方式来进行字节码插桩就是实现自动化的方案之一。
三. Android 打包流程及字节码插桩原理
在谈字节码插桩的原理之前,首先我们看看 Android 的打包流程,如下图:
从上面这张打包流程图我们可以看到,一个 App 的所有 class 文件,包括第三方的 class 文件都会经过 dex 的过程打包成一个或者多个 dex 文
件。
这其中涉及到两个很关键的环节:
javac:将 .java 格式的源代码文件编译成 class 文件;
dex: 将 class 格式的文件打包汇总,组成一个或者多个 dex 文件。
我们想要对字节码进行修改,只需要在 javac 之后 dex 之前遍历所有的字节码文件,并按照一定的规则过滤修改就好了,这里便是字节码插桩的入口。
那么我们到底如何介入打包过程,在 class 转换为 dex 文件的时候实现对字节码的修改呢?
答案是 transform api
Android Gradle Plugin 1.5.0 及以上版本,Google 官方提供了 transform api 作为字节码插桩的入口。我们只需要实现一个自定义的 Gradle Plugin,然后在编译阶段去修改字节码文件。对于 Gradle Plugin 的具体实现后面的文章再做详细讲解。
评论