Home | History | Annotate | Download | only in os
      1 /*
      2  * Copyright (C) 2006 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.os;
     18 
     19 import android.util.Log;
     20 import android.util.Printer;
     21 import android.util.PrefixPrinter;
     22 
     23 /**
     24   * Class used to run a message loop for a thread.  Threads by default do
     25   * not have a message loop associated with them; to create one, call
     26   * {@link #prepare} in the thread that is to run the loop, and then
     27   * {@link #loop} to have it process messages until the loop is stopped.
     28   *
     29   * <p>Most interaction with a message loop is through the
     30   * {@link Handler} class.
     31   *
     32   * <p>This is a typical example of the implementation of a Looper thread,
     33   * using the separation of {@link #prepare} and {@link #loop} to create an
     34   * initial Handler to communicate with the Looper.
     35   *
     36   * <pre>
     37   *  class LooperThread extends Thread {
     38   *      public Handler mHandler;
     39   *
     40   *      public void run() {
     41   *          Looper.prepare();
     42   *
     43   *          mHandler = new Handler() {
     44   *              public void handleMessage(Message msg) {
     45   *                  // process incoming messages here
     46   *              }
     47   *          };
     48   *
     49   *          Looper.loop();
     50   *      }
     51   *  }</pre>
     52   */
     53 public final class Looper {
     54     private static final String TAG = "Looper";
     55 
     56     // sThreadLocal.get() will return null unless you've called prepare().
     57     static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
     58     private static Looper sMainLooper;  // guarded by Looper.class
     59 
     60     final MessageQueue mQueue;
     61     final Thread mThread;
     62 
     63     private Printer mLogging;
     64 
     65      /** Initialize the current thread as a looper.
     66       * This gives you a chance to create handlers that then reference
     67       * this looper, before actually starting the loop. Be sure to call
     68       * {@link #loop()} after calling this method, and end it by calling
     69       * {@link #quit()}.
     70       */
     71     public static void prepare() {
     72         prepare(true);
     73     }
     74 
     75     private static void prepare(boolean quitAllowed) {
     76         if (sThreadLocal.get() != null) {
     77             throw new RuntimeException("Only one Looper may be created per thread");
     78         }
     79         sThreadLocal.set(new Looper(quitAllowed));
     80     }
     81 
     82     /**
     83      * Initialize the current thread as a looper, marking it as an
     84      * application's main looper. The main looper for your application
     85      * is created by the Android environment, so you should never need
     86      * to call this function yourself.  See also: {@link #prepare()}
     87      */
     88     public static void prepareMainLooper() {
     89         prepare(false);
     90         synchronized (Looper.class) {
     91             if (sMainLooper != null) {
     92                 throw new IllegalStateException("The main Looper has already been prepared.");
     93             }
     94             sMainLooper = myLooper();
     95         }
     96     }
     97 
     98     /** Returns the application's main looper, which lives in the main thread of the application.
     99      */
    100     public static Looper getMainLooper() {
    101         synchronized (Looper.class) {
    102             return sMainLooper;
    103         }
    104     }
    105 
    106     /**
    107      * Run the message queue in this thread. Be sure to call
    108      * {@link #quit()} to end the loop.
    109      */
    110     public static void loop() {
    111         final Looper me = myLooper();
    112         if (me == null) {
    113             throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    114         }
    115         final MessageQueue queue = me.mQueue;
    116 
    117         // Make sure the identity of this thread is that of the local process,
    118         // and keep track of what that identity token actually is.
    119         Binder.clearCallingIdentity();
    120         final long ident = Binder.clearCallingIdentity();
    121 
    122         for (;;) {
    123             Message msg = queue.next(); // might block
    124             if (msg == null) {
    125                 // No message indicates that the message queue is quitting.
    126                 return;
    127             }
    128 
    129             // This must be in a local variable, in case a UI event sets the logger
    130             Printer logging = me.mLogging;
    131             if (logging != null) {
    132                 logging.println(">>>>> Dispatching to " + msg.target + " " +
    133                         msg.callback + ": " + msg.what);
    134             }
    135 
    136             msg.target.dispatchMessage(msg);
    137 
    138             if (logging != null) {
    139                 logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
    140             }
    141 
    142             // Make sure that during the course of dispatching the
    143             // identity of the thread wasn't corrupted.
    144             final long newIdent = Binder.clearCallingIdentity();
    145             if (ident != newIdent) {
    146                 Log.wtf(TAG, "Thread identity changed from 0x"
    147                         + Long.toHexString(ident) + " to 0x"
    148                         + Long.toHexString(newIdent) + " while dispatching to "
    149                         + msg.target.getClass().getName() + " "
    150                         + msg.callback + " what=" + msg.what);
    151             }
    152 
    153             msg.recycle();
    154         }
    155     }
    156 
    157     /**
    158      * Return the Looper object associated with the current thread.  Returns
    159      * null if the calling thread is not associated with a Looper.
    160      */
    161     public static Looper myLooper() {
    162         return sThreadLocal.get();
    163     }
    164 
    165     /**
    166      * Control logging of messages as they are processed by this Looper.  If
    167      * enabled, a log message will be written to <var>printer</var>
    168      * at the beginning and ending of each message dispatch, identifying the
    169      * target Handler and message contents.
    170      *
    171      * @param printer A Printer object that will receive log messages, or
    172      * null to disable message logging.
    173      */
    174     public void setMessageLogging(Printer printer) {
    175         mLogging = printer;
    176     }
    177 
    178     /**
    179      * Return the {@link MessageQueue} object associated with the current
    180      * thread.  This must be called from a thread running a Looper, or a
    181      * NullPointerException will be thrown.
    182      */
    183     public static MessageQueue myQueue() {
    184         return myLooper().mQueue;
    185     }
    186 
    187     private Looper(boolean quitAllowed) {
    188         mQueue = new MessageQueue(quitAllowed);
    189         mThread = Thread.currentThread();
    190     }
    191 
    192     /**
    193      * Returns true if the current thread is this looper's thread.
    194      * @hide
    195      */
    196     public boolean isCurrentThread() {
    197         return Thread.currentThread() == mThread;
    198     }
    199 
    200     /**
    201      * Quits the looper.
    202      * <p>
    203      * Causes the {@link #loop} method to terminate without processing any
    204      * more messages in the message queue.
    205      * </p><p>
    206      * Any attempt to post messages to the queue after the looper is asked to quit will fail.
    207      * For example, the {@link Handler#sendMessage(Message)} method will return false.
    208      * </p><p class="note">
    209      * Using this method may be unsafe because some messages may not be delivered
    210      * before the looper terminates.  Consider using {@link #quitSafely} instead to ensure
    211      * that all pending work is completed in an orderly manner.
    212      * </p>
    213      *
    214      * @see #quitSafely
    215      */
    216     public void quit() {
    217         mQueue.quit(false);
    218     }
    219 
    220     /**
    221      * Quits the looper safely.
    222      * <p>
    223      * Causes the {@link #loop} method to terminate as soon as all remaining messages
    224      * in the message queue that are already due to be delivered have been handled.
    225      * However pending delayed messages with due times in the future will not be
    226      * delivered before the loop terminates.
    227      * </p><p>
    228      * Any attempt to post messages to the queue after the looper is asked to quit will fail.
    229      * For example, the {@link Handler#sendMessage(Message)} method will return false.
    230      * </p>
    231      */
    232     public void quitSafely() {
    233         mQueue.quit(true);
    234     }
    235 
    236     /**
    237      * Posts a synchronization barrier to the Looper's message queue.
    238      *
    239      * Message processing occurs as usual until the message queue encounters the
    240      * synchronization barrier that has been posted.  When the barrier is encountered,
    241      * later synchronous messages in the queue are stalled (prevented from being executed)
    242      * until the barrier is released by calling {@link #removeSyncBarrier} and specifying
    243      * the token that identifies the synchronization barrier.
    244      *
    245      * This method is used to immediately postpone execution of all subsequently posted
    246      * synchronous messages until a condition is met that releases the barrier.
    247      * Asynchronous messages (see {@link Message#isAsynchronous} are exempt from the barrier
    248      * and continue to be processed as usual.
    249      *
    250      * This call must be always matched by a call to {@link #removeSyncBarrier} with
    251      * the same token to ensure that the message queue resumes normal operation.
    252      * Otherwise the application will probably hang!
    253      *
    254      * @return A token that uniquely identifies the barrier.  This token must be
    255      * passed to {@link #removeSyncBarrier} to release the barrier.
    256      *
    257      * @hide
    258      */
    259     public int postSyncBarrier() {
    260         return mQueue.enqueueSyncBarrier(SystemClock.uptimeMillis());
    261     }
    262 
    263 
    264     /**
    265      * Removes a synchronization barrier.
    266      *
    267      * @param token The synchronization barrier token that was returned by
    268      * {@link #postSyncBarrier}.
    269      *
    270      * @throws IllegalStateException if the barrier was not found.
    271      *
    272      * @hide
    273      */
    274     public void removeSyncBarrier(int token) {
    275         mQueue.removeSyncBarrier(token);
    276     }
    277 
    278     /**
    279      * Return the Thread associated with this Looper.
    280      */
    281     public Thread getThread() {
    282         return mThread;
    283     }
    284 
    285     /** @hide */
    286     public MessageQueue getQueue() {
    287         return mQueue;
    288     }
    289 
    290     /**
    291      * Return whether this looper's thread is currently idle, waiting for new work
    292      * to do.  This is intrinsically racy, since its state can change before you get
    293      * the result back.
    294      * @hide
    295      */
    296     public boolean isIdling() {
    297         return mQueue.isIdling();
    298     }
    299 
    300     public void dump(Printer pw, String prefix) {
    301         pw.println(prefix + toString());
    302         mQueue.dump(pw, prefix + "  ");
    303     }
    304 
    305     public String toString() {
    306         return "Looper (" + mThread.getName() + ", tid " + mThread.getId()
    307                 + ") {" + Integer.toHexString(System.identityHashCode(this)) + "}";
    308     }
    309 }
    310