1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package libcore.java.lang; 18 19import java.lang.Thread.UncaughtExceptionHandler; 20import java.util.concurrent.atomic.AtomicInteger; 21import java.util.concurrent.atomic.AtomicBoolean; 22import java.util.concurrent.locks.ReentrantLock; 23 24import junit.framework.Assert; 25import junit.framework.TestCase; 26 27import org.mockito.InOrder; 28import org.mockito.Mockito; 29 30import libcore.java.lang.ref.FinalizationTester; 31 32public final class ThreadTest extends TestCase { 33 static { 34 System.loadLibrary("javacoretests"); 35 } 36 37 /** 38 * getContextClassLoader returned a non-application class loader. 39 * http://code.google.com/p/android/issues/detail?id=5697 40 */ 41 public void testJavaContextClassLoader() throws Exception { 42 Assert.assertNotNull("Must have a Java context ClassLoader", 43 Thread.currentThread().getContextClassLoader()); 44 } 45 46 public void testLeakingStartedThreads() { 47 final AtomicInteger finalizedThreadsCount = new AtomicInteger(); 48 for (int i = 0; true; i++) { 49 try { 50 newThread(finalizedThreadsCount, 1024 << i).start(); 51 } catch (OutOfMemoryError expected) { 52 break; 53 } 54 } 55 FinalizationTester.induceFinalization(); 56 assertTrue("Started threads were never finalized!", finalizedThreadsCount.get() > 0); 57 } 58 59 public void testLeakingUnstartedThreads() { 60 final AtomicInteger finalizedThreadsCount = new AtomicInteger(); 61 for (int i = 0; true; i++) { 62 try { 63 newThread(finalizedThreadsCount, 1024 << i); 64 } catch (OutOfMemoryError expected) { 65 break; 66 } 67 } 68 FinalizationTester.induceFinalization(); 69 assertTrue("Unstarted threads were never finalized!", finalizedThreadsCount.get() > 0); 70 } 71 72 public void testThreadSleep() throws Exception { 73 int millis = 1000; 74 long start = System.currentTimeMillis(); 75 76 Thread.sleep(millis); 77 78 long elapsed = System.currentTimeMillis() - start; 79 long offBy = Math.abs(elapsed - millis); 80 81 assertTrue("Actual sleep off by " + offBy + " ms", offBy <= 250); 82 } 83 84 public void testThreadInterrupted() throws Exception { 85 Thread.currentThread().interrupt(); 86 try { 87 Thread.sleep(0); 88 fail(); 89 } catch (InterruptedException e) { 90 assertFalse(Thread.currentThread().isInterrupted()); 91 } 92 } 93 94 public void testThreadSleepIllegalArguments() throws Exception { 95 96 try { 97 Thread.sleep(-1); 98 fail(); 99 } catch (IllegalArgumentException expected) { 100 } 101 102 try { 103 Thread.sleep(0, -1); 104 fail(); 105 } catch (IllegalArgumentException expected) { 106 } 107 108 try { 109 Thread.sleep(0, 1000000); 110 fail(); 111 } catch (IllegalArgumentException expected) { 112 } 113 } 114 115 public void testThreadWakeup() throws Exception { 116 WakeupTestThread t1 = new WakeupTestThread(); 117 WakeupTestThread t2 = new WakeupTestThread(); 118 119 t1.start(); 120 t2.start(); 121 assertTrue("Threads already finished", !t1.done && !t2.done); 122 123 t1.interrupt(); 124 t2.interrupt(); 125 126 Thread.sleep(1000); 127 assertTrue("Threads did not finish", t1.done && t2.done); 128 } 129 130 public void testContextClassLoaderIsNotNull() { 131 assertNotNull(Thread.currentThread().getContextClassLoader()); 132 } 133 134 public void testContextClassLoaderIsInherited() { 135 Thread other = new Thread(); 136 assertSame(Thread.currentThread().getContextClassLoader(), other.getContextClassLoader()); 137 } 138 139 public void testUncaughtExceptionPreHandler_calledBeforeDefaultHandler() { 140 UncaughtExceptionHandler initialHandler = Mockito.mock(UncaughtExceptionHandler.class); 141 UncaughtExceptionHandler defaultHandler = Mockito.mock(UncaughtExceptionHandler.class); 142 InOrder inOrder = Mockito.inOrder(initialHandler, defaultHandler); 143 144 UncaughtExceptionHandler originalDefaultHandler 145 = Thread.getDefaultUncaughtExceptionHandler(); 146 Thread.setUncaughtExceptionPreHandler(initialHandler); 147 Thread.setDefaultUncaughtExceptionHandler(defaultHandler); 148 try { 149 Thread t = new Thread(); 150 Throwable e = new Throwable(); 151 t.dispatchUncaughtException(e); 152 inOrder.verify(initialHandler).uncaughtException(t, e); 153 inOrder.verify(defaultHandler).uncaughtException(t, e); 154 inOrder.verifyNoMoreInteractions(); 155 } finally { 156 Thread.setDefaultUncaughtExceptionHandler(originalDefaultHandler); 157 Thread.setUncaughtExceptionPreHandler(null); 158 } 159 } 160 161 public void testUncaughtExceptionPreHandler_noDefaultHandler() { 162 UncaughtExceptionHandler initialHandler = Mockito.mock(UncaughtExceptionHandler.class); 163 UncaughtExceptionHandler originalDefaultHandler 164 = Thread.getDefaultUncaughtExceptionHandler(); 165 Thread.setUncaughtExceptionPreHandler(initialHandler); 166 Thread.setDefaultUncaughtExceptionHandler(null); 167 try { 168 Thread t = new Thread(); 169 Throwable e = new Throwable(); 170 t.dispatchUncaughtException(e); 171 Mockito.verify(initialHandler).uncaughtException(t, e); 172 Mockito.verifyNoMoreInteractions(initialHandler); 173 } finally { 174 Thread.setDefaultUncaughtExceptionHandler(originalDefaultHandler); 175 Thread.setUncaughtExceptionPreHandler(null); 176 } 177 } 178 179 /** 180 * Thread.getStackTrace() is broken. http://b/1252043 181 */ 182 public void testGetStackTrace() throws Exception { 183 Thread t1 = new Thread("t1") { 184 @Override public void run() { 185 doSomething(); 186 } 187 public void doSomething() { 188 try { 189 Thread.sleep(4000); 190 } catch (InterruptedException ignored) { 191 } 192 } 193 }; 194 t1.start(); 195 Thread.sleep(1000); 196 StackTraceElement[] traces = t1.getStackTrace(); 197 StackTraceElement trace = traces[traces.length - 2]; 198 199 // Expect to find MyThread.doSomething in the trace 200 assertTrue(trace.getClassName().contains("ThreadTest") 201 && trace.getMethodName().equals("doSomething")); 202 t1.join(); 203 } 204 205 public void testGetAllStackTracesIncludesAllGroups() throws Exception { 206 final AtomicInteger visibleTraces = new AtomicInteger(); 207 ThreadGroup group = new ThreadGroup("1"); 208 Thread t2 = new Thread(group, "t2") { 209 @Override public void run() { 210 visibleTraces.set(Thread.getAllStackTraces().size()); 211 } 212 }; 213 t2.start(); 214 t2.join(); 215 216 // Expect to see the traces of all threads (not just t2) 217 assertTrue("Must have traces for all threads", visibleTraces.get() > 1); 218 } 219 220 // http://b/27748318 221 public void testNativeThreadNames() throws Exception { 222 String testResult = nativeTestNativeThreadNames(); 223 // Not using assertNull here because this results in a better error message. 224 if (testResult != null) { 225 fail(testResult); 226 } 227 } 228 229 // http://b/29746125 230 public void testParkUntilWithUnderflowValue() throws Exception { 231 final Thread current = Thread.currentThread(); 232 233 // watchdog to unpark the tread in case it will be parked 234 AtomicBoolean afterPark = new AtomicBoolean(false); 235 AtomicBoolean wasParkedForLongTime = new AtomicBoolean(false); 236 Thread watchdog = new Thread() { 237 @Override public void run() { 238 try { 239 sleep(5000); 240 } catch(InterruptedException expected) {} 241 242 if (!afterPark.get()) { 243 wasParkedForLongTime.set(true); 244 current.unpark$(); 245 } 246 } 247 }; 248 watchdog.start(); 249 250 // b/29746125 is caused by underflow: parkUntilArg - System.currentTimeMillis() > 0. 251 // parkUntil$ should return immediately for everyargument that's <= 252 // System.currentTimeMillis(). 253 current.parkUntil$(Long.MIN_VALUE); 254 if (wasParkedForLongTime.get()) { 255 fail("Current thread was parked, but was expected to return immediately"); 256 } 257 afterPark.set(true); 258 watchdog.interrupt(); 259 watchdog.join(); 260 } 261 262 /** 263 * Check that call Thread.start for already started thread 264 * throws {@code IllegalThreadStateException} 265 */ 266 public void testThreadDoubleStart() { 267 final ReentrantLock lock = new ReentrantLock(); 268 Thread thread = new Thread() { 269 public void run() { 270 // Lock should be acquired by the main thread and 271 // this thread should block on this operation. 272 lock.lock(); 273 } 274 }; 275 // Acquire lock to ensure that new thread is not finished 276 // when we call start() second time. 277 lock.lock(); 278 try { 279 thread.start(); 280 try { 281 thread.start(); 282 fail(); 283 } catch (IllegalThreadStateException expected) { 284 } 285 } finally { 286 lock.unlock(); 287 } 288 try { 289 thread.join(); 290 } catch (InterruptedException ignored) { 291 } 292 } 293 294 /** 295 * Check that call Thread.start for already finished thread 296 * throws {@code IllegalThreadStateException} 297 */ 298 public void testThreadRestart() { 299 Thread thread = new Thread(); 300 thread.start(); 301 try { 302 thread.join(); 303 } catch (InterruptedException ignored) { 304 } 305 try { 306 thread.start(); 307 fail(); 308 } catch (IllegalThreadStateException expected) { 309 } 310 } 311 312 // This method returns {@code null} if all tests pass, or a non-null String containing 313 // failure details if an error occured. 314 private static native String nativeTestNativeThreadNames(); 315 316 private Thread newThread(final AtomicInteger finalizedThreadsCount, final int size) { 317 return new Thread() { 318 long[] memoryPressure = new long[size]; 319 @Override protected void finalize() throws Throwable { 320 super.finalize(); 321 finalizedThreadsCount.incrementAndGet(); 322 } 323 }; 324 } 325 326 private class WakeupTestThread extends Thread { 327 public boolean done; 328 329 public void run() { 330 done = false; 331 332 // Sleep for a while (1 min) 333 try { 334 Thread.sleep(60000); 335 } catch (InterruptedException ignored) { 336 } 337 338 done = true; 339 } 340 } 341} 342