mobile/android/base/util/ThreadUtils.java

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     4  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 package org.mozilla.gecko.util;
     8 import java.util.Map;
    10 import android.os.Handler;
    11 import android.os.MessageQueue;
    12 import android.util.Log;
    14 public final class ThreadUtils {
    15     private static final String LOGTAG = "ThreadUtils";
    17     /**
    18      * Controls the action taken when a method like
    19      * {@link ThreadUtils#assertOnUiThread(AssertBehavior)} detects a problem.
    20      */
    21     public static enum AssertBehavior {
    22         NONE,
    23         THROW,
    24     }
    26     private static volatile Thread sUiThread;
    27     private static volatile Thread sBackgroundThread;
    29     private static Handler sUiHandler;
    31     // Referenced directly from GeckoAppShell in highly performance-sensitive code (The extra
    32     // function call of the getter was harming performance. (Bug 897123))
    33     // Once Bug 709230 is resolved we should reconsider this as ProGuard should be able to optimise
    34     // this out at compile time.
    35     public static Handler sGeckoHandler;
    36     public static MessageQueue sGeckoQueue;
    37     public static Thread sGeckoThread;
    39     // Delayed Runnable that resets the Gecko thread priority.
    40     private static final Runnable sPriorityResetRunnable = new Runnable() {
    41         @Override
    42         public void run() {
    43             resetGeckoPriority();
    44         }
    45     };
    47     private static boolean sIsGeckoPriorityReduced;
    49     @SuppressWarnings("serial")
    50     public static class UiThreadBlockedException extends RuntimeException {
    51         public UiThreadBlockedException() {
    52             super();
    53         }
    55         public UiThreadBlockedException(String msg) {
    56             super(msg);
    57         }
    59         public UiThreadBlockedException(String msg, Throwable e) {
    60             super(msg, e);
    61         }
    63         public UiThreadBlockedException(Throwable e) {
    64             super(e);
    65         }
    66     }
    68     public static void dumpAllStackTraces() {
    69         Log.w(LOGTAG, "Dumping ALL the threads!");
    70         Map<Thread, StackTraceElement[]> allStacks = Thread.getAllStackTraces();
    71         for (Thread t : allStacks.keySet()) {
    72             Log.w(LOGTAG, t.toString());
    73             for (StackTraceElement ste : allStacks.get(t)) {
    74                 Log.w(LOGTAG, ste.toString());
    75             }
    76             Log.w(LOGTAG, "----");
    77         }
    78     }
    80     public static void setUiThread(Thread thread, Handler handler) {
    81         sUiThread = thread;
    82         sUiHandler = handler;
    83     }
    85     public static void setBackgroundThread(Thread thread) {
    86         sBackgroundThread = thread;
    87     }
    89     public static Thread getUiThread() {
    90         return sUiThread;
    91     }
    93     public static Handler getUiHandler() {
    94         return sUiHandler;
    95     }
    97     public static void postToUiThread(Runnable runnable) {
    98         sUiHandler.post(runnable);
    99     }
   101     public static Thread getBackgroundThread() {
   102         return sBackgroundThread;
   103     }
   105     public static Handler getBackgroundHandler() {
   106         return GeckoBackgroundThread.getHandler();
   107     }
   109     public static void postToBackgroundThread(Runnable runnable) {
   110         GeckoBackgroundThread.post(runnable);
   111     }
   113     public static void assertOnUiThread(final AssertBehavior assertBehavior) {
   114         assertOnThread(getUiThread(), assertBehavior);
   115     }
   117     public static void assertOnUiThread() {
   118         assertOnThread(getUiThread(), AssertBehavior.THROW);
   119     }
   121     public static void assertOnGeckoThread() {
   122         assertOnThread(sGeckoThread, AssertBehavior.THROW);
   123     }
   125     public static void assertOnBackgroundThread() {
   126         assertOnThread(getBackgroundThread(), AssertBehavior.THROW);
   127     }
   129     public static void assertOnThread(final Thread expectedThread) {
   130         assertOnThread(expectedThread, AssertBehavior.THROW);
   131     }
   133     public static void assertOnThread(final Thread expectedThread, AssertBehavior behavior) {
   134         final Thread currentThread = Thread.currentThread();
   135         final long currentThreadId = currentThread.getId();
   136         final long expectedThreadId = expectedThread.getId();
   138         if (currentThreadId == expectedThreadId) {
   139             return;
   140         }
   142         final String message = "Expected thread " +
   143                                expectedThreadId + " (\"" + expectedThread.getName() +
   144                                "\"), but running on thread " +
   145                                currentThreadId + " (\"" + currentThread.getName() + ")";
   146         final IllegalThreadStateException e = new IllegalThreadStateException(message);
   148         switch (behavior) {
   149         case THROW:
   150             throw e;
   151         default:
   152             Log.e(LOGTAG, "Method called on wrong thread!", e);
   153         }
   154     }
   156     public static boolean isOnUiThread() {
   157         return isOnThread(getUiThread());
   158     }
   160     public static boolean isOnBackgroundThread() {
   161         if (sBackgroundThread == null) {
   162             return false;
   163         }
   165         return isOnThread(sBackgroundThread);
   166     }
   168     public static boolean isOnThread(Thread thread) {
   169         return (Thread.currentThread().getId() == thread.getId());
   170     }
   172     /**
   173      * Reduces the priority of the Gecko thread, allowing other operations
   174      * (such as those related to the UI and database) to take precedence.
   175      *
   176      * Note that there are no guards in place to prevent multiple calls
   177      * to this method from conflicting with each other.
   178      *
   179      * @param timeout Timeout in ms after which the priority will be reset
   180      */
   181     public static void reduceGeckoPriority(long timeout) {
   182         if (!sIsGeckoPriorityReduced) {
   183             sIsGeckoPriorityReduced = true;
   184             sGeckoThread.setPriority(Thread.MIN_PRIORITY);
   185             getUiHandler().postDelayed(sPriorityResetRunnable, timeout);
   186         }
   187     }
   189     /**
   190      * Resets the priority of a thread whose priority has been reduced
   191      * by reduceGeckoPriority.
   192      */
   193     public static void resetGeckoPriority() {
   194         if (sIsGeckoPriorityReduced) {
   195             sIsGeckoPriorityReduced = false;
   196             sGeckoThread.setPriority(Thread.NORM_PRIORITY);
   197             getUiHandler().removeCallbacks(sPriorityResetRunnable);
   198         }
   199     }
   200 }

mercurial