主页 > 人工智能  > 

Matrix卡顿优化之IdleHandlerLagTracer源码分析

Matrix卡顿优化之IdleHandlerLagTracer源码分析
前言

IdleHandler是Android系统为开发者提供的一种在消息队列空闲时运行任务的机制,通过IdleHandler执行的任务优先级低于主线程优先级,会在主线程任务执行完成后再执行,所以适用于一些实时性要求不高的任务,通常用于Android启动优化中,将一些优先级较低的任务延后执行,以提高应用启动速度。看下消息队列中的源码。

@UnsupportedAppUsage Message next() { //前边省略了很多代码,只有消息队列当前没有需要执行的任务时,才会执行到下边的代码 for (int i = 0; i < pendingIdleHandlerCount; i++) { final IdleHandler idler = mPendingIdleHandlers[i]; keep = idler.queueIdle(); } }

那么既然IdleHandler是用于进行性能优化的,为什么matrix还要对其进行监控呢?从上边的分析我们可以知道,IdleHandler也是在主线程消息队列中运行的,所以假如IdleHandler中出现了耗时任务执行,那么很明显就会导致主线程卡顿,IdleHandler也是属于主线程卡顿监控的关键一环。

了解了IdleHandler监控的必要性,我们现在开始今天的源码分析。和其他类型的tracer一致,IdleHandler也是在TracePlugin中进行初始化和调用的,那么我们就从这几个关键方法入手:

构造方法onStartTraceonStopTrace 构造方法

构造方法仅仅是拿到了传入的配置,配置中包含的是IdleHandler监控是否启用的开关,isIdleHandlerTraceEnable。

public IdleHandlerLagTracer(TraceConfig config) { traceConfig = config; } onStartTrace

onStartTrace会调用到onAlive方法,我们看onAlive的源码,首先初始化了一个HandlerThread,然后创建了一个IdleHandlerLagRunnable,最后调用了detectIdleHandler开启监控。

@Override public void onAlive() { super.onAlive(); if (traceConfig.isIdleHandlerTraceEnable()) { //异步线程 idleHandlerLagHandlerThread = new HandlerThread("IdleHandlerLagThread"); //上报信息用的runnable idleHandlerLagRunnable = new IdleHandlerLagRunable(); detectIdleHandler(); } }

IdleHandlerLagRunnable是用于上报信息的,我们先看detectIdleHandler方法。首先拿到主线程消息队列对象,然后通过反射从MessageQueue对象上获取到mIdleHandlers的Field对象,mIdleHandlers是一个List集合,内部存储了所有当前消息队列添加的IdleHandler对象。拿到之后构造了一个自定义的List-MyArrayList,反射将其设置到消息队列上,这里的目的是将mIdleHandlers作为一个hook点,完成替换之后,主线程添加和移除IdleHandler的操作都在我们的监控范围之内了。

private static void detectIdleHandler() { MessageQueue mainQueue = Looper.getMainLooper().getQueue(); Field field = MessageQueue.class.getDeclaredField("mIdleHandlers"); field.setAccessible(true); MyArrayList<MessageQueue.IdleHandler> myIdleHandlerArrayList = new MyArrayList<>(); //反射替换消息队列中的List field.set(mainQueue, myIdleHandlerArrayList); idleHandlerLagHandlerThread.start(); idleHandlerLagHandler = new Handler(idleHandlerLagHandlerThread.getLooper()); } MyArrayList

看下MyArrayList的实现。它继承自ArrayList,重写了add和remove方法,也就是拦截了IdleHandler的添加和移除。当通过调用MessageQueue的addIdleHandler方法向list中添加时,就会走到MyArrayList的add方法中,此时会将IdleHandler再包装一层MyIdleHandler存入,达到拦截IdleHandler的queueIdle方法调用的目的。

static class MyArrayList<T> extends ArrayList { Map<MessageQueue.IdleHandler, MyIdleHandler> map = new HashMap<>(); @Override public boolean add(Object o) { if (o instanceof MessageQueue.IdleHandler) { //包装一层,作为代理。拦截queueIdle方法的执行 MyIdleHandler myIdleHandler = new MyIdleHandler((MessageQueue.IdleHandler) o); //记录映射关系 map.put((MessageQueue.IdleHandler) o, myIdleHandler); return super.add(myIdleHandler); } return super.add(o); } @Override public boolean remove(@Nullable Object o) { if (o instanceof MyIdleHandler) { MessageQueue.IdleHandler idleHandler = ((MyIdleHandler) o).idleHandler; map.remove(idleHandler); return super.remove(o); } else { MyIdleHandler myIdleHandler = map.remove(o); if (myIdleHandler != null) { return super.remove(myIdleHandler); } return super.remove(o); } } } MyIdleHandler

接下来我们看看MyIdleHandler是怎么实现的。可以看到它继承自IdleHandler,并重写了它的queueIdle方法,这样一来每一个IdleHandler执行时都会走到MyIdleHandler的queueIdle方法中,也就都在我们的监控之内了。

static class MyIdleHandler implements MessageQueue.IdleHandler { @Override public boolean queueIdle() { //发送延时消息,延时内未执行完成就上报 idleHandlerLagHandler.postDelayed(idleHandlerLagRunnable, traceConfig.idleHandlerLagThreshold); boolean ret = this.idleHandler.queueIdle(); //执行完成则移除延时消息 idleHandlerLagHandler.removeCallbacks(idleHandlerLagRunnable); return ret; } }

当queueIdle执行的时候,通过idleHandlerLagHandler发送一个延时2s(默认)的消息,idleHandlerLagHandler是一个和HandlerThread绑定的Handler,它会将消息发送到HandlerThread子线程执行,假如2s内queueIdle方法执行完成,那么这个消息就会被移除,也就是不会触发上报。

这个消息做了什么呢?我们接下来看看这个idleHandlerLagRunnable。

IdleHandlerLagRunnable

这里也就是在收集信息上报了。

static class IdleHandlerLagRunable implements Runnable { @Override public void run() { String stackTrace = Utils.getMainThreadJavaStackTrace(); boolean currentForeground = AppForegroundUtil.isInterestingToUser(); String scene = AppActiveMatrixDelegate.INSTANCE.getVisibleScene(); JSONObject jsonObject = new JSONObject(); jsonObject = DeviceUtil.getDeviceInfo(jsonObject, Matrix.with().getApplication()); jsonObject.put(SharePluginInfo.ISSUE_STACK_TYPE, Constants.Type.LAG_IDLE_HANDLER); jsonObject.put(SharePluginInfo.ISSUE_SCENE, scene); jsonObject.put(SharePluginInfo.ISSUE_THREAD_STACK, stackTrace); jsonObject.put(SharePluginInfo.ISSUE_PROCESS_FOREGROUND, currentForeground); Issue issue = new Issue(); issue.setTag(SharePluginInfo.TAG_PLUGIN_EVIL_METHOD); issue.setContent(jsonObject); plugin.onDetectIssue(issue); } } onStopTrace

onStopTrace会调用到onDead方法,这里就是当任务停止时,移除所有消息。

@Override public void onDead() { super.onDead(); if (traceConfig.isIdleHandlerTraceEnable()) { idleHandlerLagHandler.removeCallbacksAndMessages(null); } } 总结

IdleHandlerLagTracer的实现逻辑还是很简单的,它通过hook的方法替换了主线程消息队列的IdleHandlers集合,从而拦截到了IdleHandler的添加和移除逻辑,在拦截到添加IdleHandler的操作时,为原来的IdleHandler做一层代理,从来可以在queueIdle方法执行时做超时监听逻辑,超时未执行完成则收集信息上报,从而发现IdleHandler导致的卡顿问题。

Android 学习笔录

Android 性能优化篇: qr18 /FVlo89 Android Framework底层原理篇: qr18 /AQpN4J Android 车载篇: qr18 /F05ZCM Android 逆向安全学习笔记: qr18 /CQ5TcL Android 音视频篇: qr18 /Ei3VPD Jetpack全家桶篇(内含Compose): qr18 /A0gajp OkHttp 源码解析笔记: qr18 /Cw0pBD Kotlin 篇: qr18 /CdjtAF Gradle 篇: qr18 /DzrmMB Flutter 篇: qr18 /DIvKma Android 八大知识体: qr18 /CyxarU Android 核心笔记: qr21 /CaZQLo Android 往年面试题锦: qr18 /CKV8OZ 2023年最新Android 面试题集: qr18 /CgxrRy Android 车载开发岗位面试习题: qr18 /FTlyCJ 音视频面试题锦: qr18 /AcV6Ap

标签:

Matrix卡顿优化之IdleHandlerLagTracer源码分析由讯客互联人工智能栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“Matrix卡顿优化之IdleHandlerLagTracer源码分析