美文网首页
Android Framework消息机制之同步屏障解析

Android Framework消息机制之同步屏障解析

作者: 蜗牛是不是牛 | 来源:发表于2023-02-19 10:46 被阅读0次

    同步屏障的概念,在Android开发中非常容易被人忽略,因为这个概念在我们普通的开发中太少见了,很容易被忽略。大家经过上面的学习应该知道,线程的消息都是放到同一个MessageQueue里面,取消息的时候是互斥取消息,而且只能从头部取消息,而添加消息是按照消息的执行的先后顺序进行的排序, 那么问题来了,同一个时间范围内的消息,如果它是需要立刻执行的,那我们怎么办,按照常规的办法,我们需要等到队列轮询到我自己的时候才能执行哦,那岂不是黄花菜都凉了。所以,我们需要给紧急需要执行的消息一个绿色通道,这个绿色通道就是同步屏障的概念。屏障的意思即为阻碍,顾名思义, 同步屏障就是阻碍同步消息,只让异步消息通过如何开启同步屏障呢?如下而已:

    MessageQueue# postSyncBarrier( )

    我们看看它的源码

    •/
    *
    @hide
    /
    int postSyncBarrier() {
    postSyncBarrier(SystemClock.uptimeMillis());
    }
    int postSyncBarrier(long when) {
    Enqueueanewsyncba iertoken
    ( ) {
    final int token = mNextBarrierToken++;
    从消息池中获取Me age
    final Message msg = Message.obtain();
    msg.markInUse();
    就是这里!!!初始化Me age对象的时候,并没有给target赋值,因此 target==nu
    msg.when = when;
    msg.arg1 = token;
    Message prev = ;
    Message p = mMessages;
    (when != 0) {
    (p != && p.when <= when) {
    如果开启同步屏障的时间(假设记为T) T不为0,且当前的同步消息里有时间小于T,则prev
    也 不 为 nu
    prev = p;
    p = p.next;
    }
    }
    根据prev是不是为nu ,将msg按照时间顺序插入到 消息队列(链表) 的合适位置
    
    (prev != ) { invariant:p == prev.next
    msg.next = p;
    prev.next = msg;
    } {
    msg.next = p;
    mMessages = msg;
    }
    token;
    }
    }
    

    可以看到,Message 对象初始化的时候并没有给 target 赋值,因此,target == null的 来源就找到了。上面消息的插入也做了相应的注释。这样,一条target == null 的消息就进入了消息队列。

    那么,开启同步屏障后,所谓的异步消息又是如何被处理的呢?

    如果对消息机制有所了解的话,应该知道消息的最终处理是在消息轮询器Looper#loop()中,而loop()循环中会调用
    MessageQueue# next()从消息队列中进行取消息。

    / / MessageQueue. java
    Message next() .. 省略一些代码
    int pendingIdleHandlerCount = -1; -1 onlyduringfirst iteration
    1.如果nextPo TimeoutMi is=-1,一直阻塞不会超时。
    2.如果nextPo TimeoutMi is=0,不会阻塞,立即返回。
    3.如果nextPo TimeoutMi is>0,最长阻塞nextPo TimeoutMi is毫秒(超时)
    如果期间有程序唤醒会立即返回。
    int nextPollTimeoutMillis = 0;
    next()也是一个无限循环
    ( {
    (nextPollTimeoutMillis != 0) {
    Binder.flushPendingCommands();
    }
    nativePollOnce(ptr, nextPollTimeoutMillis);
    ( ) {
    获取系统开机到现在的时间
    final long now = SystemClock.uptimeMillis();
    Message prevMsg = ;
    Message msg = mMessages; 当前链表的头结点
    关键!!!
    如果target==nu ,那么它就是屏障,需要循环遍历,一直往后找到第一个异步的消息
    (msg != && msg.target == ) {
    Sta ed byaba ier. Findthenextasynchronousme ageinthequeue.
    {
    prevMsg = msg;
    msg = msg.next;
    } (msg != && !msg.isAsynchronous());
    }
    (msg != ) {
    如果有消息需要处理,先判断时间有没有到,如果没到的话设置一下阻塞时间,
    场景如常用的postDelay
    (now < msg.when) {
    计算出离执行时间还有多久赋值给nextPo TimeoutMi is,
    表示nativePo Once方法要等待nextPo TimeoutMi is时长后返回
    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALU
    E);
    } {
    获取到消息
    mBlocked = ;
    链表操作,获取msg并且删除该节点
    (prevMsg != )
    prevMsg.next = msg.next;
    } {
    mMessages = msg.next;
    }
    msg.next = null;
    msg.markInUse();
    返回拿到的消息
    msg;
    }
    } {
    没有消息,nextPo TimeoutMi is复位
    nextPollTimeoutMillis = -1;
    }
    .. 省略
    }
    

    从上面可以看出,当消息队列开启同步屏障的时候 (即标识为msg.target == null) ,消息机制在处理消息的时候,优先处理异步
    消息。这样,同步屏障就起到了一种过滤和优先级的作用。

    下面用示意图简单说明:

    在这里插入图片描述

    如上图所示,在消息队列中有同步消息和异步消息 (黄色部分) 以及一道墙----同步屏障 (红色部分) 。有了同步屏障的存在,msg2和msgM 这两个异步消息可以被优先处理,而后面的 msg_3 等同步消息则不会被处理。那么这些同步消息什么时候可以被处
    理呢?那就需要先移除这个同步屏障,即调用removeSyncBarrier()。

    似乎在日常的应用开发中,很少会用到同步屏障。那么,同步屏障在系统源码中有哪些使用场景呢?Android 系统中的 UI 更新相
    关的消息即为异步消息,需要优先处理。
    比如,在 View 更新时,draw、requestLayout、invalidate 等很多地方都调用了ViewRootImpl#scheduleTraversals(),如下:

    / / ViewRootImpl. java void scheduleTraversals() {
    (!mTraversalScheduled) {
    mTraversalScheduled = ;
    开启同步屏障
    mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
    发送异步消息
    mChoreographer.postCallback(
    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, );
    (!mUnbufferedInputDispatch) {
    scheduleConsumeBatchedInput();
    }
    notifyRendererOfFramePending();
    pokeDrawLockIfNeeded();
    }
    }
    postCallback( ) 最 终 走 到 了 ChoreographerpostCallbackDelayedInternal( ) :
    private void postCallbackDelayedInternal( int callbackType,
    Object action, Object token, long delayMillis) {
    if (DEBUG_FRAMES) {
    Log. d(TAG, "PostCallback : type=" + callbackType- ", action=" + action + ",
    token=" + token =" + delayMillis) ;
    }
    synchronized ( mLock) {
    final long now = SystemClock.uptimeMillis() ;
    final long dueTime = now + delayMillis ;
    mCallbackQueues[ callbackType] . addCallbackLocked( dueTime, action, token) ;
    if (dueTime <= now) {
    scheduleFrameLocked(now) ;
    } else {
    Message msg = mHandler. obtainMessage( MSG_ DO_ SCHEDULE_ CALLBACK, action) ;
    msg.arg1 = callbackType ;
    msg.setAsynchronous(true) ; //异步消息
    mHandler. sendMessageAtTime( msg, dueTime) ;
    }
    }
    }
    这里就开启了同步屏障,并发送异步消息, 由于 UI 更新相关的消息是优先级最高的,这样系统就会优先处理这些异步消息。
    最 后,当要移除同步屏障的时候需要调用ViewRootImpl#unscheduleTraversals()。
    void unscheduleTraversals( ) {
    if ( mTraversalScheduled) {
    mTraversalScheduled = false ;
    //移除同步屏障
    mHandler. getLooper( ) . getQueue( ) . removeSyncBarrier( mTraversalBarrier) ;
    mChoreographer. removeCallbacks(
    Choreographer. CALLBACK_ TRAVERSAL, mTraversalRunnable, null) ;
    }
    }
    

    最后

    第一章 系统启动流程分析

    • 第一节 Android启动概览
    • 第二节 init.rc解析
    • 第三节 Zygote
    • 第四节 面试题

    第二章 跨进程通信IPC解析

    • 第一节 Sercice 还可以这么理解
    • 第二节 Binder基础
    • 第三节 Binder应用
    • 第四节 AIDL应用(上)
    • 第五节 AIDL应用(下)
    • 第六节 Messenger原理及应用
    • 第七节 服务端回调
    • 第八节 获取服务(IBinder)
    • 第九节 Binder面试题全解析

    第三章 Handler源码解析

    • 第一节 源码分析
    • 第二节 难点问题
    • 第三节 Handler常问面试题

    第四章 AMS源码解析

    • 第一节 引言
    • 第二节 Android架构
    • 第三节 通信方式
    • 第四节 系统启动系列
    • 第五节 AMS
    • 第六节 AMS 面试题解析

    第五章 WMS源码解析

    • 第一节 WMS与activity启动流程
    • 第二节 WMS绘制原理
    • 第三节 WMS角色与实例化过程
    • 第四节 WMS工作原理

    第六章 Surface源码解析

    • 第一节 创建流程及软硬件绘制
    • 第二节 双缓冲及SurfaceView解析
    • 第三节 Android图形系统综述

    第七章 基于Android12.0的SurfaceFlinger源码解析

    • 第一节 应用建立和SurfaceFlinger的沟通的桥梁
    • 第二节 SurfaceFlinger的启动和消息队列处理机制
    • 第三节 SurfaceFlinger 之 VSync(上)
    • 第四节 SurfaceFlinger之VSync(中)
    • 第五节 SurfaceFlinger之VSync(下)

    第八章 PKMS源码解析

    • 第一节 PKMS调用方式
    • 第二节 PKMS启动过程分析
    • 第三节 APK的扫描
    • 第四节 APK的安装
    • 第五节 PKMS之权限扫描
    • 第六节 静默安装
    • 第七节 requestPermissions源码流程解析

    第九章 InputManagerService源码解析

    • 第一节 Android Input输入事件处理流程(1)
    • 第二节 Android Input输入事件处理流程(2)
    • 第三节 Android Input输入事件处理流程(3)

    第十章 DisplayManagerService源码解析

    • 第一节 DisplayManagerService启动
    • 第二节 DisplayAdapter和DisplayDevice的创建
    • 第三节 DMS部分亮灭屏流程
    • 第四节 亮度调节
    • 第五节 Proximity Sensor灭屏原理
    • 第六节 Logical Display和Physical Display配置的更新

    s我获取~

    相关文章

      网友评论

          本文标题:Android Framework消息机制之同步屏障解析

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