360 Argus APM 源码分析(3)—— argus-apm-aop源码分析

Android APM方案(一)完成代码注入 Android APM方案(一)完成代码注入 什么是APMAPM 是Application perfmance monitor的简称, 应用性能监控。在移动互联网对人们生活影响越来越大的今天,App的功能越来越全面,从吃穿住行,到支付开房,全方面覆盖。相同功能的App存在很多竞品,比如携程和艺龙,天猫和京东,网易云音乐和QQ音乐。随之而来的就是App性能的要求越来越高,不能被动的等待用户异常的发生,应该主动监控 阅读详情

argus-apm-aop源码分析

argus-apm-aop主要实现了面向Activity的切面和面向HttpClient和URLConnection的切片。阅读代码需要有AOP和aspectj的基础知识。

  • TraceActivity
    TraceActivity类实现对Activity(还有Application)的切面。
@Aspect
public class TraceActivity {

    @Pointcut("!within(com.argusapm.android.aop.*) && !within(com.argusapm.android.core.job.activity.*)")
    public void baseCondition() {
    }

    @Pointcut("execution(* android.app.Application.onCreate(android.content.Context)) && args(context)")
    public void applicationOnCreate(Context context) {

    }

    @After("applicationOnCreate(context)")
    public void applicationOnCreateAdvice(Context context) {
        AH.applicationOnCreate(context);
    }

    @Pointcut("execution(* android.app.Application.attachBaseContext(android.content.Context)) && args(context)")
    public void applicationAttachBaseContext(Context context) {
    }

    @Before("applicationAttachBaseContext(context)")
    public void applicationAttachBaseContextAdvice(Context context) {
        AH.applicationAttachBaseContext(context);
    }

    @Pointcut("execution(* android.app.Activity.on**(..)) && baseCondition()")
    public void activityOnXXX() {
    }

    @Around("activityOnXXX()")
    public Object activityOnXXXAdvice(ProceedingJoinPoint proceedingJoinPoint) {
        Object result = null;
        try {
            Activity activity = (Activity) proceedingJoinPoint.getTarget();
            //        Log.d("AJAOP", "Aop Info" + activity.getClass().getCanonicalName() +
            //                "\r\nkind : " + thisJoinPoint.getKind() +
            //                "\r\nargs : " + thisJoinPoint.getArgs() +
            //                "\r\nClass : " + thisJoinPoint.getClass() +
            //                "\r\nsign : " + thisJoinPoint.getSignature() +
            //                "\r\nsource : " + thisJoinPoint.getSourceLocation() +
            //                "\r\nthis : " + thisJoinPoint.getThis()
            //        );
            long startTime = System.currentTimeMillis();
            result = proceedingJoinPoint.proceed();
            String activityName = activity.getClass().getCanonicalName();

            Signature signature = proceedingJoinPoint.getSignature();
            String sign = "";
            String methodName = "";
            if (signature != null) {
                sign = signature.toString();
                methodName = signature.getName();
            }

            if (!TextUtils.isEmpty(activityName) && !TextUtils.isEmpty(sign) && sign.contains(activityName)) {
                invoke(activity, startTime, methodName, sign);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return result;
    }

    public void invoke(Activity activity, long startTime, String methodName, String sign) {
        AH.invoke(activity, startTime, methodName, sign);
    }
}

@Aspect注解表明这是一个aspectj的切面类。
第一个PointCut要排除com.argusapm.android.aop和com.argusapm.android.core.job.activity下的所有切点。第二个PointCut指定android.app.Application的onCreate方法作为切点,并且要获取方法的参数。applicationOnCreateAdvice方法上有After注解,切点事前面定义的applicationOnCreate,就是在android.app.Application.onCreate执行的最后,织入代码:AH.applicationOnCreate(context)。该方法实际上只打印了一行log。applicationAttachBaseContextAdvice方法上有Before注解,它的切点在android.app.Application.attachBaseContext方法上,所以,在这个方法运行的开始,要调用AH.applicationAttachBaseContext(context)。这个方法获取当前的系统时间,保存在ActivityCore的appAttachTime属性中,也打印一行log。
activityOnXXXAdvice方法上有Around注解,它的切点在android.app.Activity的以on开头的系列回调方法上,并且要满足前面定义的baseCondition,也即不在指定的那两个包下的类。因为是Around注解,所以会在切点前后都进行织入操作。通过proceedingJoinPoint.getTarget()获取target Activity的对象activity,获取当前的系统时间startTime。然后执行切点的原始代码。获取Activity的canonical name和切点函数的签名,进一步得到函数的名字。如果activity的canonical name和函数的签名都不是空字符串,并且函数签名的字符串里包含activity的canonical name,调用AH.invoke(activity, startTime, methodName, sign)。
AH.invoke(activity, startTime, methodName, sign)函数的代码如下:

public static void invoke(Activity activity, long startTime, String lifeCycle, Object... extars) {
    boolean isRunning = isActivityTaskRunning();
    if (Env.DEBUG) {
        LogX.d(Env.TAG, SUB_TAG, lifeCycle + " isRunning : " + isRunning);
    }
    if (!isRunning) {
        return;
    }

    if (TextUtils.equals(lifeCycle, ActivityInfo.TYPE_STR_ONCREATE)) {
        ActivityCore.onCreateInfo(activity, startTime);
    } else {
        int lc = ActivityInfo.ofLifeCycleString(lifeCycle);
        if (lc <= ActivityInfo.TYPE_UNKNOWN || lc > ActivityInfo.TYPE_DESTROY) {
            return;
        }
        ActivityCore.saveActivityInfo(activity, ActivityInfo.HOT_START, System.currentTimeMillis() - startTime, lc);
    }
}

首先要判断Activity task有没有运行。Activity task运行的标准是:ApmTask.FLAG_COLLECT_ACTIVITY_AOP标记被设置,TaskManager列表中有ApmTask.TASK_ACTIVITY类型的task,并且该task的mIsCanWork的标记为true。如果Activity task没有运行,直接返回。如果第三个参数lifeCycle是“onCreate",也就是现在执行的是Activity的onCreate回调函数,调用ActivityCore.onCreateInfo(activity, startTime);对其它生命周期,需要从参数lifeCycle转换出对应的life cycle的整型常量,获取到的值必须在合理范围内(大于ActivityInfo.TYPE_UNKNOWN,小于等于ActivityInfo.TYPE_DESTROY)。对于处在合理生命周期的方法回调,调用ActivityCore.saveActivityInfo(activity, ActivityInfo.HOT_START, System.currentTimeMillis() - startTime, lc)。
以下是ActivityCore.onCreateInfo的代码:

public static void onCreateInfo(Activity activity, long startTime) {
    startType = isFirst ? ActivityInfo.COLD_START : ActivityInfo.HOT_START;
    activity.getWindow().getDecorView().post(new FirstFrameRunnable(activity, startType, startTime));
    //onCreate 时间
    long curTime = System.currentTimeMillis();
    saveActivityInfo(activity, startType, curTime - startTime, ActivityInfo.TYPE_CREATE);
}

首先判断是冷启动还是热启动。向Activity的DecorView发送一个新的FirstFrameRunnable。记录当前时间curTime,这个就是onCreate的时间,调用saveActivityInfo(activity, startType, curTime - startTime, ActivityInfo.TYPE_CREATE),保存onCreate的相关信息。
以下是saveActivityInfo的代码:

public static void saveActivityInfo(Activity activity, int startType, long time, int lifeCycle) {
    if (activity == null) {
        if (DEBUG) {
            LogX.d(TAG, SUB_TAG, "saveActivityInfo activity == null");
        }
        return;
    }
    if (time < ArgusApmConfigManager.getInstance().getArgusApmConfigData().funcControl.activityLifecycleMinTime) {
        return;
    }
    String pluginName = ExtraInfoHelper.getPluginName(activity);
    String activityName = activity.getClass().getCanonicalName();
    activityInfo.resetData();
    activityInfo.activityName = activityName;
    activityInfo.startType = startType;
    activityInfo.time = time;
    activityInfo.lifeCycle = lifeCycle;
    activityInfo.pluginName = pluginName;
    activityInfo.pluginVer = ExtraInfoHelper.getPluginVersion(pluginName);
    if (DEBUG) {
        LogX.d(TAG, SUB_TAG, "apmins saveActivityInfo activity:" + activity.getClass().getCanonicalName() + " | lifecycle : " + activityInfo.getLifeCycleString() + " | time : " + time);
    }
    ITask task = Manager.getInstance().getTaskManager().getTask(ApmTask.TASK_ACTIVITY);
    boolean result = false;
    if (task != null) {
        result = task.save(activityInfo);
    } else {
        if (DEBUG) {
            LogX.d(TAG, SUB_TAG, "saveActivityInfo task == null");
        }
    }
    if (DEBUG) {
        LogX.d(TAG, SUB_TAG, "activity info:" + activityInfo.toString());
    }
    if (AnalyzeManager.getInstance().isDebugMode()) {
        AnalyzeManager.getInstance().getActivityTask().parse(activityInfo);
    }
    if (Env.DEBUG) {
        LogX.d(TAG, SUB_TAG, "saveActivityInfo result:" + result);
    }
}

第一个参数是当前的Activity,第二个参数是启动类型(冷启动还是热启动),第三个是生命周期的耗时,第四个是当前所处的生命周期。time的值如果小于Activity生命周期最小数据收集时间间隔单位,就不做记录,忽略该条数据。获取插件的名称pluginName和activity的名字activityName。重置activityInfo的数据,然后依次设置activityInfo的activityName,startType,time,lifecycle等属性的值。获取ApmTask.TASK_ACTIVITY的task,如果task不为null,调用task.save(activityInfo)保存activityInfo中的信息。如果当前以debug模式运行,需要通过ActivityParseTask的parse方法,解析activityInfo的内容并且通过广播发送到悬浮窗。
ITask是个接口,它有一个直接实现类,BaseTask。BaseTask中的save方法,最终需要通过调用IStorage的save方法,实现对传入参数IInfo的保存。这里保存的机会是ActivityInfo类型的数据。ActivityInfo扩展自BaseInfo,当然,BaseInfo是接口IInfo的具体实现。IStorage本身也是一个接口,它有一个直接实现类TableStorage,这是一个抽象类,ActivityStroage扩展了这个类。不过ActivityStorage并没有复写save方法,所以我们可以直接看TableStorage中save的代码:

@Override
public boolean save(IInfo value) {
    ContentValues values = value.toContentValues();
    if (!values.containsKey(BaseInfo.KEY_TIME_RECORD)) {
        values.put(BaseInfo.KEY_TIME_RECORD, System.currentTimeMillis());
    }
    try {
        return null != Manager.getInstance().getConfig().appContext.getContentResolver().insert(getTableUri(), values);
    } catch (Exception e) {
        if (Env.DEBUG) {
            LogX.d(Env.TAG, "save ex : " + Log.getStackTraceString(e));
        }
    }
    return false;
}

首先需要把参数value转换成ContentValues类型,这里实际调用的是ActivityInfo类中该方法的实现。如果values中不包含BaseInfo.KEY_TIME_RECORD这个key,就把当前的系统时间保存为BaseInfo.KEY_TIME_RECORD。向应用的ContentResolver中指定的Uri插入values。这里的Uri是:content://{package name}.apm.storage/activity。通过ApmProvider类中的insert方法可以看到,这里会调用saveDataToDB(new DbCache.InfoHolder(values, table.getTableName()))把数据写入数据库。数据存储和读取等操作我们后面会详细分析。

  • TraceNetTrafficMonitor
    代码这里不贴了。
    baseCondition定义切点,要排除以下的包和类:com.argusapm.android.aop, com.argusapm.android, com.argusapm.android.core.job.net.i,com.argusapm.android.core.job.net.impl, com.qihoo360.mobilesafe.mms.transaction.MmsHttpClient,com.qihoo360.mobilesafe.mms.transaction.MmsHttpClient及其子类。
    httpClientExecuteOne定义切点:org.apache.http.HttpResponse org.apache.http.client.HttpClient.execute(org.apache.http.client.methods.HttpUriRequest)的调用点,第一参数是HttpClient及其子类,第二参数是HttpUriRequest类型;同时要符合baseCondition的切点要求。
    httpClientExecuteOneAdvice上的注解是Around,在符合条件的切点上,调用QHC.execute(httpClient, request)。
    QHC中的execute是一组函数,它们的实现大同小异。比如这里用到的代码如下:
public static HttpResponse execute(HttpClient client, HttpUriRequest request) throws IOException {
return isTaskRunning()
        ? AopHttpClient.execute(client, request)
        : client.execute(request);
}

首先要确认ApmTask.TASK_NET有没有在运行,如果没有运行,直接调用client的execute;如果在运行,调用AopHttpClient.execute(client, request),它的代码是这样的:

public static HttpResponse execute(HttpClient httpClient, HttpUriRequest request) throws IOException {
    NetInfo data = new NetInfo();
    HttpResponse response = httpClient.execute(handleRequest(request, data));
    handleResponse(response, data);
    return response;
}

方法的核心在handleRequest和handleResponse。首先看一下handleRequest的代码:

private static HttpUriRequest handleRequest(HttpUriRequest request, NetInfo data) {
    data.setURL(request.getURI().toString());
    if (request instanceof HttpEntityEnclosingRequest) {
        HttpEntityEnclosingRequest entityRequest = (HttpEntityEnclosingRequest) request;
        if (entityRequest.getEntity() != null) {
            entityRequest.setEntity(new AopHttpRequestEntity(entityRequest.getEntity(), data));
        }
        return (HttpUriRequest) entityRequest;
    }
    return request;
}

从request获取URI,来设置data中URL。如果request的类型不是HttpEntityEnclosingRequest,直接就把request返回。如果是HttpEntityEnclosingRequest,先转换为HttpEntityEnclosingRequest类型,转换后的结果保存在HttpEntityEnclosingRequest,通过原始的Entity和data生成一个新的AopHttpRequestEntity,作为entityRequest的新的entity。对于handleRequest方法,这个data还只是一个新生成的空的NetInfo对象。通过handleRequest方法得到一个新的HttpUriRequest以后,httpClient.execute执行这个请求,这一方面会得到请求响应response,接下来handleResponse(response, data)对响应数据处理。

private static HttpResponse handleResponse(HttpResponse response, NetInfo data) {
    data.setStatusCode(response.getStatusLine().getStatusCode());
    Header[] headers = response.getHeaders("Content-Length");
    if ((headers != null) && (headers.length > 0)) {
        try {
            long l = Long.parseLong(headers[0].getValue());
            data.setReceivedBytes(l);
            if (DEBUG) {
                LogX.d(TAG, SUB_TAG, "-handleResponse--end--1");
            }
            data.end();
        } catch (NumberFormatException e) {
            if (Env.DEBUG) {
                LogX.d(TAG, SUB_TAG, "NumberFormatException ex : " + e.getMessage());
            }
        }
    } else if (response.getEntity() != null) {
        response.setEntity(new AopHttpResponseEntity(response.getEntity(), data));
    } else {
        data.setReceivedBytes(0);
        if (DEBUG) {
            LogX.d(TAG, SUB_TAG, "----handleResponse--end--2");
        }
        data.end();
    }
    if (DEBUG) {
        LogX.d(TAG, SUB_TAG, "execute:" + data.toString());
    }
    return response;
}

代码比较简单明显。从返回的信息中解析返回码设置到data中。如果首部非空并且长度大于0,从首部中解析接收字节数,设置到data中;或者,response的entity不空,通过response的entity和data生成一个新的AopHttpResponseEntity,作为response的新的entity;如果以上两个条件都不满足,就把data中的接收字节数设置为0。
此时,我们会比较好奇,data中的数据,到底是在什么时候设置的呢?实际上,AopHttpResponseEntity扩展自AopHttpEntity,而AopHttpEntity实现了HttpEntity, IStreamCompleteListener两个接口,通过实现接口中的writeTo,onOutputstreamComplete,onOutputstreamError,onInputstreamComplete,onInputstreamError,会写入接收字节数。同样的,AopHttpRequestEntity也继承自AopHttpEntity,重载的以上几个方法会写入发送字节数到data中。

回到TraceNetTrafficMonitor类,后面的方法和前面类似,只是针对不同函数调用设置切点。

360ArgusAPM:奇虎360 Argus APM android sdk源代码解读 360ArgusAPM 奇虎360 Argus APM android sdk源代码解读 立即下载

相关推荐

(完整版)从零开始教你玩转ComfyUI-保姆级部署教程-手把手带你ComfyUI工作流搭建

ComfyUI就像拥有一支神奇魔杖,可以轻松创造出令人惊叹的AI生成艺术。从本质上讲,ComfyUI是构建在Stable Diffusion之上的基于节点的图形用户界面(GUI),而Stable Diffusion是一种最先进的深度学习模型,可以根据文本描述生成图像。但ComfyUI真正特别之处在于,它如何让像你这样的艺术家释放创造力,将你最疯狂的想法变为现实。想象一下有一块数字画布,你可以通过连接不同的节点来构建自己独特的图像生成工作流,每个节点代表一个特定的功能或操作。

php源码 4万+

360Apm源码解析

360Apm 是什么? 如何收集卡顿(block)信息? 如何收集Okhttp信息? 如何收集帧(fps)信息? 如果收集Activity信息? 如果收集内存信息? 开源框架学习总结: 1.学到一些新的思路。 2.学到一些新的设计模式。 3.扩展知识面 4.学以致用,自己以后有其他的想法,会这个技术,就可以写开源框架。 ...

男儿不展风云志,空有天生八尺躯 1296

AI+AB测试提升电商主图点击率实战指南

在电商运营中,主图点击率(CTR)是衡量商品吸引力的核心指标,直接影响转化率和订单增长。通过AI技术批量生成高质量主图素材,结合数据驱动的AB测试方法,可以显著提升点击率。AI工具如MidJourney和Stable Diffusion能够快速生成多样化视觉方案,而自动化处理流水线则确保素材规格统一。AB测试体系通过多维变量控制和流量分配策略,科学验证不同素材效果。这种方法特别适用于需要快速迭代的电商场景,某女装店铺案例显示CTR从1.2%提升至3.8%,验证了AI+数据协同优化的技术价值。

weixin_29058331的博客 298

360 Argus APM 源码分析(2)—— argus-apm-gradle源码分析

argus-apm-gradle源码分析 argus-apm-gradle工程定义了一个gradle plugin,主要有以下两个作用: 支持AOP编程,方便ArgusAPM能够在编译期织入一些性能采集的代码; 通过Gradle插件来管理依赖库,使用户接入ArgusAPM更简单。 argus-apm-gradle使用kotlin语言开发。这里我们假定大家已经熟悉gradle plugin的开发...

hunter800421的专栏 1630

OpenMV模块视觉测距(避障)+颜色识别+TFT-LCD显示(实现原理与代码分析)

上图所示代码实际运行的帧率比较低,主要原因有以下两个:1.硬件问题,博主使用的版本比较低,可以尝试使用高版本OpenMV2.图像滤波问题。之前加入图像滤波是想提高色块识别的准确性,但是相应的运算速度也会下降。

ediykk的博客 1万+

中国裁判文书网案例批量爬取

本文介绍了某法院网站数据采集的技术研究过程,主要包含JS逆向分析和数据解密方法。通过开发者工具分析发现页面数据经过加密处理,重点研究了ciphertext等加密参数的生成逻辑。文章详细记录了定位加密函数、扣取加密代码、解密数据处理的全流程,并验证了解密方法的有效性。研究过程中强调了技术使用的法律边界,明确声明仅用于合法技术研究,禁止任何非法数据爬取行为。最终实现了加密数据的成功解密,并解释了各请求参数的作用,为后续数据清洗和存储奠定了基础。

2303_80825459的博客 816

360 apm框架Argus源码解析(1)——开始

开始 先看一个简单的代码示例,演示如何集成360 Argus APM: public class ArgusAPMApplication extends Application { @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); ...

hunter800421的专栏 1373

STP生成树/BPDU保护小实验

HCIA部分—STP生成树小实验 实验环境如图所示,要求: 1.在SW1上配置为根桥,使SW3的G0/0/1口作为根端口 2.在SW1的G0/0/3配置为边缘端口 3.若在SW1的G0/0/3口收到BPDU,能自动关闭该端口 4.通过配置bpdu保护,使端口能自动恢复up状态 首先,我们可以通过命令dis stp brief或者dis stp命令来得知SW1在生成树中的角色 确认SW1为非根交换机,此时可以通过修改stp优先级来让SW1成为根桥: 优先级数值缺省为32768,数值越小,优先级越高,数值

1mih的博客 5149

ArgusAPM 源码解析与学习

ArgusAPM 移动性能监控平台是 360 开源的一款 APM 监测工具。 目前已经停止免费的服务端接入,但是对于我们从客户端的角度来搭建 监测还是有不错的学习参照意义。目前支持如下性能指标:本文也将围绕 总体框架和支持的功能点进行分析。项目分为三个目录,分别是:工程定义了一个名为 的 ,主要有以下两个作用:关于实现一个 的过程这里就不赘述了,下面看一下整体的框架。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vt1jfbtf-1655453421261)(https:/

m0_56255097的博客 919

.NET适配HarmonyOS进展 1. 前言

目前国产化系统浪潮下,适配鸿蒙是中国软件大势所趋,.NET作为最适合开发客户端语言之一,适配鸿蒙系统(HarmonyOS Next)是目前.NET开发者最关心的事情。我目前业余时间正在移植Avalonia到HarmonyOS,去年在.NET Conf CN上分享过,目前又取得一点进展,所以本文把所有问题进行整合与大家进行分享。

2301_76476890的博客 1461

SAP 人力资源工资配置项3---工资项配置

工资项设置

xiouluoyang的专栏 1万+

Argus DBM 一款开源的数据库监控工具,无需部署Agent

Argus目前支持对Mysql, PostgreSQL, Oracle等数据库类型的监控,我们也会尽快适配其它数据库,致力于监控所有数据库。我们提供了更自由化的阈值告警配置,支持邮箱,短信,webhook,钉钉,企业微信,飞书机器人等告警通知。ArgusDBM 支持通过源码安装启动,Docker容器运行和安装包方式安装部署,CPU架构支持X86/ARM64。无需部署Agent,开箱即用。我们使用JDBC直连您的数据库,输入IP端口账户密码即可。更多配置详细步骤参考。更多配置详细步骤参考。

xianjie0318的博客 1387

YOLOv8改进:在C2F模块中引入RepGhost Bottleneck模块

C2F类是YOLOv8中的C2F模块的实现,它包含一个RepGhostBottleneck模块、一个卷积层和一个批归一化层。通过在C2F模块中引入RepGhost Bottleneck模块,我们可以在保持计算效率的同时提升模型的表达能力。这是因为RepGhost Bottleneck模块通过引入重复的卷积核来扩展模型的感受野,从而增加了模型对不同尺度目标的感知能力。RepGhost Bottleneck是一种用于卷积神经网络的改进模块,它可以在保持计算效率的同时提升模型的表达能力。希望以上内容对你有帮助!

IlgCrystal的博客 1306

360 Argus APM 源码分析(4)—— argus-apm-okhttp源码分析

argus-apm-okhttp源码分析 OkHttp3Aspect类 OkHttp3Aspect类是OKHTTP3的切面文件。 @Aspect public class OkHttp3Aspect { @Pointcut("call(public okhttp3.OkHttpClient build())") public void build() { } ...

hunter800421的专栏 632

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

卡顿监测 · 方案篇 · Android卡顿监测指导原则

“ 友链: BaguTree《Android 面试、卡顿、ANR》分享 Tips: 关注微信公众号 小木箱成长营,回复 "卡顿监测" 可获得卡顿监测免费思维导图 ” 一、引言 Hello,我是小木箱,欢迎来到小木箱成长营系列教程,今天将分享卡顿监测 · 方案篇 · Android 卡顿监测指导原则。小木箱从七个维度将 Android 卡顿监测技术方案解释清楚。 第一个维度是卡顿定义,第二个维度是卡顿原因,第三个维度是业界方案,第四个维度是相关预研,第五个维度是分析工具,第六个维度是卡顿指标,第七个维度是监测

Kibaco的博客 1137

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

ArgusAPM 开源项目指南

**ArgusAPM** 是由360手机卫士团队开发的移动端性能监控平台,旨在帮助开发者实时监测和诊断应用程序的性能问题。这个开源项目是非侵入式的,允许开发者在不改变原有工程结构的情况下轻松接入,其特性包括UI性能、网络性能、内存、进程、文件、卡顿和ANR等多维度的监控,以提升用户体验。 ### 主要特点 - **非侵入式**:无须修改代码,低接入成本。 - **无性能损耗**:优化采集机制,...

gitblog_00233的博客 991

探索高效性能监控:ArgusAPM移动性能监控平台

在移动应用的开发与维护过程中,性能问题往往是影响用户体验的关键因素。360公司推出的ArgusAPM移动性能监控平台,正是为了解决这一痛点而生。本文将深入介绍ArgusAPM的核心功能、技术架构及其应用场景,帮助开发者更好地理解和利用这一强大的工具。 ## 项目介绍 ArgusAPM是360手机卫士客户端团队继RePlugin之后推出的又一开源力作。作为一个移动端产品的可视化性能监控平台,Ar...

gitblog_00026的博客 1155

推荐:ArgusAPM - 移动性能监控的强大工具

ArgusAPM是由360手机卫士团队倾力打造的一款强大的移动性能监控平台,旨在协助开发者实时监测和管理APP性能,以提高用户的使用体验。这个开源项目已经在多个360产品中得到成功应用,包括手机卫士、清理大师等,现面向全球开发者开放。 ## 项目技术分析 ### 非侵入式设计 ArgusAPM的非侵入式设计允许您无需改动现有代码结构即可轻松接入,极大地降低了接入成本。 ### AOP与Gr...

gitblog_00072的博客 592

360重磅开源性能监控平台ArgusAPM

12月16日,在360移动性能开放日上,360手机卫士技术架构负责人卜云涛向我们介绍了360最新开源的性能监控平台ArgusAPM。ArgusAPM是360手机卫士客户端团队继RePlugin之后开源的又一个重量级开源项目。ArgusAPM是360移动端产品使用的可视化性能监控平台,为移动端APP提供性能监控与管理,可以迅速发现和定位各类APP性能和使用问题,帮助APP不断的提升用户体验。GitH...

cpongo5 1018

360 重磅开源性能监控平台 ArgusAPM

12 月 16 日,在 360 移动性能开放日上,360 手机卫士技术架构负责人卜云涛向我们介绍了 360 最新开源的性能监控平台 ArgusAPM。ArgusAPM 是 360 手机卫士客户端团队继 RePlugin 之后开源的又一个重量级开源项目。ArgusAPM 是 360 移动端产品使用的可视化性能监控平台,为移动端 APP 提供性能监控与管理,可以迅速发现和定位各类 APP 性能和使用问...

weixin_33816821的博客 693

360移动技术开放日 聚焦移动前沿技术(有福利)

在手机已经成为我们时刻离不开的生活必需品的今天,移动开发技术变得尤为重要。360移动端可视化的性能监控平台——Argus APM如何帮App提升性能及用户体验?Andro...

HULK一线技术杂谈 526

argus-apm-main中的task(2) —— Activity Task

argus-apm-main中的task(2) —— Activity Task Activity Task实现对Activity的性能监控。我们在“开始”一篇里提到过,Activity的性能采集实现方式有两种,Instrumentation和AOP,而ActivitTask的start方法主要就做了一个判断:如果使能了ApmTask.FLAG_COLLECT_ACTIVITY_INSTRUMEN...

hunter800421的专栏 471

360移动端性能监控实践QDAS-APM(iOS篇)

一、背景 360是一家注重用户体验的公司,公司的口号是用户至上。在这么一个注重用户体验的氛围里,app的性能问题无疑是被重点关注的,同样也是造成用户流失的罪魁祸首之一。性能问题主要包含:崩溃、网络请求错误或者超时、UI响应速度慢、主线程卡顿、CPU和内存使用高、耗电量大等等。大多问题的原因在于开发者错误地使用了线程、锁、系统函数、编程规范问题、数据结构等等。解决这个问题的关键在于尽早发现和定位问题...

360技术 3484

POJ 2051 Argus

Description A data stream is a real-time, continuous, ordered sequence of items. Some examples include sensor data, Internet traffic, financial tickers, on-line auctions, and transaction logs such as ...

zhaohaibo的博客 375

argus-apm-main中的task(1) —— FpsTask

argus-apm-main中的task(1) —— FpsTask argus-apm-main中定义和实现了各个具体的监控task,包括Activity,网络,fps等等。这里我们先从fps作为例子入手分析。 FpsTask类 FpsTask类定义了fps监控的task,相当于是fps task的入口。先来看一下这个类的代码。 public class FpsTask extends Base...

hunter800421的专栏 455

Android Camera2 拍照(三)——切换摄像头,延时拍摄和闪光模式

一、切换摄像头 在前后摄像头之间切换,首先需要关闭之前打开的摄像头,关闭preview,之后重新打开新的摄像头,重新打开preview。 public void switchCamera() { if (mCameraId.equals(CAMERA_FRONT)) { mCameraId = CAMERA_BACK; close

hunter800421的专栏 1万+
上一篇: Android多媒体框架(7)—— stagefright中MediaMuxer源码分析
下一篇: 360 Argus APM 源码分析(4)—— argus-apm-okhttp源码分析
hunter800421
博客等级 码龄22年 60粉丝 97原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值