推广

APP卡顿检测工具 BlockCanary——使用和原理

iseeyu3年前 (2024-02-22)推广130

流程图

BlockCanary启动一个线程负责保存UI线程当前堆栈信息,将堆栈信息以及CPU信息保存分别保存在 mThreadStackEntries和mCpuInfoEntries中,每条信息都以时间撮为key保存。

BlockCanary注册了logging来获取事件开始结束时间。如果检测到事件处理时间超过阈值(默认值1s),则从mThreadStackEntries中查找T1T2这段时间内的堆栈信息,并且从mCpuInfoEntries中查找T1T2这段时间内的CPU及内存信息。并且将信息格式化后保存到本地文件,并且通知用户。
该组件利用了主线程的消息队列处理机制,通过

Looper.getMainLooper().setMessageLogging(mainLooperPrinter);

并在mainLooperPrinter中判断start和end,来获取主线程dispatch该message的开始和结束时间,并判定该时间超过阈值(如2000毫秒)为主线程卡慢发生,并dump出各种信息,提供开发者分析性能瓶颈。

...
@Override
public void println(String x) {
    if (!mStartedPrinting) {
        mStartTimeMillis = System.currentTimeMillis();
        mStartThreadTimeMillis = SystemClock.currentThreadTimeMillis();
        mStartedPrinting = true;
    } else {
        final long endTime = System.currentTimeMillis();
        mStartedPrinting = false;
        if (isBlock(endTime)) {
            notifyBlockEvent(endTime);
        }
    }
}

private boolean isBlock(long endTime) {
    return endTime - mStartTimeMillis > mBlockThresholdMillis;
}
...

四、源码解读

 BlockCanary.install(this, new AppBlockContext()).start();

首先我们看看他的入口,install这个方法:

 /**
     * Install {@link BlockCanary}
     *
     * @param context            Application context
     * @param blockCanaryContext BlockCanary context
     * @return {@link BlockCanary}
     */
    public static BlockCanary install(Context context, BlockCanaryContext blockCanaryContext) {
        BlockCanaryContext.init(context, blockCanaryContext);
        setEnabled(context, DisplayActivity.class, BlockCanaryContext.get().displayNotification());
        return get();
    }

这里调用三行代码:

  • 调用init()方法, 记录ApplicationBlockCanaryContext, 为后面的处理提供上下文Context和配置参数(例如: 卡顿阈值,是否显示通知 等等…)
  • 调用setEnabled()方法, 判断桌面是否显示黄色的logo图标
  • 调用get()方法, 创建BlockCanary的实例,并且创建BlockCanaryInternals实例, 赋值给mBlockCanaryCore属性, 用来处理后面的流程
static void init(Context context, BlockCanaryContext blockCanaryContext) {
        sApplicationContext = context;
        sInstance = blockCanaryContext;
    }

这个init方法就做了一个赋值的操作,将我们传递过来的context进行赋值。

我们继续看BlockCanary.start()做了什么事:

public void start() {
    if (!mMonitorStarted) {
        mMonitorStarted = true;
        Looper.getMainLooper().setMessageLogging(mBlockCanaryCore.monitor);
    }
}

start()方法只做了一件事: 给Looper设置一个Printer

那么当Looper处理消息的前后, 就会调用mBlockCanaryCore.monitor的println()方法。

mBlockCanaryCore.monitor是BlockCanaryInternals的成员属性LooperMonitor

class LooperMonitor implements Printer {
    ...
    @Override
    public void println(String x) {
        //如果StopWhenDebugging, 就不检测
        if (mStopWhenDebugging && Debug.isDebuggerConnected()) {
            return;
        }
        if (!mPrintingStarted) {
            mStartTimestamp = System.currentTimeMillis();
            mStartThreadTimestamp = SystemClock.currentThreadTimeMillis();
            mPrintingStarted = true;
            startDump();  //在子线程中获取调用栈和CPU信息
        } else {
            final long endTime = System.currentTimeMillis();
            mPrintingStarted = false;
            if (isBlock(endTime)) {  //判断是否超过设置的阈值
                notifyBlockEvent(endTime);
            }
            stopDump(); //停止获取调用栈和CPU信息
        }
    }
    //判断是否超过设置的阈值
    private boolean isBlock(long endTime) {
        return endTime - mStartTimestamp > mBlockThresholdMillis;
    }
    ...
}

LooperMonitor的println()就是最核心的地方, 实现代码也很简单:

  • Looper处理消息前, 获取当前时间并且保存, 调用startDump()启动一个任务定时去采集 调用栈/CPU 等等信息
  • Looper处理消息完成, 获取当前时间, 判断是否超过我们自定义的阈值isBlock(endTime)如果超过了, 就调用notifyBlockEvent(endTime)来通知处理后面的流程
  • 调用stopDump()停止获取调用栈以及CPU的任务

startDump采集的信息包括:

  • 基本信息:机型, CPU内核数, 进程名, 内存, 版本号 等等
  • 耗时信息:实际耗时, 主线程时钟耗时, 卡顿开始时间和结束时间
  • CPU信息:时间段内CPU是否忙, 时间段内的系统CPU/应用CPU占比, I/O占- – CPU使用率
  • 堆栈信息:发生卡顿前的最近堆栈

五、总结

blockcanary完美利用了安卓上的消息机制,给Looper设置一个Printer,通过记录堆栈和CPU信息,计算主线程处理消息的时间,如果超过了阈值,就检索此时的堆栈和cpu信息来帮助分析卡顿原因。

BlockCanary — 轻松找出Android App界面卡顿元凶
GitHub:BlockCanary

扫描二维码推送至手机访问。

版权声明:本文由西安泽虎代运营发布,如需转载请注明出处。

转载请注明出处https://www.0291.com.cn/post/56429.html

相关文章

传统文化与销售技巧:读冯木良《古典文学与现代营销策略》有感1

传统文化与销售技巧:读冯木良《古典文学与现代营销策略》有感1

待人真诚是传统的精髓,也是现代致胜的法宝。庄子曰:不精不诚,不能动人。且看南宋爱国诗人陆游悼念前妻唐琬的《沈园二首》:①城上斜阳画角哀,沈园非复旧池台。伤心桥下春波绿,曾是惊鸿照影来。②梦断香消四十年,沈园柳老不吹绵。此身行作稽山土,犹吊遗踪一泫然。陆游与表妹自由恋爱,却却...

小编教你21世纪,最大的财富是网络推广。

小编教你21世纪,最大的财富是网络推广。

比尔盖茨说:“21世纪,谁掌握了信息,谁就掌握了。”所以,在如今这个信息高度升值的时代里,互联网成为信息传播最有效的途径,也成为企业宣传产品或服务的最好渠道。作为将已掌握信息推销出去的一种手段,在信息社会中逐渐占据主导地位。但是大家在利用互联网进行推广时,却必须要掌握一些技巧。比如: 1...

财富篇——资源整合

财富篇——资源整合

什么是资源整合?资源整合指的是系统论的方式。就是要通过组织和协调,把彼此相关但却彼此分离的东西整合起来,整合就是要优化资源配置,就是要有进有退、有取有舍,就是要获得整体的最优。 一、资源整合定义整合就是把一些零散的东西通过某种方式而彼此衔接...

教你网络推广对企业有哪些意义(企业网络推广可以选择哪些方法)

教你网络推广对企业有哪些意义(企业网络推广可以选择哪些方法)

随着互联网用户的日益增多,网络涉及到人们日常生活的方方面面。互联网用户的增多,为企业的网络营销提供了基础,是网络营销的主要手段,对企业的长远发展有着重要的。那么,网络推广对企业有哪些意义呢?网络推广专家接下来为大家进行介绍。 1.传播范围广 网络推广的传播它不受时间和空间的限制,它通过...

企业从事网站SEO优化需要知道的小技巧。

企业从事网站SEO优化需要知道的小技巧。

企业做SEO优化关键就是说做关键字优化,要是把关键字的排名送上去就是说SEO优化的总体目标,关键字深圳市SEO优化的方式有许多,下边就给大伙儿详细介绍一下下SEO关键词优化的方式。 企业网站建设 一、关键字排名 通常状况下,低指数值的关键字非常容易优化,通常长尾关键词重要关词指数值都稍低,优化...

用好这一个小妙招,可以很轻松让你的销售业绩翻番!

用好这一个小妙招,可以很轻松让你的销售业绩翻番!

很多粉丝经常问我一些关于成交率的问题,比如,在成交的时候,怎么样才能让我们的成交率更高呢?那么,我在这里跟你讲个故事,看完,你大概就知道怎么做了。美国篮球之神迈克尔·乔丹,相信大家都知道,NBA公认的篮球之神,可以这么说,到今天为止,他创造的很多记录,到现在,依旧还是没有人...

现在,非常期待与您的又一次邂逅

我们努力让每一部企业宣传片和抖音短视频成为商业大片