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