From ed7393274af2f268fcdede5f1a3d72c9af842b8e Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Tue, 21 Sep 2010 15:14:14 -0700 Subject: [PATCH] Simplify and optimize MessageQueue loop. Avoids allocating new idle handler arrays on each iteration since we only need one to copy into. Coalesced the synchronized blocks. Hoisted the call to Binder.flushPendingCommands() outside of the synchronized block. Change-Id: Iabb6b633627954564bdd5d09e696663223407f47 --- core/java/android/os/MessageQueue.java | 131 +++++++++++-------------- 1 file changed, 58 insertions(+), 73 deletions(-) diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java index 2813863053113..6237c0e4e5239 100644 --- a/core/java/android/os/MessageQueue.java +++ b/core/java/android/os/MessageQueue.java @@ -33,6 +33,7 @@ import java.util.ArrayList; public class MessageQueue { Message mMessages; private final ArrayList mIdleHandlers = new ArrayList(); + private IdleHandler[] mPendingIdleHandlers; private boolean mQuiting = false; boolean mQuitAllowed = true; @@ -105,90 +106,74 @@ public class MessageQueue { } final Message next() { - boolean tryIdle = true; - // when we start out, we'll just touch the input pipes and then go from there - int timeToNextEventMillis = 0; + int pendingIdleHandlerCount = -1; // -1 only during first iteration + int nextPollTimeoutMillis = 0; - while (true) { - long now; - Object[] idlers = null; + for (;;) { + if (nextPollTimeoutMillis != 0) { + Binder.flushPendingCommands(); + } + nativePollOnce(nextPollTimeoutMillis); - boolean dispatched = nativePollOnce(timeToNextEventMillis); - - // Try to retrieve the next message, returning if found. synchronized (this) { - now = SystemClock.uptimeMillis(); - Message msg = pullNextLocked(now); + // Try to retrieve the next message. Return if found. + final long now = SystemClock.uptimeMillis(); + final Message msg = mMessages; if (msg != null) { - return msg; - } - - if (tryIdle && mIdleHandlers.size() > 0) { - idlers = mIdleHandlers.toArray(); - } - } - - // There was no message so we are going to wait... but first, - // if there are any idle handlers let them know. - boolean didIdle = false; - if (idlers != null) { - for (Object idler : idlers) { - boolean keep = false; - try { - didIdle = true; - keep = ((IdleHandler)idler).queueIdle(); - } catch (Throwable t) { - Log.wtf("MessageQueue", "IdleHandler threw exception", t); - } - - if (!keep) { - synchronized (this) { - mIdleHandlers.remove(idler); - } - } - } - } - - // While calling an idle handler, a new message could have been - // delivered... so go back and look again for a pending message. - if (didIdle) { - tryIdle = false; - continue; - } - - synchronized (this) { - // No messages, nobody to tell about it... time to wait! - if (mMessages != null) { - long longTimeToNextEventMillis = mMessages.when - now; - - if (longTimeToNextEventMillis > 0) { - Binder.flushPendingCommands(); - timeToNextEventMillis = (int) Math.min(longTimeToNextEventMillis, - Integer.MAX_VALUE); + final long when = msg.when; + if (now >= when) { + mMessages = msg.next; + if (Config.LOGV) Log.v("MessageQueue", "Returning message: " + msg); + return msg; } else { - timeToNextEventMillis = 0; + nextPollTimeoutMillis = (int) Math.min(when - now, Integer.MAX_VALUE); } } else { - Binder.flushPendingCommands(); - timeToNextEventMillis = -1; + nextPollTimeoutMillis = -1; + } + + // If first time, then get the number of idlers to run. + if (pendingIdleHandlerCount < 0) { + pendingIdleHandlerCount = mIdleHandlers.size(); + } + if (pendingIdleHandlerCount == 0) { + // No idle handlers to run. Loop and wait some more. + continue; + } + + if (mPendingIdleHandlers == null) { + mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; + } + mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); + } + + // Run the idle handlers. + // We only ever reach this code block during the first iteration. + for (int i = 0; i < pendingIdleHandlerCount; i++) { + final IdleHandler idler = mPendingIdleHandlers[i]; + mPendingIdleHandlers[i] = null; // release the reference to the handler + + boolean keep = false; + try { + keep = idler.queueIdle(); + } catch (Throwable t) { + Log.wtf("MessageQueue", "IdleHandler threw exception", t); + } + + if (!keep) { + synchronized (this) { + mIdleHandlers.remove(idler); + } } } - // loop to the while(true) and do the appropriate nativeWait(when) - } - } - final Message pullNextLocked(long now) { - Message msg = mMessages; - if (msg != null) { - if (now >= msg.when) { - mMessages = msg.next; - if (Config.LOGV) Log.v( - "MessageQueue", "Returning message: " + msg); - return msg; - } - } + // Reset the idle handler count to 0 so we do not run them again. + pendingIdleHandlerCount = 0; - return null; + // While calling an idle handler, a new message could have been delivered + // so go back and look again for a pending message without waiting. + nextPollTimeoutMillis = 0; + } } final boolean enqueueMessage(Message msg, long when) {