Android BlockCanary source parsing

BlockCanary What is
non-intrusive performance monitoring components

The role of BlockCanary
found UI Caton problem (ANR usually when we can get the information when the stack)

UI Caton principle
1.60fps ----> 16m / s frame
2. Try to ensure that each processed within 16m / s all the CPU and GPU computing drawing, rendering and other operations, otherwise it will cause frame loss problem Caton

The role of the main thread
1. The role of the main thread (after application startup, create a main thread is ActivityThread)
2. the event (click, touch, etc.) or sent to the appropriate View Widget
3. Application UI also interact with the application of The main thread

Processed common method in the sub-thread processing operations (consuming operations can not be processed in the main thread)
Handler
Activity.runOnUiThread (the Runnable)
View.post (the Runnable)
View.postDelayed (the Runnable, Long)

Common causes of UI Caton
1. consuming operations
2. Layout Layout too complex to be finished rendering within 16m / S
3.View excessive draw
4.View frequent trigger its measure, layout
5. memory too frequently trigger GC ( virtual machine in the implementation of garbage collection, all threads, including the UI thread will be suspended only if the GC garbage collection finished, all the threads before proceeding to work)

Look at [ActivityThread] (Android application has only one main thread is ActivityThread)
see Android source code Web site address

//创建一个Looper,Looper里又会关联消息队列MessageQueue
   final Looper mLooper = Looper.myLooper();
    public static void main(String[] args) {
               .
               .
               .
    //一个主线程创建MainLooper后,就会在我们的应用生命周期内,不断轮询,通过Looper.loop()方法,获取到消息队列中的Message,然后通知我们的主线程,去更新UI
   Looper.prepareMainLooper();  
    }

Look prepareMainLooper () method

public static void prepareMainLooper() {
 prepare(false);
 synchronized (Looper.class) {
   if (sMainLooper != null) {
    throw new IllegalStateException("The main Looper has already been prepared.");
     }
     //创建一个主线程的Looper(不管整个应用的主线程,它有多少个子线程,主线程中只有这一个Looper,不管有多少Hanlder,在其它地方可以创建Handler,最终会会到这个sMainLooper 上)
     sMainLooper = myLooper();
   }
  }

Look Looper.loop () method

//在msg.target.dispatchMessage(msg)方法上下方都有log输出,在dispatchMessage上下分别打印方法执行的时间,根据时间差,来判定dispatchMessage中有没有耗时操作,也就是dispatchMessage中,有没有UI卡顿,如果超过时间差的阈值,就要打印出信息,BlockCanary就是利了这个特点,这也是它的核心实现原理
public static void loop() {
             final Printer logging = me.mLogging;
            final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
                      final long dispatchEnd;
                       try {
                       //分发message,target就是Handler
                           msg.target.dispatchMessage(msg);
                           dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
                       } finally {
                           if (traceTag != 0) {
                               Trace.traceEnd(traceTag);
                           }
                       }
                       if (logSlowDelivery) {
                              if (slowDeliveryDetected) {
                                  if ((dispatchStart - msg.when) <= 10) {
                                      Slog.w(TAG, "Drained");
                                      slowDeliveryDetected = false;
                                  }
                              } else {
                                  if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
                                          msg)) {
                                      // Once we write a slow delivery log,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         suppress until the queue drains.
                                      slowDeliveryDetected = true;
                                 }
                              }
                          }
                          if (logSlowDispatch) {
                              showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
                          }
              
                       if (logging != null) {
                           logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);        .
                  
}

Look msg.target.dispatchMessage (msg) Method

//这都是执行在主线程中,如果产生了UI卡顿,必定是在这个方法当中
 public void dispatchMessage(Message msg) {
 //callback就是runnable
  if (msg.callback != null) {
  //handleCallback,就是把runnable放到方法中,调用它的run方法执行我们的子线程
   handleCallback(msg);
    } else {
    //相当于调用hanlder.sendMessage
     if (mCallback != null) {
         if (mCallback.handleMessage(msg)) {
          return;
            }    
          }
          //处理消息
           handleMessage(msg);
         }
       }

Look BlockCanary.install method

public static BlockCanary install(Context context, BlockCanaryContext blockCanaryContext) {
    //init方法就做了BlockCanaryContext的成员变量的赋值
    BlockCanaryContext.init(context, blockCanaryContext);
    //设置通知栏消息是否开启或关闭,BlockCanaryContext.get().displayNotification(),debug模式默开启(true),release默认关闭(false)
    setEnabled(context, DisplayActivity.class, BlockCanaryContext.get().displayNotification());
    return get();
}

Look get () method

 public static BlockCanary get() {
       //单例,生成BlockCanary的实例
        if (sInstance == null) {
            synchronized (BlockCanary.class) {
                if (sInstance == null) {
                    sInstance = new BlockCanary();
                }
            }
        }
        return sInstance;
    }

Constructors look BlockCanary

   private BlockCanary() {
        BlockCanaryInternals.setContext(BlockCanaryContext.get());
        //单例获取
        mBlockCanaryCore = BlockCanaryInternals.getInstance();
        mBlockCanaryCore.addBlockInterceptor(BlockCanaryContext.get());
        if (!BlockCanaryContext.get().displayNotification()) {
            return;
        }
        //通知展示
        mBlockCanaryCore.addBlockInterceptor(new DisplayService());

    }

The method of construction of a look BlockCanaryInternals

public BlockCanaryInternals() {
         //dump出线程的stack信息,传入的参数是主线程,第二个参数是Dump的间隔    
        stackSampler = new StackSampler(
                Looper.getMainLooper().getThread(),
                sContext.provideDumpInterval());
        //dump出cpu的有关情况
        cpuSampler = new CpuSampler(sContext.provideDumpInterval());
       //LooperMonitor是在dispatchMessage上下分别打印方法执行的时间
        setMonitor(new LooperMonitor(new LooperMonitor.BlockListener() {
            //主线程的调用栈,CPU的是使用情况,内存使用情况都会这个方法监听到,会回调
            @Override
            public void onBlockEvent(long realTimeStart, long realTimeEnd,
                                     long threadTimeStart, long threadTimeEnd) {
                // Get recent thread-stack entries and cpu usage
                ArrayList<String> threadStackEntries = stackSampler
                        .getThreadStackEntries(realTimeStart, realTimeEnd);
                if (!threadStackEntries.isEmpty()) {
                    BlockInfo blockInfo = BlockInfo.newInstance()
                            .setMainThreadTimeCost(realTimeStart, realTimeEnd, threadTimeStart, threadTimeEnd)
                            .setCpuBusyFlag(cpuSampler.isCpuBusy(realTimeStart, realTimeEnd))
                            .setRecentCpuRate(cpuSampler.getCpuRateInfo())
                            .setThreadStackEntries(threadStackEntries)
                            .flushString();
                    LogWriter.save(blockInfo.toString());

                    if (mInterceptorChain.size() != 0) {
                        for (BlockInterceptor interceptor : mInterceptorChain) {
                            interceptor.onBlock(getContext().provideContext(), blockInfo);
                        }
                    }
                }
            }
        }, getContext().provideBlockThreshold(), getContext().stopWhenDebugging()));
       //就是用来删除日志用的,因为在BlockCanary当中,默认情况下日志会保存两天,需要定期的删除  
        LogWriter.cleanObsolete();
    }

Look start () method

  public void start() {
        if (!mMonitorStarted) {
            mMonitorStarted = true;
// Looper.getMainLooper()得到主线程Looper,调用setMessageLogging打印时间           Looper.getMainLooper().setMessageLogging(mBlockCanaryCore.monitor);
        }
    }

Look LooperMonitor of println (String x) method

//打印时间
  public void println(String x) {
        if (mStopWhenDebugging && Debug.isDebuggerConnected()) {
            return;
        }
        //表示是否在dispatchMessage方法前
        if (!mPrintingStarted) {
          //系统时间
            mStartTimestamp = System.currentTimeMillis();
            //当前线程运行状态的总时间(sleep和wait不会记录到时间里去)
            mStartThreadTimestamp = SystemClock.currentThreadTimeMillis();
            mPrintingStarted = true;
            startDump();
        } else {  //表示是否在dispatchMessage方法后
            final long endTime = System.currentTimeMillis();
            mPrintingStarted = false;
            //表示有卡顿,UI有阻塞
            if (isBlock(endTime)) {
                notifyBlockEvent(endTime);
            }
            stopDump();
        }
    }

Look startDump () method

  private void startDump() {
        if (null != BlockCanaryInternals.getInstance().stackSampler) {
            BlockCanaryInternals.getInstance().stackSampler.start();
        }

        if (null != BlockCanaryInternals.getInstance().cpuSampler) {
            BlockCanaryInternals.getInstance().cpuSampler.start();
        }
    }

Look BlockCanaryInternals.getInstance (). StackSampler.start () method

  public void start() {
        if (mShouldSample.get()) {
            return;
        }
        mShouldSample.set(true);

        HandlerThreadFactory.getTimerThreadHandler().removeCallbacks(mRunnable);
        HandlerThreadFactory.getTimerThreadHandler().postDelayed(mRunnable,
                BlockCanaryInternals.getInstance().getSampleDelay());
    }

Look mRunnable, in aabstract class AbstractSampler years, AbstractSampler is stackSampler and cpuSampler abstract class

  private Runnable mRunnable = new Runnable() {
        @Override
        public void run() {
            doSample();

            if (mShouldSample.get()) {
                HandlerThreadFactory.getTimerThreadHandler()
                        .postDelayed(mRunnable, mSampleInterval);
            }
        }
    };

Implement look doSample () abstract method of StackSampler

p

//打印栈的信息
rotected void doSample() {
        StringBuilder stringBuilder = new StringBuilder();
//mCurrentThread.getStackTrace()获取到当前线程的调用栈,mCurrentThread是主线程,因为前面调用的是getMainLooper
        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());
            }
            //以当前时间为Key,放入到HashMap中,sStackMap是LinkedHashMap,这里为什么要定义为LinkedHashMap,LinkedHashMap会记录插入的键的顺序,所以遍历的时候是按插入顺序的,普通的HashMap无法做到,所以遍历顺序未知
            sStackMap.put(System.currentTimeMillis(), stringBuilder.toString());
        }
    }

Implement look doSample () abstract method of CpuSampler

@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 = "";
        }
                     .
                     .
                     .               
       
    } } catch (Throwable throwable) {}
    }

Look isBlock (endTime) Method

  private boolean isBlock(long endTime) {
  //endTime是dispatchMessage后的时间,mStartTimestamp 是dispatchMessage前的时间,mBlockThresholdMillis时间为3000,如果大于就表示产生卡顿了,UI阻塞了
        return endTime - mStartTimestamp > mBlockThresholdMillis;
    }

Look notifyBlockEvent (endTime) Method

  private void notifyBlockEvent(final long endTime) {
        final long startTime = mStartTimestamp;
        final long startThreadTime = mStartThreadTimestamp;
        final long endThreadTime = SystemClock.currentThreadTimeMillis();
        HandlerThreadFactory.getWriteLogThreadHandler().post(new Runnable() {
            @Override
            public void run() {
            //调用前面所说的监听事件
                mBlockListener.onBlockEvent(startTime, endTime, startThreadTime, endThreadTime);
            }
        });
    }
Published 70 original articles · won praise 13 · views 50000 +

Guess you like

Origin blog.csdn.net/sunshine_0707/article/details/104463613