mobile/android/base/util/ThreadUtils.java

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/mobile/android/base/util/ThreadUtils.java	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,200 @@
     1.4 +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
     1.5 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     1.7 + * You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +package org.mozilla.gecko.util;
    1.10 +
    1.11 +import java.util.Map;
    1.12 +
    1.13 +import android.os.Handler;
    1.14 +import android.os.MessageQueue;
    1.15 +import android.util.Log;
    1.16 +
    1.17 +public final class ThreadUtils {
    1.18 +    private static final String LOGTAG = "ThreadUtils";
    1.19 +
    1.20 +    /**
    1.21 +     * Controls the action taken when a method like
    1.22 +     * {@link ThreadUtils#assertOnUiThread(AssertBehavior)} detects a problem.
    1.23 +     */
    1.24 +    public static enum AssertBehavior {
    1.25 +        NONE,
    1.26 +        THROW,
    1.27 +    }
    1.28 +
    1.29 +    private static volatile Thread sUiThread;
    1.30 +    private static volatile Thread sBackgroundThread;
    1.31 +
    1.32 +    private static Handler sUiHandler;
    1.33 +
    1.34 +    // Referenced directly from GeckoAppShell in highly performance-sensitive code (The extra
    1.35 +    // function call of the getter was harming performance. (Bug 897123))
    1.36 +    // Once Bug 709230 is resolved we should reconsider this as ProGuard should be able to optimise
    1.37 +    // this out at compile time.
    1.38 +    public static Handler sGeckoHandler;
    1.39 +    public static MessageQueue sGeckoQueue;
    1.40 +    public static Thread sGeckoThread;
    1.41 +
    1.42 +    // Delayed Runnable that resets the Gecko thread priority.
    1.43 +    private static final Runnable sPriorityResetRunnable = new Runnable() {
    1.44 +        @Override
    1.45 +        public void run() {
    1.46 +            resetGeckoPriority();
    1.47 +        }
    1.48 +    };
    1.49 +
    1.50 +    private static boolean sIsGeckoPriorityReduced;
    1.51 +
    1.52 +    @SuppressWarnings("serial")
    1.53 +    public static class UiThreadBlockedException extends RuntimeException {
    1.54 +        public UiThreadBlockedException() {
    1.55 +            super();
    1.56 +        }
    1.57 +
    1.58 +        public UiThreadBlockedException(String msg) {
    1.59 +            super(msg);
    1.60 +        }
    1.61 +
    1.62 +        public UiThreadBlockedException(String msg, Throwable e) {
    1.63 +            super(msg, e);
    1.64 +        }
    1.65 +
    1.66 +        public UiThreadBlockedException(Throwable e) {
    1.67 +            super(e);
    1.68 +        }
    1.69 +    }
    1.70 +
    1.71 +    public static void dumpAllStackTraces() {
    1.72 +        Log.w(LOGTAG, "Dumping ALL the threads!");
    1.73 +        Map<Thread, StackTraceElement[]> allStacks = Thread.getAllStackTraces();
    1.74 +        for (Thread t : allStacks.keySet()) {
    1.75 +            Log.w(LOGTAG, t.toString());
    1.76 +            for (StackTraceElement ste : allStacks.get(t)) {
    1.77 +                Log.w(LOGTAG, ste.toString());
    1.78 +            }
    1.79 +            Log.w(LOGTAG, "----");
    1.80 +        }
    1.81 +    }
    1.82 +
    1.83 +    public static void setUiThread(Thread thread, Handler handler) {
    1.84 +        sUiThread = thread;
    1.85 +        sUiHandler = handler;
    1.86 +    }
    1.87 +
    1.88 +    public static void setBackgroundThread(Thread thread) {
    1.89 +        sBackgroundThread = thread;
    1.90 +    }
    1.91 +
    1.92 +    public static Thread getUiThread() {
    1.93 +        return sUiThread;
    1.94 +    }
    1.95 +
    1.96 +    public static Handler getUiHandler() {
    1.97 +        return sUiHandler;
    1.98 +    }
    1.99 +
   1.100 +    public static void postToUiThread(Runnable runnable) {
   1.101 +        sUiHandler.post(runnable);
   1.102 +    }
   1.103 +
   1.104 +    public static Thread getBackgroundThread() {
   1.105 +        return sBackgroundThread;
   1.106 +    }
   1.107 +
   1.108 +    public static Handler getBackgroundHandler() {
   1.109 +        return GeckoBackgroundThread.getHandler();
   1.110 +    }
   1.111 +
   1.112 +    public static void postToBackgroundThread(Runnable runnable) {
   1.113 +        GeckoBackgroundThread.post(runnable);
   1.114 +    }
   1.115 +
   1.116 +    public static void assertOnUiThread(final AssertBehavior assertBehavior) {
   1.117 +        assertOnThread(getUiThread(), assertBehavior);
   1.118 +    }
   1.119 +
   1.120 +    public static void assertOnUiThread() {
   1.121 +        assertOnThread(getUiThread(), AssertBehavior.THROW);
   1.122 +    }
   1.123 +
   1.124 +    public static void assertOnGeckoThread() {
   1.125 +        assertOnThread(sGeckoThread, AssertBehavior.THROW);
   1.126 +    }
   1.127 +
   1.128 +    public static void assertOnBackgroundThread() {
   1.129 +        assertOnThread(getBackgroundThread(), AssertBehavior.THROW);
   1.130 +    }
   1.131 +
   1.132 +    public static void assertOnThread(final Thread expectedThread) {
   1.133 +        assertOnThread(expectedThread, AssertBehavior.THROW);
   1.134 +    }
   1.135 +
   1.136 +    public static void assertOnThread(final Thread expectedThread, AssertBehavior behavior) {
   1.137 +        final Thread currentThread = Thread.currentThread();
   1.138 +        final long currentThreadId = currentThread.getId();
   1.139 +        final long expectedThreadId = expectedThread.getId();
   1.140 +
   1.141 +        if (currentThreadId == expectedThreadId) {
   1.142 +            return;
   1.143 +        }
   1.144 +
   1.145 +        final String message = "Expected thread " +
   1.146 +                               expectedThreadId + " (\"" + expectedThread.getName() +
   1.147 +                               "\"), but running on thread " +
   1.148 +                               currentThreadId + " (\"" + currentThread.getName() + ")";
   1.149 +        final IllegalThreadStateException e = new IllegalThreadStateException(message);
   1.150 +
   1.151 +        switch (behavior) {
   1.152 +        case THROW:
   1.153 +            throw e;
   1.154 +        default:
   1.155 +            Log.e(LOGTAG, "Method called on wrong thread!", e);
   1.156 +        }
   1.157 +    }
   1.158 +
   1.159 +    public static boolean isOnUiThread() {
   1.160 +        return isOnThread(getUiThread());
   1.161 +    }
   1.162 +
   1.163 +    public static boolean isOnBackgroundThread() {
   1.164 +        if (sBackgroundThread == null) {
   1.165 +            return false;
   1.166 +        }
   1.167 +
   1.168 +        return isOnThread(sBackgroundThread);
   1.169 +    }
   1.170 +
   1.171 +    public static boolean isOnThread(Thread thread) {
   1.172 +        return (Thread.currentThread().getId() == thread.getId());
   1.173 +    }
   1.174 +
   1.175 +    /**
   1.176 +     * Reduces the priority of the Gecko thread, allowing other operations
   1.177 +     * (such as those related to the UI and database) to take precedence.
   1.178 +     *
   1.179 +     * Note that there are no guards in place to prevent multiple calls
   1.180 +     * to this method from conflicting with each other.
   1.181 +     *
   1.182 +     * @param timeout Timeout in ms after which the priority will be reset
   1.183 +     */
   1.184 +    public static void reduceGeckoPriority(long timeout) {
   1.185 +        if (!sIsGeckoPriorityReduced) {
   1.186 +            sIsGeckoPriorityReduced = true;
   1.187 +            sGeckoThread.setPriority(Thread.MIN_PRIORITY);
   1.188 +            getUiHandler().postDelayed(sPriorityResetRunnable, timeout);
   1.189 +        }
   1.190 +    }
   1.191 +
   1.192 +    /**
   1.193 +     * Resets the priority of a thread whose priority has been reduced
   1.194 +     * by reduceGeckoPriority.
   1.195 +     */
   1.196 +    public static void resetGeckoPriority() {
   1.197 +        if (sIsGeckoPriorityReduced) {
   1.198 +            sIsGeckoPriorityReduced = false;
   1.199 +            sGeckoThread.setPriority(Thread.NORM_PRIORITY);
   1.200 +            getUiHandler().removeCallbacks(sPriorityResetRunnable);
   1.201 +        }
   1.202 +    }
   1.203 +}

mercurial