推广

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

iseeyu2年前 (2024-02-22)推广123

流程图

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

相关文章

软文推广怎么做,读懂让你少走弯路

软文推广怎么做,读懂让你少走弯路

软文,当初是很多公司看不上的推广方式,为什么却又成为了最热门的推广方式,其实原因也简单,因为公司发展不是一两年,而推广也是一样,大多数的公司就是想着砸钱推广,只要不花钱,只要停下来,流量就没了,所以这是很多公司比较头疼的事情。而软文推广的优势则是前期坚持去做,后期就算不做推...

如何快速建立公司网站建设网站需要做些什么。

如何快速建立公司网站建设网站需要做些什么。

在互联网超级发展的时代,特别是中国互联网高速发生,比例互联网巨头公司---百度、腾讯、阿里巴巴、淘宝、京东等大型互联网技术科技企业,通过互联网为企业、客户、人民大众提供有价值的信息技术服务,知识科技等,而传统企业,如制造业、实体企业,研发产品科技的企业,如何让更多的人,企业公司知道,其中建设一个网站...

百度搜索引擎逐渐没落,现在SEO的出路在哪里?(百度搜索引擎添加)

百度搜索引擎逐渐没落,现在SEO的出路在哪里?(百度搜索引擎添加)

回答要求官方的二十赞,搜索引擎CEO是一个长期坚持的过程,其实简单来说也就是关键词排名的优化,可以规纳以下几点,1.首先做好自己网吧,关键词,只有关键词,一但选好自己网站的关键词,只有关键词选择合理,推广网站相意义,而且关键词一但选好最好不要更改,对网站影响很大,关键词最好选择选好五个词以内这样比较...

知乎机构号运营实战手册

知乎机构号运营实战手册

  去年写了知乎机构号运营实战1.0,分定位篇、选题篇、创作篇、SEO篇四部分,如今过去一年多时间,其中部分实战技巧有些过时,比如: 1.0的选题篇适用于大部分机构号的发展初期,也就是快速铺设关键词的阶段。但随着大部分关键词铺设完毕,机构号就会面临没有问题可答的尴尬。 同样...

淘宝客定向计划如何取消(怎么关闭淘宝客计划)

淘宝客定向计划如何取消(怎么关闭淘宝客计划)

打开http://ad.alimama.com/,登录账号,【进入我的淘宝客】,页面中下方找到【定向计划】点击右侧【查看】,找到对应计划在左侧将鼠标放置在【状态】标示中,选择【暂停】,将运行的计划先暂停,等计划暂停之后即可删除。...

百度营销“宝藏中国”落地河南,三大升级助力城市品牌升级

百度营销“宝藏中国”落地河南,三大升级助力城市品牌升级

恁弄啥嘞?中不中?得劲儿不?百度搜索大显示,河南话口头禅已经成为全国人民热搜关键词。如果不学上一两句你就Out了。河南话风靡全国的背后,不只是方言的逆袭,更是数千年中原积淀传承的体现。2021年5月17日,百度“宝藏中国”IP落地河南。百度移动生态矩阵打造的城市“宝藏河南”...

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

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