Loading core/java/android/os/CombinedMessageQueue/MessageQueue.java +114 −0 Original line number Diff line number Diff line Loading @@ -1093,6 +1093,120 @@ public final class MessageQueue { } } /** * Returns the last message in the queue in execution order. * * Caller must ensure that this doesn't race 'next' from the Looper thread. * @hide */ public @Nullable Message peekLastMessageForTest() { ActivityThread.throwIfNotInstrumenting(); if (sUseConcurrent) { return peekLastMessageConcurrent(); } else { return peekLastMessageLegacy(); } } /** * Matches no messages, but stores the message with the latest execution time. */ static final class FindLastMessage extends MessageCompare { Message lastMsg; @Override public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, long when) { if (m.target != null && (lastMsg == null || lastMsg.when <= m.when)) { lastMsg = m; } return false; } } private Message peekLastMessageConcurrent() { final FindLastMessage findLastMessage = new FindLastMessage(); findOrRemoveMessages(null, 0, null, null, 0, findLastMessage, false); return findLastMessage.lastMsg; } private Message peekLastMessageLegacy() { synchronized (this) { Message lastMsg = null; Message current = mMessages; while (current != null) { if (current.target != null && (lastMsg == null || lastMsg.when <= current.when)) { lastMsg = current; } current = current.next; } return lastMsg; } } /** * Resets this queue's state and allows it to continue being used. * * @hide */ public void resetForTest() { ActivityThread.throwIfNotInstrumenting(); if (sUseConcurrent) { resetConcurrent(); } else { resetLegacy(); } } private void resetConcurrent() { // This queue is already quitting, so we can't reset its state and continue using it. if (getQuitting()) { return; } synchronized (mIdleHandlersLock) { mIdleHandlers.clear(); } synchronized (mFileDescriptorRecordsLock) { removeAllFdRecords(); } removeAllMessages(); // We reset the sync barrier tokens to reflect the queue's state reset. This helps ensure // that the queue's behavior is deterministic in both individual tests and in a test suite. resetSyncBarrierTokens(); } private void resetLegacy() { synchronized (this) { // This queue is already quitting, so we can't reset its state and continue using it. if (mQuitting) { return; } mIdleHandlers.clear(); removeAllFdRecords(); removeAllMessagesLocked(); // We reset the sync barrier tokens to reflect the queue's state reset. This helps // ensure that the queue's behavior is deterministic in both individual tests and in a // test suite. resetSyncBarrierTokens(); nativeWake(mPtr); } } private void removeAllFdRecords() { if (mFileDescriptorRecords != null) { while (mFileDescriptorRecords.size() > 0) { removeOnFileDescriptorEventListener(mFileDescriptorRecords.valueAt(0).mDescriptor); } } } private void resetSyncBarrierTokens() { mNextBarrierTokenAtomic.set(1); mNextBarrierToken = 0; } void quit(boolean safe) { if (!mQuitAllowed) { throw new IllegalStateException("Main thread not allowed to quit."); Loading core/java/android/os/DeliQueue/MessageQueue.java +50 −0 Original line number Diff line number Diff line Loading @@ -660,6 +660,56 @@ public final class MessageQueue { return false; } /** * Returns the message with the latest scheduled execution time. * * * Caller must ensure that this doesn't race 'next' from the Looper thread. * @hide */ public @Nullable Message peekLastMessageForTest() { ActivityThread.throwIfNotInstrumenting(); return mStack.peekLastMessageForTest(); } /** * Resets this queue's state. * * @hide */ public void resetForTest() { ActivityThread.throwIfNotInstrumenting(); // This queue is already quitting, so we can't reset its state and continue using it. if (mWorkerShouldQuit) { return; } synchronized (mIdleHandlersLock) { mIdleHandlers.clear(); } synchronized (mFileDescriptorRecordsLock) { removeAllFdRecords(); } removeAllMessages(); mStack.drainFreelist(); // We reset the sync barrier tokens to reflect the queue's state reset. This helps ensure // that the queue's behavior is deterministic in both individual tests and in a test suite. resetSyncBarrierTokens(); } private void removeAllFdRecords() { if (mFileDescriptorRecords != null) { while (mFileDescriptorRecords.size() > 0) { removeOnFileDescriptorEventListener(mFileDescriptorRecords.valueAt(0).mDescriptor); } } } private void resetSyncBarrierTokens() { mNextBarrierTokenAtomic.set(1); mNextBarrierToken = 0; } void quit(boolean safe) { if (!mQuitAllowed) { throw new IllegalStateException("Main thread not allowed to quit."); Loading core/java/android/os/LegacyMessageQueue/MessageQueue.java +60 −0 Original line number Diff line number Diff line Loading @@ -469,6 +469,66 @@ public final class MessageQueue { } } /** * Returns the last message in the queue in execution order. * * Caller must ensure that this doesn't race 'next' from the Looper thread. * @hide */ public @Nullable Message peekLastMessageForTest() { ActivityThread.throwIfNotInstrumenting(); synchronized (this) { Message lastMsg = null; Message current = mMessages; while (current != null) { if (current.target != null && (lastMsg == null || lastMsg.when <= current.when)) { lastMsg = current; } current = current.next; } return lastMsg; } } /** * Resets this queue's state and allows it to continue being used. * * @hide */ public void resetForTest() { ActivityThread.throwIfNotInstrumenting(); synchronized (this) { // This queue is already quitting, so we can't reset its state and continue using it. if (mQuitting) { return; } mIdleHandlers.clear(); removeAllFdRecords(); removeAllMessagesLocked(); // We reset the sync barrier tokens to reflect the queue's state reset. This helps // ensure that the queue's behavior is deterministic in both individual tests and in a // test suite. resetSyncBarrierTokens(); nativeWake(mPtr); } } private void removeAllFdRecords() { if (mFileDescriptorRecords != null) { while (mFileDescriptorRecords.size() > 0) { removeOnFileDescriptorEventListener(mFileDescriptorRecords.valueAt(0).mDescriptor); } } } private void resetSyncBarrierTokens() { // Legacy MQ doesn't use an atomic integer for barrier tokens. // mNextBarrierTokenAtomic.set(1); mNextBarrierToken = 0; } void quit(boolean safe) { if (!mQuitAllowed) { throw new IllegalStateException("Main thread not allowed to quit."); Loading core/java/android/os/MessageStack.java +12 −0 Original line number Diff line number Diff line Loading @@ -355,6 +355,18 @@ public final class MessageStack { removeMessage(m, /* removeFromHeap= */ true); } Message peekLastMessageForTest() { Message lastMsg = null; Message current = (Message) sTop.getAcquire(this); while (current != null) { if (lastMsg == null || (current.when > lastMsg.when && !lastMsg.isRemoved())) { lastMsg = current; } current = current.next; } return lastMsg; } /** * Returns the number of non-removed messages in this stack. */ Loading core/tests/coretests/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -866,6 +866,7 @@ test_module_config { include_filters: [ "android.os.MessageHeapTest", "android.os.MessageStackTest", "android.os.MessageQueueTest", "android.os.WaitStateTest", ], } Loading
core/java/android/os/CombinedMessageQueue/MessageQueue.java +114 −0 Original line number Diff line number Diff line Loading @@ -1093,6 +1093,120 @@ public final class MessageQueue { } } /** * Returns the last message in the queue in execution order. * * Caller must ensure that this doesn't race 'next' from the Looper thread. * @hide */ public @Nullable Message peekLastMessageForTest() { ActivityThread.throwIfNotInstrumenting(); if (sUseConcurrent) { return peekLastMessageConcurrent(); } else { return peekLastMessageLegacy(); } } /** * Matches no messages, but stores the message with the latest execution time. */ static final class FindLastMessage extends MessageCompare { Message lastMsg; @Override public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, long when) { if (m.target != null && (lastMsg == null || lastMsg.when <= m.when)) { lastMsg = m; } return false; } } private Message peekLastMessageConcurrent() { final FindLastMessage findLastMessage = new FindLastMessage(); findOrRemoveMessages(null, 0, null, null, 0, findLastMessage, false); return findLastMessage.lastMsg; } private Message peekLastMessageLegacy() { synchronized (this) { Message lastMsg = null; Message current = mMessages; while (current != null) { if (current.target != null && (lastMsg == null || lastMsg.when <= current.when)) { lastMsg = current; } current = current.next; } return lastMsg; } } /** * Resets this queue's state and allows it to continue being used. * * @hide */ public void resetForTest() { ActivityThread.throwIfNotInstrumenting(); if (sUseConcurrent) { resetConcurrent(); } else { resetLegacy(); } } private void resetConcurrent() { // This queue is already quitting, so we can't reset its state and continue using it. if (getQuitting()) { return; } synchronized (mIdleHandlersLock) { mIdleHandlers.clear(); } synchronized (mFileDescriptorRecordsLock) { removeAllFdRecords(); } removeAllMessages(); // We reset the sync barrier tokens to reflect the queue's state reset. This helps ensure // that the queue's behavior is deterministic in both individual tests and in a test suite. resetSyncBarrierTokens(); } private void resetLegacy() { synchronized (this) { // This queue is already quitting, so we can't reset its state and continue using it. if (mQuitting) { return; } mIdleHandlers.clear(); removeAllFdRecords(); removeAllMessagesLocked(); // We reset the sync barrier tokens to reflect the queue's state reset. This helps // ensure that the queue's behavior is deterministic in both individual tests and in a // test suite. resetSyncBarrierTokens(); nativeWake(mPtr); } } private void removeAllFdRecords() { if (mFileDescriptorRecords != null) { while (mFileDescriptorRecords.size() > 0) { removeOnFileDescriptorEventListener(mFileDescriptorRecords.valueAt(0).mDescriptor); } } } private void resetSyncBarrierTokens() { mNextBarrierTokenAtomic.set(1); mNextBarrierToken = 0; } void quit(boolean safe) { if (!mQuitAllowed) { throw new IllegalStateException("Main thread not allowed to quit."); Loading
core/java/android/os/DeliQueue/MessageQueue.java +50 −0 Original line number Diff line number Diff line Loading @@ -660,6 +660,56 @@ public final class MessageQueue { return false; } /** * Returns the message with the latest scheduled execution time. * * * Caller must ensure that this doesn't race 'next' from the Looper thread. * @hide */ public @Nullable Message peekLastMessageForTest() { ActivityThread.throwIfNotInstrumenting(); return mStack.peekLastMessageForTest(); } /** * Resets this queue's state. * * @hide */ public void resetForTest() { ActivityThread.throwIfNotInstrumenting(); // This queue is already quitting, so we can't reset its state and continue using it. if (mWorkerShouldQuit) { return; } synchronized (mIdleHandlersLock) { mIdleHandlers.clear(); } synchronized (mFileDescriptorRecordsLock) { removeAllFdRecords(); } removeAllMessages(); mStack.drainFreelist(); // We reset the sync barrier tokens to reflect the queue's state reset. This helps ensure // that the queue's behavior is deterministic in both individual tests and in a test suite. resetSyncBarrierTokens(); } private void removeAllFdRecords() { if (mFileDescriptorRecords != null) { while (mFileDescriptorRecords.size() > 0) { removeOnFileDescriptorEventListener(mFileDescriptorRecords.valueAt(0).mDescriptor); } } } private void resetSyncBarrierTokens() { mNextBarrierTokenAtomic.set(1); mNextBarrierToken = 0; } void quit(boolean safe) { if (!mQuitAllowed) { throw new IllegalStateException("Main thread not allowed to quit."); Loading
core/java/android/os/LegacyMessageQueue/MessageQueue.java +60 −0 Original line number Diff line number Diff line Loading @@ -469,6 +469,66 @@ public final class MessageQueue { } } /** * Returns the last message in the queue in execution order. * * Caller must ensure that this doesn't race 'next' from the Looper thread. * @hide */ public @Nullable Message peekLastMessageForTest() { ActivityThread.throwIfNotInstrumenting(); synchronized (this) { Message lastMsg = null; Message current = mMessages; while (current != null) { if (current.target != null && (lastMsg == null || lastMsg.when <= current.when)) { lastMsg = current; } current = current.next; } return lastMsg; } } /** * Resets this queue's state and allows it to continue being used. * * @hide */ public void resetForTest() { ActivityThread.throwIfNotInstrumenting(); synchronized (this) { // This queue is already quitting, so we can't reset its state and continue using it. if (mQuitting) { return; } mIdleHandlers.clear(); removeAllFdRecords(); removeAllMessagesLocked(); // We reset the sync barrier tokens to reflect the queue's state reset. This helps // ensure that the queue's behavior is deterministic in both individual tests and in a // test suite. resetSyncBarrierTokens(); nativeWake(mPtr); } } private void removeAllFdRecords() { if (mFileDescriptorRecords != null) { while (mFileDescriptorRecords.size() > 0) { removeOnFileDescriptorEventListener(mFileDescriptorRecords.valueAt(0).mDescriptor); } } } private void resetSyncBarrierTokens() { // Legacy MQ doesn't use an atomic integer for barrier tokens. // mNextBarrierTokenAtomic.set(1); mNextBarrierToken = 0; } void quit(boolean safe) { if (!mQuitAllowed) { throw new IllegalStateException("Main thread not allowed to quit."); Loading
core/java/android/os/MessageStack.java +12 −0 Original line number Diff line number Diff line Loading @@ -355,6 +355,18 @@ public final class MessageStack { removeMessage(m, /* removeFromHeap= */ true); } Message peekLastMessageForTest() { Message lastMsg = null; Message current = (Message) sTop.getAcquire(this); while (current != null) { if (lastMsg == null || (current.when > lastMsg.when && !lastMsg.isRemoved())) { lastMsg = current; } current = current.next; } return lastMsg; } /** * Returns the number of non-removed messages in this stack. */ Loading
core/tests/coretests/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -866,6 +866,7 @@ test_module_config { include_filters: [ "android.os.MessageHeapTest", "android.os.MessageStackTest", "android.os.MessageQueueTest", "android.os.WaitStateTest", ], }