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