Home | History | Annotate | Download | only in base
      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 
     28     public static void setWillOverrideUiThread() {
     29         synchronized (sLock) {
     30             sWillOverride = true;
     31         }
     32     }
     33 
     34     @VisibleForTesting
     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 
     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      */
     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
     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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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
    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      */
    191     public static void assertOnUiThread() {
    192         assert runningOnUiThread();
    193     }
    194 
    195     /**
    196      * @return true iff the current thread is the main (UI) thread.
    197      */
    198     public static boolean runningOnUiThread() {
    199         return getUiThreadHandler().getLooper() == Looper.myLooper();
    200     }
    201 
    202     public static Looper getUiThreadLooper() {
    203         return getUiThreadHandler().getLooper();
    204     }
    205 
    206     /**
    207      * Set thread priority to audio.
    208      */
    209     @CalledByNative
    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
    220     private static boolean isThreadPriorityAudio(int tid) {
    221         return Process.getThreadPriority(tid) == Process.THREAD_PRIORITY_AUDIO;
    222     }
    223 }
    224