1 // Copyright 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.base; 6 7 import android.os.Handler; 8 import android.os.Looper; 9 import android.os.Process; 10 11 import java.util.concurrent.Callable; 12 import java.util.concurrent.ExecutionException; 13 import java.util.concurrent.FutureTask; 14 15 /** 16 * Helper methods to deal with threading related tasks. 17 */ 18 public class ThreadUtils { 19 20 private static final Object sLock = new Object(); 21 22 private static boolean sWillOverride = false; 23 24 private static Handler sUiThreadHandler = null; 25 setWillOverrideUiThread()26 public static void setWillOverrideUiThread() { 27 synchronized (sLock) { 28 sWillOverride = true; 29 } 30 } 31 setUiThread(Looper looper)32 public static void setUiThread(Looper looper) { 33 synchronized (sLock) { 34 if (sUiThreadHandler != null && sUiThreadHandler.getLooper() != looper) { 35 throw new RuntimeException("UI thread looper is already set to " + 36 sUiThreadHandler.getLooper() + " (Main thread looper is " + 37 Looper.getMainLooper() + "), cannot set to new looper " + looper); 38 } else { 39 sUiThreadHandler = new Handler(looper); 40 } 41 } 42 } 43 getUiThreadHandler()44 private static Handler getUiThreadHandler() { 45 synchronized (sLock) { 46 if (sUiThreadHandler == null) { 47 if (sWillOverride) { 48 throw new RuntimeException("Did not yet override the UI thread"); 49 } 50 sUiThreadHandler = new Handler(Looper.getMainLooper()); 51 } 52 return sUiThreadHandler; 53 } 54 } 55 56 /** 57 * Run the supplied Runnable on the main thread. The method will block until the Runnable 58 * completes. 59 * 60 * @param r The Runnable to run. 61 */ runOnUiThreadBlocking(final Runnable r)62 public static void runOnUiThreadBlocking(final Runnable r) { 63 if (runningOnUiThread()) { 64 r.run(); 65 } else { 66 FutureTask<Void> task = new FutureTask<Void>(r, null); 67 postOnUiThread(task); 68 try { 69 task.get(); 70 } catch (Exception e) { 71 throw new RuntimeException("Exception occured while waiting for runnable", e); 72 } 73 } 74 } 75 76 /** 77 * Run the supplied Callable on the main thread, wrapping any exceptions in a RuntimeException. 78 * The method will block until the Callable completes. 79 * 80 * @param c The Callable to run 81 * @return The result of the callable 82 */ runOnUiThreadBlockingNoException(Callable<T> c)83 public static <T> T runOnUiThreadBlockingNoException(Callable<T> c) { 84 try { 85 return runOnUiThreadBlocking(c); 86 } catch (ExecutionException e) { 87 throw new RuntimeException("Error occured waiting for callable", e); 88 } 89 } 90 91 /** 92 * Run the supplied Callable on the main thread, The method will block until the Callable 93 * completes. 94 * 95 * @param c The Callable to run 96 * @return The result of the callable 97 * @throws ExecutionException c's exception 98 */ runOnUiThreadBlocking(Callable<T> c)99 public static <T> T runOnUiThreadBlocking(Callable<T> c) throws ExecutionException { 100 FutureTask<T> task = new FutureTask<T>(c); 101 runOnUiThread(task); 102 try { 103 return task.get(); 104 } catch (InterruptedException e) { 105 throw new RuntimeException("Interrupted waiting for callable", e); 106 } 107 } 108 109 /** 110 * Run the supplied FutureTask on the main thread. The method will block only if the current 111 * thread is the main thread. 112 * 113 * @param task The FutureTask to run 114 * @return The queried task (to aid inline construction) 115 */ runOnUiThread(FutureTask<T> task)116 public static <T> FutureTask<T> runOnUiThread(FutureTask<T> task) { 117 if (runningOnUiThread()) { 118 task.run(); 119 } else { 120 postOnUiThread(task); 121 } 122 return task; 123 } 124 125 /** 126 * Run the supplied Callable on the main thread. The method will block only if the current 127 * thread is the main thread. 128 * 129 * @param c The Callable to run 130 * @return A FutureTask wrapping the callable to retrieve results 131 */ runOnUiThread(Callable<T> c)132 public static <T> FutureTask<T> runOnUiThread(Callable<T> c) { 133 return runOnUiThread(new FutureTask<T>(c)); 134 } 135 136 /** 137 * Run the supplied Runnable on the main thread. The method will block only if the current 138 * thread is the main thread. 139 * 140 * @param r The Runnable to run 141 */ runOnUiThread(Runnable r)142 public static void runOnUiThread(Runnable r) { 143 if (runningOnUiThread()) { 144 r.run(); 145 } else { 146 getUiThreadHandler().post(r); 147 } 148 } 149 150 /** 151 * Post the supplied FutureTask to run on the main thread. The method will not block, even if 152 * called on the UI thread. 153 * 154 * @param task The FutureTask to run 155 * @return The queried task (to aid inline construction) 156 */ postOnUiThread(FutureTask<T> task)157 public static <T> FutureTask<T> postOnUiThread(FutureTask<T> task) { 158 getUiThreadHandler().post(task); 159 return task; 160 } 161 162 /** 163 * Post the supplied Runnable to run on the main thread. The method will not block, even if 164 * called on the UI thread. 165 * 166 * @param task The Runnable to run 167 */ postOnUiThread(Runnable task)168 public static void postOnUiThread(Runnable task) { 169 getUiThreadHandler().post(task); 170 } 171 172 /** 173 * Post the supplied Runnable to run on the main thread after the given amount of time. The 174 * method will not block, even if called on the UI thread. 175 * 176 * @param task The Runnable to run 177 * @param delayMillis The delay in milliseconds until the Runnable will be run 178 */ postOnUiThreadDelayed(Runnable task, long delayMillis)179 public static void postOnUiThreadDelayed(Runnable task, long delayMillis) { 180 getUiThreadHandler().postDelayed(task, delayMillis); 181 } 182 183 /** 184 * Asserts that the current thread is running on the main thread. 185 */ assertOnUiThread()186 public static void assertOnUiThread() { 187 assert runningOnUiThread(); 188 } 189 190 /** 191 * @return true iff the current thread is the main (UI) thread. 192 */ runningOnUiThread()193 public static boolean runningOnUiThread() { 194 return getUiThreadHandler().getLooper() == Looper.myLooper(); 195 } 196 getUiThreadLooper()197 public static Looper getUiThreadLooper() { 198 return getUiThreadHandler().getLooper(); 199 } 200 201 /** 202 * Set thread priority to audio. 203 */ 204 @CalledByNative setThreadPriorityAudio(int tid)205 public static void setThreadPriorityAudio(int tid) { 206 Process.setThreadPriority(tid, Process.THREAD_PRIORITY_AUDIO); 207 } 208 } 209