APM(应用性能管理)实现关键点:
1,主要由4个子项目组成:
1), apm lib:作为agent,app的公共库,实现apm客户端的主要业务逻辑,如汇总,封装,发送;该库必须要在android编译环境下生成,然后对内部引用的第三方库做移包处理,解决被跟踪api的版本兼容问题。
2),agent:利用java规范提供的动态或静态插入代码的机制,实现对关键代码的hook,进而触发汇总,上报行为,常用修改字节码的库有javaassist,AMS,其中AMS可以做到编译时修改字节码,不增加额外函数,对应用性能影响很小,故推荐。
3),gradle plugin:android IDE主流是AS,内部主要采用gradle编译系统,在复杂的编译环境下时能自动实现修改字节码能力的最有效的做法是实现gradle插件
4),数据呈现:个人建议用ElasticStack + Kibana, 传输用JSON格式,后台开发成本则会低很多
2,gradle版本对hook函数方式有影响,另外混淆,multiDex, retrolambda也需要特殊处理
关键gradle plugin实现代码如下:
project.configure(project, {
String agentArgs = System.getProperty("TypanyAPM.AgentArgs")
pluginExtension = project.extensions.create("typanyapm", TypanyAPMExtension.class)
typanyAPMTransform = new TypanyAPMTransform(project, pluginExtension, agentArgs)
if(project.hasProperty("android")) {
typanyAPMInstrumentTask = project.task(type:TypanyAPMInstrumentTask)
typanyAPMDeinstrumentTask = project.task(type:TypanyAPMDeinstrumentTask)
project.tasks.whenTaskAdded( { task ->
def taskName = task.getName().toLowerCase()
if(taskName.startsWith("transformclasseswithdexbuilderfor") || taskName.startsWith("transformdexarchivewithdexmergerfor"))
{
if(!pluginExtension.shouldUseTransformApi()) {
logger.warn("[typanyapm.info] Android Gradle plugin version 3.+ detected. Using transform API");
return pluginExtension.setUseTransformApi(true)
}
return
}
if(taskName.startsWith("transformclasseswithdexfor") || taskName.startsWith("dex")) {
return configureInstrumentationTask(task)
}
} )
project.afterEvaluate( {
try
{
if (checkDexguard(project)) {
logger.debug("[typanyapm.debug] Dexguard detected.");
}
if (checkRetrolambda(project)) {
logger.debug("[typanyapm.debug] Retrolambda detected.");
}
configureMultidexTask(project)
return (pluginExtension.shouldUseTransformApi()) ? this.configureMapUploadTask(project) : null
}
catch (MissingPropertyException e) {
return logger.warn("[typanyapm.warn] Not supported for library builds. ", e);
}
} )
logger.debug("[typanyapm.debug] TransformAPI: registering TypanyAPMTransform(" + agentArgs + ")");
project.android.registerTransform(typanyAPMTransform)
}
}