关于BlockCanary的源码分析
来源:互联网 发布:超级优化基因液txt网盘 编辑:程序博客网 时间:2024/05/19 06:38
关于BlockCanary的源码分析——Grass
如下是Looper的源码,应用不断地从MessageQueue中取出Message并执行。
for (;;) { Message msg = queue.next(); // might blockif (msg == null) { // No message indicates that the message queue is quitting. return;} Printer logging = me.mLogging;if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what);} msg.target.dispatchMessage(msg);if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);} msg.recycleUnchecked();}
在 msg.target.dispatchMessage(msg);的前后各有一次Log输出,dispatchMessage即处理一次消息,BlockCanary的原理就是计算消息处理前后的时间差,如果超出设定的阈值,则认为这是一个耗时操作。
BlockCanary.classpublic void start() { if (!mMonitorStarted) { mMonitorStarted = true; Looper.getMainLooper().setMessageLogging(mBlockCanaryCore.monitor); }}
将在BlockCanaryInternals中创建的LooperMonitor给主线程Looper的mLogging变量赋值。通过调用Looper.getMainLooper().setMessageLogging(mBlockCanaryCore.monitor);获取主线程dispatchmessage的开始和结束时间。其中,monitor变量的类型是LooperMonitor类,该类实现了Printer接口,主线程中所有的事件都会调用此方法;
@Overridepublic void println(String x) { if (mStopWhenDebugging && Debug.isDebuggerConnected()) { return; } if (!mPrintingStarted) { mStartTimestamp = System.currentTimeMillis(); mStartThreadTimestamp = SystemClock.currentThreadTimeMillis(); mPrintingStarted = true; startDump(); } else { final long endTime = System.currentTimeMillis(); mPrintingStarted = false; if (isBlock(endTime)) { notifyBlockEvent(endTime); } stopDump(); }}
开始会调用startDump方法开始收集信息,获取堆栈信息和CPU信息,事件结束时在 if(isBlock(endTime)) 中判断是否超过指定阻塞时间值,超过的话在notifyBlockEvent(endTime)中回调信息。而notifyBlockEvent中通过接口回调到BlockCanaryInternals类中。
public BlockCanaryInternals() {stackSampler = new StackSampler( Looper.getMainLooper().getThread(), sContext.provideDumpInterval());cpuSampler = new CpuSampler(sContext.provideDumpInterval());setMonitor(new LooperMonitor(new LooperMonitor.BlockListener() { @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())); LogWriter.cleanObsolete();}
BlockCanaryInternals类是事件处理事件超出设定阈值时的处理,其中的onBlockEvent方法对耗时情况进行赋值,包括方法总耗时,线程耗时,CPU是否忙,CPU占用率以及定位到具体的耗时代码行。
关于上面这段代码中的 stackSampler,是堆栈的采样,通过Main Looper获取到主线程Thread对象,调用Thread的getStackTrace方法即可获取到堆栈信息,以下是 StackSampler 中的代码:
public ArrayList<String> getThreadStackEntries(long startTime, long endTime) { ArrayList<String> result = new ArrayList<>(); synchronized (sStackMap) { for (Long entryTime : sStackMap.keySet()) { if (startTime < entryTime && entryTime < endTime) { result.add(BlockInfo.TIME_FORMATTER.format(entryTime) + BlockInfo.SEPARATOR + BlockInfo.SEPARATOR + sStackMap.get(entryTime)); } } } return result;}@Overrideprotected 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()); }}
堆栈中耗时的代码保存在ArrayList中,堆栈则通过append拼接保存在LinkedHashMap中。
- 关于BlockCanary的源码分析
- BlockCanary源码分析
- BlockCanary源码分析
- Android-BlockCanary框架源码分析
- [源码]BlockCanary学习笔记
- 学习BlockCanary的实现
- BlockCanary分析android卡顿
- BlockCanary分析android卡顿
- BlockCanary
- BlockCanary
- 关于HashMap的源码分析
- 关于netty源码的分析
- 关于RxJava源码的分析
- 关于vector的一点源码分析
- 关于这个android源码分析的博客
- live555源码分析----关于mp3的处理
- nginx关于域名解析的源码分析
- live555源码分析----关于mp3的处理
- 解决AndroidCamera2官方Demo的bug
- Fiddler 使用
- 封装OkHttp3
- 《Java 编程技巧1001条》 第383条 了解数组的引用,
- 【bzoj1176】[Balkan2007]Mokia
- 关于BlockCanary的源码分析
- python17-12-21-
- C-COT目标跟踪代码下载运行
- python安装后无scripts内文件,无法使用pip
- video播放器
- (3)mysql index
- eclipse activiti插件安装办法
- 腾讯首席工程师:程序员成长之道
- 浅谈Java内存模型、并发、多线程