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.compat.annotation.UnsupportedAppUsage;
22 import android.util.Log;
23 import android.util.Printer;
24 import android.util.Slog;
25 import android.util.proto.ProtoOutputStream;
26 
27 import java.util.Objects;
28 
29 /**
30   * Class used to run a message loop for a thread.  Threads by default do
31   * not have a message loop associated with them; to create one, call
32   * {@link #prepare} in the thread that is to run the loop, and then
33   * {@link #loop} to have it process messages until the loop is stopped.
34   *
35   * <p>Most interaction with a message loop is through the
36   * {@link Handler} class.
37   *
38   * <p>This is a typical example of the implementation of a Looper thread,
39   * using the separation of {@link #prepare} and {@link #loop} to create an
40   * initial Handler to communicate with the Looper.
41   *
42   * <pre>
43   *  class LooperThread extends Thread {
44   *      public Handler mHandler;
45   *
46   *      public void run() {
47   *          Looper.prepare();
48   *
49   *          mHandler = new Handler(Looper.myLooper()) {
50   *              public void handleMessage(Message msg) {
51   *                  // process incoming messages here
52   *              }
53   *          };
54   *
55   *          Looper.loop();
56   *      }
57   *  }</pre>
58   */
59 @android.ravenwood.annotation.RavenwoodKeepWholeClass
60 public final class Looper {
61     /*
62      * API Implementation Note:
63      *
64      * This class contains the code required to set up and manage an event loop
65      * based on MessageQueue.  APIs that affect the state of the queue should be
66      * defined on MessageQueue or Handler rather than on Looper itself.  For example,
67      * idle handlers and sync barriers are defined on the queue whereas preparing the
68      * thread, looping, and quitting are defined on the looper.
69      */
70 
71     private static final String TAG = "Looper";
72 
73     // sThreadLocal.get() will return null unless you've called prepare().
74     @UnsupportedAppUsage
75     static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
76     @UnsupportedAppUsage
77     private static Looper sMainLooper;  // guarded by Looper.class
78     private static Observer sObserver;
79 
80     @UnsupportedAppUsage
81     final MessageQueue mQueue;
82     final Thread mThread;
83     private boolean mInLoop;
84 
85     @UnsupportedAppUsage
86     private Printer mLogging;
87     private long mTraceTag;
88 
89     /**
90      * If set, the looper will show a warning log if a message dispatch takes longer than this.
91      */
92     private long mSlowDispatchThresholdMs;
93 
94     /**
95      * If set, the looper will show a warning log if a message delivery (actual delivery time -
96      * post time) takes longer than this.
97      */
98     private long mSlowDeliveryThresholdMs;
99 
100     /**
101      * True if a message delivery takes longer than {@link #mSlowDeliveryThresholdMs}.
102      */
103     private boolean mSlowDeliveryDetected;
104 
105     /** Initialize the current thread as a looper.
106       * This gives you a chance to create handlers that then reference
107       * this looper, before actually starting the loop. Be sure to call
108       * {@link #loop()} after calling this method, and end it by calling
109       * {@link #quit()}.
110       */
prepare()111     public static void prepare() {
112         prepare(true);
113     }
114 
prepare(boolean quitAllowed)115     private static void prepare(boolean quitAllowed) {
116         if (sThreadLocal.get() != null) {
117             throw new RuntimeException("Only one Looper may be created per thread");
118         }
119         sThreadLocal.set(new Looper(quitAllowed));
120     }
121 
122     /**
123      * Initialize the current thread as a looper, marking it as an
124      * application's main looper. See also: {@link #prepare()}
125      *
126      * @deprecated The main looper for your application is created by the Android environment,
127      *   so you should never need to call this function yourself.
128      */
129     @Deprecated
prepareMainLooper()130     public static void prepareMainLooper() {
131         prepare(false);
132         synchronized (Looper.class) {
133             if (sMainLooper != null) {
134                 throw new IllegalStateException("The main Looper has already been prepared.");
135             }
136             sMainLooper = myLooper();
137         }
138     }
139 
140     /**
141      * Returns the application's main looper, which lives in the main thread of the application.
142      */
getMainLooper()143     public static Looper getMainLooper() {
144         synchronized (Looper.class) {
145             return sMainLooper;
146         }
147     }
148 
149     /**
150      * Force the application's main looper to the given value.  The main looper is typically
151      * configured automatically by the OS, so this capability is only intended to enable testing.
152      *
153      * @hide
154      */
setMainLooperForTest(@onNull Looper looper)155     public static void setMainLooperForTest(@NonNull Looper looper) {
156         synchronized (Looper.class) {
157             sMainLooper = Objects.requireNonNull(looper);
158         }
159     }
160 
161     /**
162      * Clear the application's main looper to be undefined.  The main looper is typically
163      * configured automatically by the OS, so this capability is only intended to enable testing.
164      *
165      * @hide
166      */
clearMainLooperForTest()167     public static void clearMainLooperForTest() {
168         synchronized (Looper.class) {
169             sMainLooper = null;
170         }
171     }
172 
173     /**
174      * Set the transaction observer for all Loopers in this process.
175      *
176      * @hide
177      */
setObserver(@ullable Observer observer)178     public static void setObserver(@Nullable Observer observer) {
179         sObserver = observer;
180     }
181 
182     /**
183      * Poll and deliver single message, return true if the outer loop should continue.
184      */
185     @SuppressWarnings({"UnusedTokenOfOriginalCallingIdentity",
186             "ClearIdentityCallNotFollowedByTryFinally"})
loopOnce(final Looper me, final long ident, final int thresholdOverride)187     private static boolean loopOnce(final Looper me,
188             final long ident, final int thresholdOverride) {
189         Message msg = me.mQueue.next(); // might block
190         if (msg == null) {
191             // No message indicates that the message queue is quitting.
192             return false;
193         }
194 
195         // This must be in a local variable, in case a UI event sets the logger
196         final Printer logging = me.mLogging;
197         if (logging != null) {
198             logging.println(">>>>> Dispatching to " + msg.target + " "
199                     + msg.callback + ": " + msg.what);
200         }
201         // Make sure the observer won't change while processing a transaction.
202         final Observer observer = sObserver;
203 
204         final long traceTag = me.mTraceTag;
205         long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
206         long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
207 
208         final boolean hasOverride = thresholdOverride >= 0;
209         if (hasOverride) {
210             slowDispatchThresholdMs = thresholdOverride;
211             slowDeliveryThresholdMs = thresholdOverride;
212         }
213         final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0 || hasOverride)
214                 && (msg.when > 0);
215         final boolean logSlowDispatch = (slowDispatchThresholdMs > 0 || hasOverride);
216 
217         final boolean needStartTime = logSlowDelivery || logSlowDispatch;
218         final boolean needEndTime = logSlowDispatch;
219 
220         if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
221             Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
222         }
223 
224         final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
225         final long dispatchEnd;
226         Object token = null;
227         if (observer != null) {
228             token = observer.messageDispatchStarting();
229         }
230         long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
231         try {
232             msg.target.dispatchMessage(msg);
233             if (observer != null) {
234                 observer.messageDispatched(token, msg);
235             }
236             dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
237         } catch (Exception exception) {
238             if (observer != null) {
239                 observer.dispatchingThrewException(token, msg, exception);
240             }
241             throw exception;
242         } finally {
243             ThreadLocalWorkSource.restore(origWorkSource);
244             if (traceTag != 0) {
245                 Trace.traceEnd(traceTag);
246             }
247         }
248         if (logSlowDelivery) {
249             if (me.mSlowDeliveryDetected) {
250                 if ((dispatchStart - msg.when) <= 10) {
251                     Slog.w(TAG, "Drained");
252                     me.mSlowDeliveryDetected = false;
253                 }
254             } else {
255                 if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
256                         msg)) {
257                     // Once we write a slow delivery log, suppress until the queue drains.
258                     me.mSlowDeliveryDetected = true;
259                 }
260             }
261         }
262         if (logSlowDispatch) {
263             showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
264         }
265 
266         if (logging != null) {
267             logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
268         }
269 
270         // Make sure that during the course of dispatching the
271         // identity of the thread wasn't corrupted.
272         final long newIdent = Binder.clearCallingIdentity();
273         if (ident != newIdent) {
274             Log.wtf(TAG, "Thread identity changed from 0x"
275                     + Long.toHexString(ident) + " to 0x"
276                     + Long.toHexString(newIdent) + " while dispatching to "
277                     + msg.target.getClass().getName() + " "
278                     + msg.callback + " what=" + msg.what);
279         }
280 
281         msg.recycleUnchecked();
282 
283         return true;
284     }
285 
286     /**
287      * Run the message queue in this thread. Be sure to call
288      * {@link #quit()} to end the loop.
289      */
290     @SuppressWarnings({"UnusedTokenOfOriginalCallingIdentity",
291             "ClearIdentityCallNotFollowedByTryFinally",
292             "ResultOfClearIdentityCallNotStoredInVariable"})
loop()293     public static void loop() {
294         final Looper me = myLooper();
295         if (me == null) {
296             throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
297         }
298         if (me.mInLoop) {
299             Slog.w(TAG, "Loop again would have the queued messages be executed"
300                     + " before this one completed.");
301         }
302 
303         me.mInLoop = true;
304 
305         // Make sure the identity of this thread is that of the local process,
306         // and keep track of what that identity token actually is.
307         Binder.clearCallingIdentity();
308         final long ident = Binder.clearCallingIdentity();
309 
310         // Allow overriding a threshold with a system prop. e.g.
311         // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
312         final int thresholdOverride = getThresholdOverride();
313 
314         me.mSlowDeliveryDetected = false;
315 
316         for (;;) {
317             if (!loopOnce(me, ident, thresholdOverride)) {
318                 return;
319             }
320         }
321     }
322 
323     @android.ravenwood.annotation.RavenwoodReplace
getThresholdOverride()324     private static int getThresholdOverride() {
325         return SystemProperties.getInt("log.looper."
326                 + Process.myUid() + "."
327                 + Thread.currentThread().getName()
328                 + ".slow", -1);
329     }
330 
getThresholdOverride$ravenwood()331     private static int getThresholdOverride$ravenwood() {
332         return -1;
333     }
334 
showSlowLog(long threshold, long measureStart, long measureEnd, String what, Message msg)335     private static boolean showSlowLog(long threshold, long measureStart, long measureEnd,
336             String what, Message msg) {
337         final long actualTime = measureEnd - measureStart;
338         if (actualTime < threshold) {
339             return false;
340         }
341         // For slow delivery, the current message isn't really important, but log it anyway.
342         Slog.w(TAG, "Slow " + what + " took " + actualTime + "ms "
343                 + Thread.currentThread().getName() + " h="
344                 + msg.target.getClass().getName() + " c=" + msg.callback + " m=" + msg.what);
345         return true;
346     }
347 
348     /**
349      * Return the Looper object associated with the current thread.  Returns
350      * null if the calling thread is not associated with a Looper.
351      */
myLooper()352     public static @Nullable Looper myLooper() {
353         return sThreadLocal.get();
354     }
355 
356     /**
357      * Return the {@link MessageQueue} object associated with the current
358      * thread.  This must be called from a thread running a Looper, or a
359      * NullPointerException will be thrown.
360      */
myQueue()361     public static @NonNull MessageQueue myQueue() {
362         return myLooper().mQueue;
363     }
364 
Looper(boolean quitAllowed)365     private Looper(boolean quitAllowed) {
366         mQueue = new MessageQueue(quitAllowed);
367         mThread = Thread.currentThread();
368     }
369 
370     /**
371      * Returns true if the current thread is this looper's thread.
372      */
isCurrentThread()373     public boolean isCurrentThread() {
374         return Thread.currentThread() == mThread;
375     }
376 
377     /**
378      * Control logging of messages as they are processed by this Looper.  If
379      * enabled, a log message will be written to <var>printer</var>
380      * at the beginning and ending of each message dispatch, identifying the
381      * target Handler and message contents.
382      *
383      * @param printer A Printer object that will receive log messages, or
384      * null to disable message logging.
385      */
setMessageLogging(@ullable Printer printer)386     public void setMessageLogging(@Nullable Printer printer) {
387         mLogging = printer;
388     }
389 
390     /** {@hide} */
391     @UnsupportedAppUsage
setTraceTag(long traceTag)392     public void setTraceTag(long traceTag) {
393         mTraceTag = traceTag;
394     }
395 
396     /**
397      * Set a thresholds for slow dispatch/delivery log.
398      * {@hide}
399      */
setSlowLogThresholdMs(long slowDispatchThresholdMs, long slowDeliveryThresholdMs)400     public void setSlowLogThresholdMs(long slowDispatchThresholdMs, long slowDeliveryThresholdMs) {
401         mSlowDispatchThresholdMs = slowDispatchThresholdMs;
402         mSlowDeliveryThresholdMs = slowDeliveryThresholdMs;
403     }
404 
405     /**
406      * Quits the looper.
407      * <p>
408      * Causes the {@link #loop} method to terminate without processing any
409      * more messages in the message queue.
410      * </p><p>
411      * Any attempt to post messages to the queue after the looper is asked to quit will fail.
412      * For example, the {@link Handler#sendMessage(Message)} method will return false.
413      * </p><p class="note">
414      * Using this method may be unsafe because some messages may not be delivered
415      * before the looper terminates.  Consider using {@link #quitSafely} instead to ensure
416      * that all pending work is completed in an orderly manner.
417      * </p>
418      *
419      * @see #quitSafely
420      */
quit()421     public void quit() {
422         mQueue.quit(false);
423     }
424 
425     /**
426      * Quits the looper safely.
427      * <p>
428      * Causes the {@link #loop} method to terminate as soon as all remaining messages
429      * in the message queue that are already due to be delivered have been handled.
430      * However pending delayed messages with due times in the future will not be
431      * delivered before the loop terminates.
432      * </p><p>
433      * Any attempt to post messages to the queue after the looper is asked to quit will fail.
434      * For example, the {@link Handler#sendMessage(Message)} method will return false.
435      * </p>
436      */
quitSafely()437     public void quitSafely() {
438         mQueue.quit(true);
439     }
440 
441     /**
442      * Gets the Thread associated with this Looper.
443      *
444      * @return The looper's thread.
445      */
getThread()446     public @NonNull Thread getThread() {
447         return mThread;
448     }
449 
450     /**
451      * Gets this looper's message queue.
452      *
453      * @return The looper's message queue.
454      */
getQueue()455     public @NonNull MessageQueue getQueue() {
456         return mQueue;
457     }
458 
459     /**
460      * Dumps the state of the looper for debugging purposes.
461      *
462      * @param pw A printer to receive the contents of the dump.
463      * @param prefix A prefix to prepend to each line which is printed.
464      */
dump(@onNull Printer pw, @NonNull String prefix)465     public void dump(@NonNull Printer pw, @NonNull String prefix) {
466         pw.println(prefix + toString());
467         mQueue.dump(pw, prefix + "  ", null);
468     }
469 
470     /**
471      * Dumps the state of the looper for debugging purposes.
472      *
473      * @param pw A printer to receive the contents of the dump.
474      * @param prefix A prefix to prepend to each line which is printed.
475      * @param handler Only dump messages for this Handler.
476      * @hide
477      */
dump(@onNull Printer pw, @NonNull String prefix, Handler handler)478     public void dump(@NonNull Printer pw, @NonNull String prefix, Handler handler) {
479         pw.println(prefix + toString());
480         mQueue.dump(pw, prefix + "  ", handler);
481     }
482 
483     /** @hide */
dumpDebug(ProtoOutputStream proto, long fieldId)484     public void dumpDebug(ProtoOutputStream proto, long fieldId) {
485         final long looperToken = proto.start(fieldId);
486         proto.write(LooperProto.THREAD_NAME, mThread.getName());
487         proto.write(LooperProto.THREAD_ID, mThread.getId());
488         if (mQueue != null) {
489             mQueue.dumpDebug(proto, LooperProto.QUEUE);
490         }
491         proto.end(looperToken);
492     }
493 
494     @Override
toString()495     public String toString() {
496         return "Looper (" + mThread.getName() + ", tid " + mThread.getId()
497                 + ") {" + Integer.toHexString(System.identityHashCode(this)) + "}";
498     }
499 
500     /** {@hide} */
501     public interface Observer {
502         /**
503          * Called right before a message is dispatched.
504          *
505          * <p> The token type is not specified to allow the implementation to specify its own type.
506          *
507          * @return a token used for collecting telemetry when dispatching a single message.
508          *         The token token must be passed back exactly once to either
509          *         {@link Observer#messageDispatched} or {@link Observer#dispatchingThrewException}
510          *         and must not be reused again.
511          *
512          */
messageDispatchStarting()513         Object messageDispatchStarting();
514 
515         /**
516          * Called when a message was processed by a Handler.
517          *
518          * @param token Token obtained by previously calling
519          *              {@link Observer#messageDispatchStarting} on the same Observer instance.
520          * @param msg The message that was dispatched.
521          */
messageDispatched(Object token, Message msg)522         void messageDispatched(Object token, Message msg);
523 
524         /**
525          * Called when an exception was thrown while processing a message.
526          *
527          * @param token Token obtained by previously calling
528          *              {@link Observer#messageDispatchStarting} on the same Observer instance.
529          * @param msg The message that was dispatched and caused an exception.
530          * @param exception The exception that was thrown.
531          */
dispatchingThrewException(Object token, Message msg, Exception exception)532         void dispatchingThrewException(Object token, Message msg, Exception exception);
533     }
534 }
535