@@ -39,6 +39,9 @@ public class MessageQueue {
3939 // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
4040 private boolean mBlocked ;
4141
42+ // Indicates the barrier nesting level.
43+ private int mBarrierNestCount ;
44+
4245 @ SuppressWarnings ("unused" )
4346 private int mPtr ; // used by native code
4447
@@ -93,7 +96,53 @@ public final void removeIdleHandler(IdleHandler handler) {
9396 mIdleHandlers .remove (handler );
9497 }
9598 }
96-
99+
100+ /**
101+ * Acquires a synchronization barrier.
102+ *
103+ * While a synchronization barrier is active, only asynchronous messages are
104+ * permitted to execute. Synchronous messages are retained but are not executed
105+ * until the synchronization barrier is released.
106+ *
107+ * This method is used to immediately postpone execution of all synchronous messages
108+ * until a condition is met that releases the barrier. Asynchronous messages are
109+ * exempt from the barrier and continue to be executed as usual.
110+ *
111+ * This call nests and must be matched by an equal number of calls to
112+ * {@link #releaseSyncBarrier}.
113+ *
114+ * @hide
115+ */
116+ public final void acquireSyncBarrier () {
117+ synchronized (this ) {
118+ mBarrierNestCount += 1 ;
119+ }
120+ }
121+
122+ /**
123+ * Releases a synchronization barrier.
124+ *
125+ * This class undoes one invocation of {@link #acquireSyncBarrier}.
126+ *
127+ * @throws IllegalStateException if the barrier is not acquired.
128+ *
129+ * @hide
130+ */
131+ public final void releaseSyncBarrier () {
132+ synchronized (this ) {
133+ if (mBarrierNestCount == 0 ) {
134+ throw new IllegalStateException ("The message queue synchronization barrier "
135+ + "has not been acquired." );
136+ }
137+
138+ mBarrierNestCount -= 1 ;
139+ if (!mBlocked || mMessages == null ) {
140+ return ;
141+ }
142+ }
143+ nativeWake (mPtr );
144+ }
145+
97146 MessageQueue () {
98147 nativeInit ();
99148 }
@@ -120,28 +169,49 @@ final Message next() {
120169 synchronized (this ) {
121170 // Try to retrieve the next message. Return if found.
122171 final long now = SystemClock .uptimeMillis ();
123- final Message msg = mMessages ;
124- if (msg != null ) {
172+
173+ Message prevMsg = null ;
174+ Message msg = mMessages ;
175+ for (;;) {
176+ if (msg == null ) {
177+ // No more messages.
178+ nextPollTimeoutMillis = -1 ;
179+ break ;
180+ }
181+
125182 final long when = msg .when ;
126- if (now >= when ) {
183+ if (now < when ) {
184+ // Next message is not ready. Set a timeout to wake up when it is ready.
185+ nextPollTimeoutMillis = (int ) Math .min (when - now , Integer .MAX_VALUE );
186+ break ;
187+ }
188+
189+ if (mBarrierNestCount == 0 || msg .isAsynchronous ()) {
190+ // Got a message.
127191 mBlocked = false ;
128- mMessages = msg .next ;
192+ if (prevMsg != null ) {
193+ prevMsg .next = msg .next ;
194+ } else {
195+ mMessages = msg .next ;
196+ }
129197 msg .next = null ;
130198 if (false ) Log .v ("MessageQueue" , "Returning message: " + msg );
131199 msg .markInUse ();
132200 return msg ;
133- } else {
134- nextPollTimeoutMillis = (int ) Math .min (when - now , Integer .MAX_VALUE );
135201 }
136- } else {
137- nextPollTimeoutMillis = -1 ;
202+
203+ // We have a message that we could return except that it is
204+ // blocked by the sync barrier. In particular, this means that
205+ // we are not idle yet, so we do not want to run the idle handlers.
206+ prevMsg = msg ;
207+ msg = msg .next ;
138208 }
139209
140- // If first time, then get the number of idlers to run.
141- if (pendingIdleHandlerCount < 0 ) {
210+ // If first time idle , then get the number of idlers to run.
211+ if (pendingIdleHandlerCount < 0 && msg == mMessages ) {
142212 pendingIdleHandlerCount = mIdleHandlers .size ();
143213 }
144- if (pendingIdleHandlerCount = = 0 ) {
214+ if (pendingIdleHandlerCount < = 0 ) {
145215 // No idle handlers to run. Loop and wait some more.
146216 mBlocked = true ;
147217 continue ;
@@ -205,18 +275,24 @@ final boolean enqueueMessage(Message msg, long when) {
205275 //Log.d("MessageQueue", "Enqueing: " + msg);
206276 Message p = mMessages ;
207277 if (p == null || when == 0 || when < p .when ) {
278+ // New head, wake up the event queue if blocked.
208279 msg .next = p ;
209280 mMessages = msg ;
210- needWake = mBlocked ; // new head, might need to wake up
281+ needWake = mBlocked ;
211282 } else {
283+ // Inserted within the middle of the queue. Usually we don't have to wake
284+ // up the event queue unless the message is asynchronous and it might be
285+ // possible for it to be returned out of sequence relative to an earlier
286+ // synchronous message at the head of the queue.
212287 Message prev = null ;
213288 while (p != null && p .when <= when ) {
214289 prev = p ;
215290 p = p .next ;
216291 }
217292 msg .next = prev .next ;
218293 prev .next = msg ;
219- needWake = false ; // still waiting on head, no need to wake up
294+ needWake = mBlocked && mBarrierNestCount != 0 && msg .isAsynchronous ()
295+ && !mMessages .isAsynchronous ();
220296 }
221297 }
222298 if (needWake ) {
0 commit comments