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