• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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