美文网首页
BlockCanary分析实现原理

BlockCanary分析实现原理

作者: only_run | 来源:发表于2019-12-30 17:33 被阅读0次

介绍

BlockCanary 一个android UI检测工具,追踪view耗时操作;
附上地址:
https://github.com/markzhai/AndroidPerformanceMonitor
http://blog.zhaiyifan.cn/2016/01/16/BlockCanaryTransparentPerformanceMonitor/

核心代码

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

监听loop处理事件

原来是监听主线程的 loop事件;看下怎样监听的

 public static void loop() {
      //...
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // This must be in a local variable, in case a UI event sets the logger
            final Printer logging = me.mLogging;
            if (logging != null) {//1
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }
        //...
            try {
                msg.target.dispatchMessage(msg);//2
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
         //..

            if (logging != null) {//3
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }
  //...
        }
    }

原来主线程的消息队列抽取消息 去处理的前后,注释1,注释2 都会执行 logging的日志打印;而logging正是 BlockCanary传入的,实现类是
LooperMonitor;

class LooperMonitor implements Printer {
 @Override
    public void println(String x) {
        if (mStopWhenDebugging && Debug.isDebuggerConnected()) {
            return;
        }
        if (!mPrintingStarted) {//1
            mStartTimestamp = System.currentTimeMillis();
            mStartThreadTimestamp = SystemClock.currentThreadTimeMillis();
            mPrintingStarted = true;
            startDump();
        } else {//2
            final long endTime = System.currentTimeMillis();
            mPrintingStarted = false;
            if (isBlock(endTime)) {//3
                notifyBlockEvent(endTime);
            }
            stopDump();
        }
    }
  
    private boolean isBlock(long endTime) {
        return endTime - mStartTimestamp > mBlockThresholdMillis;
    }
}

注释1 记录当前时间和开始标记,代码执行到注释2的时候,自然是要记录结束时间;
执行注释3 判断handler的消息处理是否 超过阀值,如果超出 就给出ui卡顿提示 以及方法调用(stacktrace)和cpu使用信息,来帮助开发者 即使发现ui卡顿问题;

BlockCanary如何读取stacktrace和cpu使用信息

BlockCanary 有两个采样器,StackSampler和CpuSampler;
handler开始处理消息时,执行startDump;采样器开始工作
handler开始处理结束时,执行stopDumo;采样器结束工作

在handle开始处理信息时,使用Stack采样器获取方法调用信息 使用Cpu采样器获取Cpu使用信息;
在handle处理信息完毕时,采样器结束读取。
这样就获取到了handler处理消息过程中的 方法调用信息和cpu使用信息;

附StackSampler,CpuSampler 部分代码

class StackSampler extends AbstractSampler {
   @Override
    protected void doSample() {
        StringBuilder stringBuilder = new StringBuilder();

        for (StackTraceElement stackTraceElement : mCurrentThread.getStackTrace()) {
            stringBuilder
                    .append(stackTraceElement.toString())
                    .append(BlockInfo.SEPARATOR);
        }

        synchronized (sStackMap) {
            if (sStackMap.size() == mMaxEntryCount && mMaxEntryCount > 0) {
                sStackMap.remove(sStackMap.keySet().iterator().next());
            }
            sStackMap.put(System.currentTimeMillis(), stringBuilder.toString());
        }
    }
}

class CpuSampler extends AbstractSampler {
    @Override
    protected void doSample() {
        BufferedReader cpuReader = null;
        BufferedReader pidReader = null;

        try {
            cpuReader = new BufferedReader(new InputStreamReader(
                    new FileInputStream("/proc/stat")), BUFFER_SIZE);
            String cpuRate = cpuReader.readLine();
            if (cpuRate == null) {
                cpuRate = "";
            }

            if (mPid == 0) {
                mPid = android.os.Process.myPid();
            }
            pidReader = new BufferedReader(new InputStreamReader(
                    new FileInputStream("/proc/" + mPid + "/stat")), BUFFER_SIZE);
            String pidCpuRate = pidReader.readLine();
            if (pidCpuRate == null) {
                pidCpuRate = "";
            }

            parse(cpuRate, pidCpuRate);
        } catch (Throwable throwable) {
            Log.e(TAG, "doSample: ", throwable);
        } finally {
            try {
                if (cpuReader != null) {
                    cpuReader.close();
                }
                if (pidReader != null) {
                    pidReader.close();
                }
            } catch (IOException exception) {
                Log.e(TAG, "doSample: ", exception);
            }
        }
    }
}

StackSampler和CpuSampler都有一个HandlerThread对象,用来在各自的子线程中 间隔性的启动任务;来读取 主线程方法调用和cpu使用信息。

相关文章

  • BlockCanary分析实现原理

    介绍 BlockCanary 一个android UI检测工具,追踪view耗时操作;附上地址:https://g...

  • 无标题文章

    APP性能优化 UI卡顿优化 View的绘制原理 UI卡顿原理分析 UI卡顿检测分析 BlockCanary原理分...

  • BlockCanary原理分析

    概述 BlockCanary是Android平台上的一个轻量的,非侵入式的性能监控组件,可以在使用应用的时候检测主...

  • BlockCanary的实现原理和源码分析

    BlockCanary源码地址 简单使用 实现BlockCanaryContext, 重写provideBlock...

  • blockCanary原理

    blockCanary 对于android里面的性能优化,最主要的问题就是UI线程的阻塞导致的,对于如何准确的计算...

  • BlockCanary原理

    我们都知道Android应用程序只有一个主线程ActivityThread,这个主线程会创建一个Looper(Lo...

  • 性能优化(7.3)-BlockCanary原理分析

    主目录见:Android高级进阶知识(这是总目录索引)[written by 无心追求] BlockCanary...

  • BlockCanary,LeakCanary原理

    BlockCanary 简介github地址,一款用来检测页面卡顿的非侵入式插件使用 然后在Application...

  • java8中hashset源码分析

    分析大纲 hashset实现原理 hashset代码分析 1. hashset实现原理 hashset存储无序,不...

  • BlockCanary源码笔记

    BlockCanary 核心原理离不开主线程ActivityThread,用到了Handler,Looper;在L...

网友评论

      本文标题:BlockCanary分析实现原理

      本文链接:https://www.haomeiwen.com/subject/icumoctx.html