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

同步屏障的概念,在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 Framework框架,这里可以分享一份《Android Framework源码开发揭秘》,其中记录了从系统启动流程到WMS全部源码解析,相信你能优秀地学习整个Framework框架。

第一章 系统启动流程分析

  • 第一节 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配置的更新

在这里插入图片描述

各位小伙伴们如果有需要这份《Android Framework源码开发揭秘》资料,扫码即可【免费领取】

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值