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.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.util.Log;
22 import android.util.Printer;
23 
24 /**
25   * Class used to run a message loop for a thread.  Threads by default do
26   * not have a message loop associated with them; to create one, call
27   * {@link #prepare} in the thread that is to run the loop, and then
28   * {@link #loop} to have it process messages until the loop is stopped.
29   *
30   * <p>Most interaction with a message loop is through the
31   * {@link Handler} class.
32   *
33   * <p>This is a typical example of the implementation of a Looper thread,
34   * using the separation of {@link #prepare} and {@link #loop} to create an
35   * initial Handler to communicate with the Looper.
36   *
37   * <pre>
38   *  class LooperThread extends Thread {
39   *      public Handler mHandler;
40   *
41   *      public void run() {
42   *          Looper.prepare();
43   *
44   *          mHandler = new Handler() {
45   *              public void handleMessage(Message msg) {
46   *                  // process incoming messages here
47   *              }
48   *          };
49   *
50   *          Looper.loop();
51   *      }
52   *  }</pre>
53   */
54 public final class Looper {
55     /*
56      * API Implementation Note:
57      *
58      * This class contains the code required to set up and manage an event loop
59      * based on MessageQueue.  APIs that affect the state of the queue should be
60      * defined on MessageQueue or Handler rather than on Looper itself.  For example,
61      * idle handlers and sync barriers are defined on the queue whereas preparing the
62      * thread, looping, and quitting are defined on the looper.
63      */
64 
65     private static final String TAG = "Looper";
66 
67     // sThreadLocal.get() will return null unless you've called prepare().
68     static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
69     private static Looper sMainLooper;  // guarded by Looper.class
70 
71     final MessageQueue mQueue;
72     final Thread mThread;
73 
74     private Printer mLogging;
75 
76      /** Initialize the current thread as a looper.
77       * This gives you a chance to create handlers that then reference
78       * this looper, before actually starting the loop. Be sure to call
79       * {@link #loop()} after calling this method, and end it by calling
80       * {@link #quit()}.
81       */
prepare()82     public static void prepare() {
83         prepare(true);
84     }
85 
prepare(boolean quitAllowed)86     private static void prepare(boolean quitAllowed) {
87         if (sThreadLocal.get() != null) {
88             throw new RuntimeException("Only one Looper may be created per thread");
89         }
90         sThreadLocal.set(new Looper(quitAllowed));
91     }
92 
93     /**
94      * Initialize the current thread as a looper, marking it as an
95      * application's main looper. The main looper for your application
96      * is created by the Android environment, so you should never need
97      * to call this function yourself.  See also: {@link #prepare()}
98      */
prepareMainLooper()99     public static void prepareMainLooper() {
100         prepare(false);
101         synchronized (Looper.class) {
102             if (sMainLooper != null) {
103                 throw new IllegalStateException("The main Looper has already been prepared.");
104             }
105             sMainLooper = myLooper();
106         }
107     }
108 
109     /**
110      * Returns the application's main looper, which lives in the main thread of the application.
111      */
getMainLooper()112     public static Looper getMainLooper() {
113         synchronized (Looper.class) {
114             return sMainLooper;
115         }
116     }
117 
118     /**
119      * Run the message queue in this thread. Be sure to call
120      * {@link #quit()} to end the loop.
121      */
loop()122     public static void loop() {
123         final Looper me = myLooper();
124         if (me == null) {
125             throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
126         }
127         final MessageQueue queue = me.mQueue;
128 
129         // Make sure the identity of this thread is that of the local process,
130         // and keep track of what that identity token actually is.
131         Binder.clearCallingIdentity();
132         final long ident = Binder.clearCallingIdentity();
133 
134         for (;;) {
135             Message msg = queue.next(); // might block
136             if (msg == null) {
137                 // No message indicates that the message queue is quitting.
138                 return;
139             }
140 
141             // This must be in a local variable, in case a UI event sets the logger
142             Printer logging = me.mLogging;
143             if (logging != null) {
144                 logging.println(">>>>> Dispatching to " + msg.target + " " +
145                         msg.callback + ": " + msg.what);
146             }
147 
148             msg.target.dispatchMessage(msg);
149 
150             if (logging != null) {
151                 logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
152             }
153 
154             // Make sure that during the course of dispatching the
155             // identity of the thread wasn't corrupted.
156             final long newIdent = Binder.clearCallingIdentity();
157             if (ident != newIdent) {
158                 Log.wtf(TAG, "Thread identity changed from 0x"
159                         + Long.toHexString(ident) + " to 0x"
160                         + Long.toHexString(newIdent) + " while dispatching to "
161                         + msg.target.getClass().getName() + " "
162                         + msg.callback + " what=" + msg.what);
163             }
164 
165             msg.recycleUnchecked();
166         }
167     }
168 
169     /**
170      * Return the Looper object associated with the current thread.  Returns
171      * null if the calling thread is not associated with a Looper.
172      */
myLooper()173     public static @Nullable Looper myLooper() {
174         return sThreadLocal.get();
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      */
myQueue()182     public static @NonNull MessageQueue myQueue() {
183         return myLooper().mQueue;
184     }
185 
Looper(boolean quitAllowed)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      */
isCurrentThread()194     public boolean isCurrentThread() {
195         return Thread.currentThread() == mThread;
196     }
197 
198     /**
199      * Control logging of messages as they are processed by this Looper.  If
200      * enabled, a log message will be written to <var>printer</var>
201      * at the beginning and ending of each message dispatch, identifying the
202      * target Handler and message contents.
203      *
204      * @param printer A Printer object that will receive log messages, or
205      * null to disable message logging.
206      */
setMessageLogging(@ullable Printer printer)207     public void setMessageLogging(@Nullable Printer printer) {
208         mLogging = printer;
209     }
210 
211     /**
212      * Quits the looper.
213      * <p>
214      * Causes the {@link #loop} method to terminate without processing any
215      * more messages in the message queue.
216      * </p><p>
217      * Any attempt to post messages to the queue after the looper is asked to quit will fail.
218      * For example, the {@link Handler#sendMessage(Message)} method will return false.
219      * </p><p class="note">
220      * Using this method may be unsafe because some messages may not be delivered
221      * before the looper terminates.  Consider using {@link #quitSafely} instead to ensure
222      * that all pending work is completed in an orderly manner.
223      * </p>
224      *
225      * @see #quitSafely
226      */
quit()227     public void quit() {
228         mQueue.quit(false);
229     }
230 
231     /**
232      * Quits the looper safely.
233      * <p>
234      * Causes the {@link #loop} method to terminate as soon as all remaining messages
235      * in the message queue that are already due to be delivered have been handled.
236      * However pending delayed messages with due times in the future will not be
237      * delivered before the loop terminates.
238      * </p><p>
239      * Any attempt to post messages to the queue after the looper is asked to quit will fail.
240      * For example, the {@link Handler#sendMessage(Message)} method will return false.
241      * </p>
242      */
quitSafely()243     public void quitSafely() {
244         mQueue.quit(true);
245     }
246 
247     /**
248      * Gets the Thread associated with this Looper.
249      *
250      * @return The looper's thread.
251      */
getThread()252     public @NonNull Thread getThread() {
253         return mThread;
254     }
255 
256     /**
257      * Gets this looper's message queue.
258      *
259      * @return The looper's message queue.
260      */
getQueue()261     public @NonNull MessageQueue getQueue() {
262         return mQueue;
263     }
264 
265     /**
266      * Dumps the state of the looper for debugging purposes.
267      *
268      * @param pw A printer to receive the contents of the dump.
269      * @param prefix A prefix to prepend to each line which is printed.
270      */
dump(@onNull Printer pw, @NonNull String prefix)271     public void dump(@NonNull Printer pw, @NonNull String prefix) {
272         pw.println(prefix + toString());
273         mQueue.dump(pw, prefix + "  ");
274     }
275 
276     @Override
toString()277     public String toString() {
278         return "Looper (" + mThread.getName() + ", tid " + mThread.getId()
279                 + ") {" + Integer.toHexString(System.identityHashCode(this)) + "}";
280     }
281 }
282