BlockCanary
核心原理离不开主线程ActivityThread,用到了Handler,Looper;在Looper循环方法,BlockCanary利用了handler原理,在 msg.target.dispatchMessage(msg);的上下方去分别打印方法执行时间,根据时间差去判断dispatchMessage是否产生了耗时的操作,是否有UI卡顿
//将打印类替换成自己的打印类,重写println就能获取消息执行前后的时间
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
try {
//上方下方都是log输出
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
BlockCanary流程分析
初始化
在application中的oncreate方法中
BlockCanary.install(getApplicationContext(), new AppBlockCanaryContext()).start();
public static BlockCanary install(Context context, BlockCanaryContext blockCanaryContext) {
//init方法仅仅做了些赋值操作
BlockCanaryContext.init(context, blockCanaryContext);
//根据用户消息栏通知消息配置是否开启关系来展示blockcanary界面
setEnabled(context, DisplayActivity.class, BlockCanaryContext.get().displayNotification());
return get();
}
public static BlockCanary get() {
if(sInstance == null) {
Class var0 = BlockCanary.class;
synchronized(BlockCanary.class) {
if(sInstance == null) {
sInstance = new BlockCanary();
}
}
}
return sInstance;
}
private BlockCanary() {
//BlockCanary一些重要的实现放在这个内部内中实现
BlockCanaryInternals.setContext(BlockCanaryContext.get());
//BlockCanaryInternals的单例
this.mBlockCanaryCore = BlockCanaryInternals.getInstance();
this.mBlockCanaryCore.addBlockInterceptor(BlockCanaryContext.get());
//通知栏是否开启,release是不显示的
if(BlockCanaryContext.get().displayNotification()) {
//展示页面
this.mBlockCanaryCore.addBlockInterceptor(new DisplayService());
}
}
由上面的代码分析出核心的一些功能在BlockCanary的内部类BlockCanaryInternals中实现
public final class BlockCanaryInternals {
LooperMonitor monitor;
StackSampler stackSampler;
CpuSampler cpuSampler;
private static BlockCanaryInternals sInstance;
private static BlockCanaryContext sContext;
private List mInterceptorChain = new LinkedList();
public BlockCanaryInternals() {
//dump出我们线程的stack信息,传入主线程以及dump的时间间隔
this.stackSampler = new StackSampler(Looper.getMainLooper().getThread(), (long)sContext.provideDumpInterval());
//dump出CPU的信息
this.cpuSampler = new CpuSampler((long)sContext.provideDumpInterval());
//LooperMonitor很重要,因为通过LooperMonitor来打印dispatchMessage时上
//下的时间
this.setMonitor(new LooperMonitor(new BlockListener() {
//当消息处理时间大于阈值,回调打印主线程调用栈,cpu的使用情况,内存情况等
public void onBlockEvent(long realTimeStart, long realTimeEnd, long threadTimeStart, long threadTimeEnd) {
ArrayList threadStackEntries = BlockCanaryInternals.this.stackSampler.getThreadStackEntries(realTimeStart, realTimeEnd);
if(!threadStackEntries.isEmpty()) {
BlockInfo blockInfo = BlockInfo.newInstance().setMainThreadTimeCost(realTimeStart, realTimeEnd, threadTimeStart, threadTimeEnd).setCpuBusyFlag(BlockCanaryInternals.this.cpuSampler.isCpuBusy(realTimeStart, realTimeEnd)).setRecentCpuRate(BlockCanaryInternals.this.cpuSampler.getCpuRateInfo()).setThreadStackEntries(threadStackEntries).flushString();
LogWriter.save(blockInfo.toString());
if(BlockCanaryInternals.this.mInterceptorChain.size() != 0) {
Iterator var11 = BlockCanaryInternals.this.mInterceptorChain.iterator();
while(var11.hasNext()) {
BlockInterceptor interceptor = (BlockInterceptor)var11.next();
interceptor.onBlock(BlockCanaryInternals.sContext.provideContext(), blockInfo);
}
}
}
}
}, (long)getContext().provideBlockThreshold(), getContext().stopWhenDebugging()));
//删除日志
LogWriter.cleanObsolete();
}
}
stacksampler/cpusampler/start方法
上面分析了install方法,现在分析下start方法
BlockCanary.install(getApplicationContext(), new AppBlockCanaryContext()).start();
public void start() {
if(!this.mMonitorStarted) {
this.mMonitorStarted = true;
//monitor为LooperMonitor
Looper.getMainLooper().setMessageLogging(this.mBlockCanaryCore.monitor);
}
//Looper类中
public void setMessageLogging(@Nullable Printer printer) {
mLogging = printer;
}
}
LooperMonitor类中有个重要的方法println,之后Looper中的日志打印将走这个方法。
class LooperMonitor implements Printer {
public void println(String x) {
if(!this.mStopWhenDebugging || !Debug.isDebuggerConnected()) {
if(!this.mPrintingStarted) {
this.mStartTimestamp = System.currentTimeMillis();
//当前线程运行的总时间,sleep跟wait不会记录这个时间当中
this.mStartThreadTimestamp = SystemClock.currentThreadTimeMillis();
this.mPrintingStarted = true;
//开始dump
this.startDump();
} else {
long endTime = System.currentTimeMillis();
this.mPrintingStarted = false;
//如果message执行后减去执行前的时间大于阈值
if(this.isBlock(endTime)) {
//执行回调
this.notifyBlockEvent(endTime);
}
//停止dump
this.stopDump();
}
}
}
private void startDump() {
if(null != BlockCanaryInternals.getInstance().stackSampler) {
//开启HandlerThread线程处理doSample()方法,doSample()主要是把当前时间
//(key)跟当前线程栈信息(value)存入linkedHashmap中
BlockCanaryInternals.getInstance().stackSampler.start();
}
if(null != BlockCanaryInternals.getInstance().cpuSampler) {
//同stackSampler,开启HandlerThread线程处理doSample()方法,主要是读
//取/proc/stat文件跟"/proc/" + this.mPid + "/stat"文件中的信息
BlockCanaryInternals.getInstance().cpuSampler.start();
}
}
private void stopDump() {
if(null != BlockCanaryInternals.getInstance().stackSampler) {
BlockCanaryInternals.getInstance().stackSampler.stop();
}
if(null != BlockCanaryInternals.getInstance().cpuSampler) {
BlockCanaryInternals.getInstance().cpuSampler.stop();
}
}
}
StackSampler类:
private static final LinkedHashMap sStackMap = new LinkedHashMap();
protected void doSample() {
StringBuilder stringBuilder = new StringBuilder();
//获取当前线程的调用栈,mCurrentThread这里代表主线程
StackTraceElement[] var2 = this.mCurrentThread.getStackTrace();
int var3 = var2.length;
for(int var4 = 0; var4 < var3; ++var4) {
StackTraceElement stackTraceElement = var2[var4];
stringBuilder.append(stackTraceElement.toString()).append("\r\n");
}
LinkedHashMap var8 = sStackMap;
synchronized(sStackMap) {
if(sStackMap.size() == this.mMaxEntryCount && this.mMaxEntryCount > 0) {
sStackMap.remove(sStackMap.keySet().iterator().next());
}
//sStackMap为LinkedHashMap,能记录我们先后插入顺序
sStackMap.put(Long.valueOf(System.currentTimeMillis()), stringBuilder.toString());
}
}
相关问题
一.ANR问题:Application Not Responding
在android中由Activity Manager和WindowManager来监控,当出现以下三种情况会报ANR
1.Service Timeout:服务在20s没执行
2.BroadcastQueue Timeout:前台广播在10s没执行
3.inputDispatching Timeout:输入事件在5s没执行(触屏,按键等)
主要原因:主线程在规定时间内没完成任务。具体分以下几类
1.主线程在做一些耗时工作
2.主线程被其他线程锁
3.cpu被其他进程占用
如何解决:
1.主线程读取数据,耗时的数据库读取
2.sharePreference的commit(同步),apply(异步)
3.不要在广播的onReceive中做耗时操作
4.Activity的生命周期不应该有太多耗时操作
watchdog-anr 如何检测ANR
使用:在Application中开启new ANRWatchDog().start();
原理:ANRWatchDog继承Thread
1.创建监测线程
2.该线程不断往UI线程post一个任务
3.睡眠固定时间
4.等该线程重新起来后检测之前post的任务是否执行了(任务执行的是++操作,判断只需要判断是否执行了++)
public class ANRWatchDog extends Thread {
private final Handler _uiHandler = new Handler(Looper.getMainLooper());
@Override
public void run() {
setName("|ANR-WatchDog|");
int lastTick;
int lastIgnored = -1;
while (!isInterrupted()) {
lastTick = _tick;
_uiHandler.post(_ticker);
try {
Thread.sleep(_timeoutInterval);
}
catch (InterruptedException e) {
_interruptionListener.onInterrupted(e);
return ;
}
// If the main thread has not handled _ticker, it is blocked. ANR.
if (_tick == lastTick) {
if (!_ignoreDebugger && Debug.isDebuggerConnected()) {
if (_tick != lastIgnored)
Log.w("ANRWatchdog", "An ANR was detected but ignored because the debugger is connected (you can prevent this with setIgnoreDebugger(true))");
lastIgnored = _tick;
continue ;
}
ANRError error;
if (_namePrefix != null)
error = ANRError.New(_namePrefix, _logThreadsWithoutStackTrace);
else
error = ANRError.NewMainOnly();
_anrListener.onAppNotResponding(error);
return;
}
}
}
}
二.线程,多线程问题
1.new Tread问题
调用start启动线程(就绪状态),实现了多线程;run方法表示一个普通的方法,不代表多线程(??)
1).多个耗时任务就会开启多个新线程,开销非常大
2).如果在线程中执行循环任务,只能通过一个Flag来控制它的停止
3).没有线程切换的接口(只能通过handler或者其他的线程通信方式)
4).如果从UI线程启动,则该线程优先级默认为Default(和UI线程相同,可能还是会阻塞主线程);Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
2.线程通信
多线程编程时有两大原则
1).不要阻塞UI线程
2).不要在UI线程之外访问UI组件
线程通信分两类
1).将任务从工作线程抛到主线程
2).将任务从主线程抛到工作线程
工作线程抛任务到主线程(不管是哪种方式,最终都是通过Handler)
1).通过Handler
2).activity.runOnUiThread(runnalbe);
3).AsynkTask
任务从主线程到工作线程
1).Thread/Runnable
2).HandlerThread
3).IntentService