141e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills/* 241e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills * Copyright (C) 2015 The Android Open Source Project 341e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills * 441e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills * Licensed under the Apache License, Version 2.0 (the "License"); 541e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills * you may not use this file except in compliance with the License. 641e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills * You may obtain a copy of the License at 741e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills * 841e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills * http://www.apache.org/licenses/LICENSE-2.0 941e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills * 1041e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills * Unless required by applicable law or agreed to in writing, software 1141e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills * distributed under the License is distributed on an "AS IS" BASIS, 1241e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1341e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills * See the License for the specific language governing permissions and 1441e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills * limitations under the License. 1541e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills */ 1641e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills 1741e38d84f562e12198f7db0d45f633712cae6cbaMitchell Willspackage com.android.server.wifi; 1841e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills 1972c639e8b97067e948eca8be50dfea3173121090Mitchell Willsimport static org.junit.Assert.assertTrue; 2041e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills 2141e38d84f562e12198f7db0d45f633712cae6cbaMitchell Willsimport android.os.Looper; 2241e38d84f562e12198f7db0d45f633712cae6cbaMitchell Willsimport android.os.Message; 2341e38d84f562e12198f7db0d45f633712cae6cbaMitchell Willsimport android.os.MessageQueue; 24b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohenimport android.os.SystemClock; 25d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silbersteinimport android.util.Log; 2641e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills 2741e38d84f562e12198f7db0d45f633712cae6cbaMitchell Willsimport java.lang.reflect.Constructor; 2841e38d84f562e12198f7db0d45f633712cae6cbaMitchell Willsimport java.lang.reflect.Field; 2941e38d84f562e12198f7db0d45f633712cae6cbaMitchell Willsimport java.lang.reflect.InvocationTargetException; 3041e38d84f562e12198f7db0d45f633712cae6cbaMitchell Willsimport java.lang.reflect.Method; 3141e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills 3241e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills/** 3341e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills * Creates a looper whose message queue can be manipulated 3441e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills * This allows testing code that uses a looper to dispatch messages in a deterministic manner 3541e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills * Creating a MockLooper will also install it as the looper for the current thread 3641e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills */ 3741e38d84f562e12198f7db0d45f633712cae6cbaMitchell Willspublic class MockLooper { 38e1e1c7317e5e5d61daf90cd2f2861305f19890b7Etan Cohen protected final Looper mLooper; 3941e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills 4072c639e8b97067e948eca8be50dfea3173121090Mitchell Wills private static final Constructor<Looper> LOOPER_CONSTRUCTOR; 4172c639e8b97067e948eca8be50dfea3173121090Mitchell Wills private static final Field THREAD_LOCAL_LOOPER_FIELD; 42b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen private static final Field MESSAGE_QUEUE_MESSAGES_FIELD; 43b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen private static final Field MESSAGE_NEXT_FIELD; 44b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen private static final Field MESSAGE_WHEN_FIELD; 45b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen private static final Method MESSAGE_MARK_IN_USE_METHOD; 46d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein private static final String TAG = "MockLooper"; 47d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein 48d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein private AutoDispatchThread mAutoDispatchThread; 4941e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills 5041e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills static { 5141e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills try { 5272c639e8b97067e948eca8be50dfea3173121090Mitchell Wills LOOPER_CONSTRUCTOR = Looper.class.getDeclaredConstructor(Boolean.TYPE); 5372c639e8b97067e948eca8be50dfea3173121090Mitchell Wills LOOPER_CONSTRUCTOR.setAccessible(true); 5472c639e8b97067e948eca8be50dfea3173121090Mitchell Wills THREAD_LOCAL_LOOPER_FIELD = Looper.class.getDeclaredField("sThreadLocal"); 5572c639e8b97067e948eca8be50dfea3173121090Mitchell Wills THREAD_LOCAL_LOOPER_FIELD.setAccessible(true); 56b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen MESSAGE_QUEUE_MESSAGES_FIELD = MessageQueue.class.getDeclaredField("mMessages"); 57b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen MESSAGE_QUEUE_MESSAGES_FIELD.setAccessible(true); 58b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen MESSAGE_NEXT_FIELD = Message.class.getDeclaredField("next"); 59b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen MESSAGE_NEXT_FIELD.setAccessible(true); 60b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen MESSAGE_WHEN_FIELD = Message.class.getDeclaredField("when"); 61b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen MESSAGE_WHEN_FIELD.setAccessible(true); 62b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen MESSAGE_MARK_IN_USE_METHOD = Message.class.getDeclaredMethod("markInUse"); 63b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen MESSAGE_MARK_IN_USE_METHOD.setAccessible(true); 6472c639e8b97067e948eca8be50dfea3173121090Mitchell Wills } catch (NoSuchFieldException | NoSuchMethodException e) { 6541e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills throw new RuntimeException("Failed to initialize MockLooper", e); 6641e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills } 6741e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills } 6841e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills 6941e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills 70e1e1c7317e5e5d61daf90cd2f2861305f19890b7Etan Cohen public MockLooper() { 71e1e1c7317e5e5d61daf90cd2f2861305f19890b7Etan Cohen try { 72e1e1c7317e5e5d61daf90cd2f2861305f19890b7Etan Cohen mLooper = LOOPER_CONSTRUCTOR.newInstance(false); 7341e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills 74e1e1c7317e5e5d61daf90cd2f2861305f19890b7Etan Cohen ThreadLocal<Looper> threadLocalLooper = (ThreadLocal<Looper>) THREAD_LOCAL_LOOPER_FIELD 75e1e1c7317e5e5d61daf90cd2f2861305f19890b7Etan Cohen .get(null); 76e1e1c7317e5e5d61daf90cd2f2861305f19890b7Etan Cohen threadLocalLooper.set(mLooper); 77e1e1c7317e5e5d61daf90cd2f2861305f19890b7Etan Cohen } catch (IllegalAccessException | InstantiationException | InvocationTargetException e) { 78e1e1c7317e5e5d61daf90cd2f2861305f19890b7Etan Cohen throw new RuntimeException("Reflection error constructing or accessing looper", e); 79e1e1c7317e5e5d61daf90cd2f2861305f19890b7Etan Cohen } 8041e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills } 8141e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills 8241e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills public Looper getLooper() { 8341e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills return mLooper; 8441e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills } 8541e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills 86b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen private Message getMessageLinkedList() { 8741e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills try { 88b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen MessageQueue queue = mLooper.getQueue(); 89b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen return (Message) MESSAGE_QUEUE_MESSAGES_FIELD.get(queue); 90b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen } catch (IllegalAccessException e) { 91b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen throw new RuntimeException("Access failed in MockLooper: get - MessageQueue.mMessages", 92b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen e); 93b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen } 94b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen } 95b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen 96b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen public void moveTimeForward(long milliSeconds) { 97b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen try { 98b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen Message msg = getMessageLinkedList(); 99b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen while (msg != null) { 100b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen long updatedWhen = msg.getWhen() - milliSeconds; 101b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen if (updatedWhen < 0) { 102b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen updatedWhen = 0; 103b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen } 104b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen MESSAGE_WHEN_FIELD.set(msg, updatedWhen); 105b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen msg = (Message) MESSAGE_NEXT_FIELD.get(msg); 106b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen } 107b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen } catch (IllegalAccessException e) { 108b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen throw new RuntimeException("Access failed in MockLooper: set - Message.when", e); 109b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen } 110b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen } 111b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen 112b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen private Message messageQueueNext() { 113b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen try { 114b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen long now = SystemClock.uptimeMillis(); 115b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen 116b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen Message prevMsg = null; 117b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen Message msg = getMessageLinkedList(); 118b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen if (msg != null && msg.getTarget() == null) { 119b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen // Stalled by a barrier. Find the next asynchronous message in 120b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen // the queue. 121b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen do { 122b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen prevMsg = msg; 123b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen msg = (Message) MESSAGE_NEXT_FIELD.get(msg); 124b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen } while (msg != null && !msg.isAsynchronous()); 125b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen } 126b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen if (msg != null) { 127b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen if (now >= msg.getWhen()) { 128b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen // Got a message. 129b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen if (prevMsg != null) { 130b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen MESSAGE_NEXT_FIELD.set(prevMsg, MESSAGE_NEXT_FIELD.get(msg)); 131b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen } else { 132b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen MESSAGE_QUEUE_MESSAGES_FIELD.set(mLooper.getQueue(), 133b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen MESSAGE_NEXT_FIELD.get(msg)); 134b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen } 135b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen MESSAGE_NEXT_FIELD.set(msg, null); 136b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen MESSAGE_MARK_IN_USE_METHOD.invoke(msg); 137b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen return msg; 138b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen } 139b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen } 14072c639e8b97067e948eca8be50dfea3173121090Mitchell Wills } catch (IllegalAccessException | InvocationTargetException e) { 141b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen throw new RuntimeException("Access failed in MockLooper", e); 14241e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills } 143b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen 144b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen return null; 14541e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills } 14641e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills 14741e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills /** 14841e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills * @return true if there are pending messages in the message queue 14941e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills */ 150d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein public synchronized boolean isIdle() { 151b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen Message messageList = getMessageLinkedList(); 152b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen 153b35c2105231b61606db78d4bf8a75ec31039db61Etan Cohen return messageList != null && SystemClock.uptimeMillis() >= messageList.getWhen(); 15441e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills } 15541e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills 15641e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills /** 15741e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills * @return the next message in the Looper's message queue or null if there is none 15841e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills */ 159d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein public synchronized Message nextMessage() { 160e1e1c7317e5e5d61daf90cd2f2861305f19890b7Etan Cohen if (isIdle()) { 16141e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills return messageQueueNext(); 16272c639e8b97067e948eca8be50dfea3173121090Mitchell Wills } else { 16341e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills return null; 16441e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills } 16541e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills } 16641e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills 16741e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills /** 16841e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills * Dispatch the next message in the queue 16941e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills * Asserts that there is a message in the queue 17041e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills */ 171d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein public synchronized void dispatchNext() { 172e1e1c7317e5e5d61daf90cd2f2861305f19890b7Etan Cohen assertTrue(isIdle()); 17341e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills Message msg = messageQueueNext(); 17441e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills if (msg == null) { 17541e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills return; 17641e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills } 17741e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills msg.getTarget().dispatchMessage(msg); 17841e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills } 17941e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills 18041e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills /** 18141e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills * Dispatch all messages currently in the queue 18241e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills * Will not fail if there are no messages pending 18341e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills * @return the number of messages dispatched 18441e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills */ 185d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein public synchronized int dispatchAll() { 18641e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills int count = 0; 187e1e1c7317e5e5d61daf90cd2f2861305f19890b7Etan Cohen while (isIdle()) { 18841e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills dispatchNext(); 18941e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills ++count; 19041e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills } 19141e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills return count; 19241e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills } 193d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein 194d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein /** 195d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein * Thread used to dispatch messages when the main thread is blocked waiting for a response. 196d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein */ 197d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein private class AutoDispatchThread extends Thread { 198d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein private static final int MAX_LOOPS = 100; 199d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein private static final int LOOP_SLEEP_TIME_MS = 10; 200d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein 201d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein private RuntimeException mAutoDispatchException = null; 202d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein 203d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein /** 204d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein * Run method for the auto dispatch thread. 205d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein * The thread loops a maximum of MAX_LOOPS times with a 10ms sleep between loops. 206d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein * The thread continues looping and attempting to dispatch all messages until at 207d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein * least one message has been dispatched. 208d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein */ 209d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein @Override 210d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein public void run() { 211d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein int dispatchCount = 0; 212d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein for (int i = 0; i < MAX_LOOPS; i++) { 213d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein try { 214d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein dispatchCount = dispatchAll(); 215d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein } catch (RuntimeException e) { 216d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein mAutoDispatchException = e; 217d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein } 218d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein Log.d(TAG, "dispatched " + dispatchCount + " messages"); 219d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein if (dispatchCount > 0) { 220d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein return; 221d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein } 222d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein try { 223d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein Thread.sleep(LOOP_SLEEP_TIME_MS); 224d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein } catch (InterruptedException e) { 225d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein mAutoDispatchException = new IllegalStateException( 226d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein "stopAutoDispatch called before any messages were dispatched."); 227d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein return; 228d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein } 229d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein } 230d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein Log.e(TAG, "AutoDispatchThread did not dispatch any messages."); 231d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein mAutoDispatchException = new IllegalStateException( 232d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein "MockLooper did not dispatch any messages before exiting."); 233d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein } 234d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein 235d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein /** 236d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein * Method allowing the MockLooper to pass any exceptions thrown by the thread to be passed 237d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein * to the main thread. 238d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein * 239d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein * @return RuntimeException Exception created by stopping without dispatching a message 240d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein */ 241d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein public RuntimeException getException() { 242d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein return mAutoDispatchException; 243d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein } 244d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein } 245d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein 246d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein /** 247d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein * Create and start a new AutoDispatchThread if one is not already running. 248d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein */ 249d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein public void startAutoDispatch() { 250d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein if (mAutoDispatchThread != null) { 251d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein throw new IllegalStateException( 252d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein "startAutoDispatch called with the AutoDispatchThread already running."); 253d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein } 254d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein mAutoDispatchThread = new AutoDispatchThread(); 255d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein mAutoDispatchThread.start(); 256d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein } 257d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein 258d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein /** 259d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein * If an AutoDispatchThread is currently running, stop and clean up. 260d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein */ 261d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein public void stopAutoDispatch() { 262d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein if (mAutoDispatchThread != null) { 263d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein if (mAutoDispatchThread.isAlive()) { 264d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein mAutoDispatchThread.interrupt(); 265d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein } 266d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein try { 267d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein mAutoDispatchThread.join(); 268d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein } catch (InterruptedException e) { 269d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein // Catch exception from join. 270d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein } 271d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein 272d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein RuntimeException e = mAutoDispatchThread.getException(); 273d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein mAutoDispatchThread = null; 274d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein if (e != null) { 275d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein throw e; 276d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein } 277d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein } else { 278d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein // stopAutoDispatch was called when startAutoDispatch has not created a new thread. 279d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein throw new IllegalStateException( 280d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein "stopAutoDispatch called without startAutoDispatch."); 281d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein } 282d0846fa841b604ccb969c54b45367fa2bececf83Rebecca Silberstein } 28341e38d84f562e12198f7db0d45f633712cae6cbaMitchell Wills} 284