• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.content;
18 
19 import android.app.ActivityManager;
20 import android.app.ActivityThread;
21 import android.app.IActivityManager;
22 import android.app.QueuedWork;
23 import android.os.Bundle;
24 import android.os.IBinder;
25 import android.os.RemoteException;
26 import android.util.Log;
27 import android.util.Slog;
28 
29 /**
30  * Base class for code that receives and handles broadcast intents sent by
31  * {@link android.content.Context#sendBroadcast(Intent)}.
32  *
33  * <p>You can either dynamically register an instance of this class with
34  * {@link Context#registerReceiver Context.registerReceiver()}
35  * or statically declare an implementation with the
36  * {@link android.R.styleable#AndroidManifestReceiver &lt;receiver&gt;}
37  * tag in your <code>AndroidManifest.xml</code>.
38  *
39  * <div class="special reference">
40  * <h3>Developer Guides</h3>
41  * <p>For more information about using BroadcastReceiver, read the
42  * <a href="{@docRoot}guide/components/broadcasts.html">Broadcasts</a> developer guide.</p></div>
43  *
44  */
45 public abstract class BroadcastReceiver {
46     private PendingResult mPendingResult;
47     private boolean mDebugUnregister;
48 
49     /**
50      * State for a result that is pending for a broadcast receiver.  Returned
51      * by {@link BroadcastReceiver#goAsync() goAsync()}
52      * while in {@link BroadcastReceiver#onReceive BroadcastReceiver.onReceive()}.
53      * This allows you to return from onReceive() without having the broadcast
54      * terminate; you must call {@link #finish()} once you are done with the
55      * broadcast.  This allows you to process the broadcast off of the main
56      * thread of your app.
57      *
58      * <p>Note on threading: the state inside of this class is not itself
59      * thread-safe, however you can use it from any thread if you properly
60      * sure that you do not have races.  Typically this means you will hand
61      * the entire object to another thread, which will be solely responsible
62      * for setting any results and finally calling {@link #finish()}.
63      */
64     public static class PendingResult {
65         /** @hide */
66         public static final int TYPE_COMPONENT = 0;
67         /** @hide */
68         public static final int TYPE_REGISTERED = 1;
69         /** @hide */
70         public static final int TYPE_UNREGISTERED = 2;
71 
72         final int mType;
73         final boolean mOrderedHint;
74         final boolean mInitialStickyHint;
75         final IBinder mToken;
76         final int mSendingUser;
77         final int mFlags;
78 
79         int mResultCode;
80         String mResultData;
81         Bundle mResultExtras;
82         boolean mAbortBroadcast;
83         boolean mFinished;
84 
85         /** @hide */
PendingResult(int resultCode, String resultData, Bundle resultExtras, int type, boolean ordered, boolean sticky, IBinder token, int userId, int flags)86         public PendingResult(int resultCode, String resultData, Bundle resultExtras, int type,
87                 boolean ordered, boolean sticky, IBinder token, int userId, int flags) {
88             mResultCode = resultCode;
89             mResultData = resultData;
90             mResultExtras = resultExtras;
91             mType = type;
92             mOrderedHint = ordered;
93             mInitialStickyHint = sticky;
94             mToken = token;
95             mSendingUser = userId;
96             mFlags = flags;
97         }
98 
99         /**
100          * Version of {@link BroadcastReceiver#setResultCode(int)
101          * BroadcastReceiver.setResultCode(int)} for
102          * asynchronous broadcast handling.
103          */
setResultCode(int code)104         public final void setResultCode(int code) {
105             checkSynchronousHint();
106             mResultCode = code;
107         }
108 
109         /**
110          * Version of {@link BroadcastReceiver#getResultCode()
111          * BroadcastReceiver.getResultCode()} for
112          * asynchronous broadcast handling.
113          */
getResultCode()114         public final int getResultCode() {
115             return mResultCode;
116         }
117 
118         /**
119          * Version of {@link BroadcastReceiver#setResultData(String)
120          * BroadcastReceiver.setResultData(String)} for
121          * asynchronous broadcast handling.
122          */
setResultData(String data)123         public final void setResultData(String data) {
124             checkSynchronousHint();
125             mResultData = data;
126         }
127 
128         /**
129          * Version of {@link BroadcastReceiver#getResultData()
130          * BroadcastReceiver.getResultData()} for
131          * asynchronous broadcast handling.
132          */
getResultData()133         public final String getResultData() {
134             return mResultData;
135         }
136 
137         /**
138          * Version of {@link BroadcastReceiver#setResultExtras(Bundle)
139          * BroadcastReceiver.setResultExtras(Bundle)} for
140          * asynchronous broadcast handling.
141          */
setResultExtras(Bundle extras)142         public final void setResultExtras(Bundle extras) {
143             checkSynchronousHint();
144             mResultExtras = extras;
145         }
146 
147         /**
148          * Version of {@link BroadcastReceiver#getResultExtras(boolean)
149          * BroadcastReceiver.getResultExtras(boolean)} for
150          * asynchronous broadcast handling.
151          */
getResultExtras(boolean makeMap)152         public final Bundle getResultExtras(boolean makeMap) {
153             Bundle e = mResultExtras;
154             if (!makeMap) return e;
155             if (e == null) mResultExtras = e = new Bundle();
156             return e;
157         }
158 
159         /**
160          * Version of {@link BroadcastReceiver#setResult(int, String, Bundle)
161          * BroadcastReceiver.setResult(int, String, Bundle)} for
162          * asynchronous broadcast handling.
163          */
setResult(int code, String data, Bundle extras)164         public final void setResult(int code, String data, Bundle extras) {
165             checkSynchronousHint();
166             mResultCode = code;
167             mResultData = data;
168             mResultExtras = extras;
169         }
170 
171         /**
172          * Version of {@link BroadcastReceiver#getAbortBroadcast()
173          * BroadcastReceiver.getAbortBroadcast()} for
174          * asynchronous broadcast handling.
175          */
getAbortBroadcast()176         public final boolean getAbortBroadcast() {
177             return mAbortBroadcast;
178         }
179 
180         /**
181          * Version of {@link BroadcastReceiver#abortBroadcast()
182          * BroadcastReceiver.abortBroadcast()} for
183          * asynchronous broadcast handling.
184          */
abortBroadcast()185         public final void abortBroadcast() {
186             checkSynchronousHint();
187             mAbortBroadcast = true;
188         }
189 
190         /**
191          * Version of {@link BroadcastReceiver#clearAbortBroadcast()
192          * BroadcastReceiver.clearAbortBroadcast()} for
193          * asynchronous broadcast handling.
194          */
clearAbortBroadcast()195         public final void clearAbortBroadcast() {
196             mAbortBroadcast = false;
197         }
198 
199         /**
200          * Finish the broadcast.  The current result will be sent and the
201          * next broadcast will proceed.
202          */
finish()203         public final void finish() {
204             if (mType == TYPE_COMPONENT) {
205                 final IActivityManager mgr = ActivityManager.getService();
206                 if (QueuedWork.hasPendingWork()) {
207                     // If this is a broadcast component, we need to make sure any
208                     // queued work is complete before telling AM we are done, so
209                     // we don't have our process killed before that.  We now know
210                     // there is pending work; put another piece of work at the end
211                     // of the list to finish the broadcast, so we don't block this
212                     // thread (which may be the main thread) to have it finished.
213                     //
214                     // Note that we don't need to use QueuedWork.addFinisher() with the
215                     // runnable, since we know the AM is waiting for us until the
216                     // executor gets to it.
217                     QueuedWork.queue(new Runnable() {
218                         @Override public void run() {
219                             if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
220                                     "Finishing broadcast after work to component " + mToken);
221                             sendFinished(mgr);
222                         }
223                     }, false);
224                 } else {
225                     if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
226                             "Finishing broadcast to component " + mToken);
227                     sendFinished(mgr);
228                 }
229             } else if (mOrderedHint && mType != TYPE_UNREGISTERED) {
230                 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
231                         "Finishing broadcast to " + mToken);
232                 final IActivityManager mgr = ActivityManager.getService();
233                 sendFinished(mgr);
234             }
235         }
236 
237         /** @hide */
setExtrasClassLoader(ClassLoader cl)238         public void setExtrasClassLoader(ClassLoader cl) {
239             if (mResultExtras != null) {
240                 mResultExtras.setClassLoader(cl);
241             }
242         }
243 
244         /** @hide */
sendFinished(IActivityManager am)245         public void sendFinished(IActivityManager am) {
246             synchronized (this) {
247                 if (mFinished) {
248                     throw new IllegalStateException("Broadcast already finished");
249                 }
250                 mFinished = true;
251 
252                 try {
253                     if (mResultExtras != null) {
254                         mResultExtras.setAllowFds(false);
255                     }
256                     if (mOrderedHint) {
257                         am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras,
258                                 mAbortBroadcast, mFlags);
259                     } else {
260                         // This broadcast was sent to a component; it is not ordered,
261                         // but we still need to tell the activity manager we are done.
262                         am.finishReceiver(mToken, 0, null, null, false, mFlags);
263                     }
264                 } catch (RemoteException ex) {
265                 }
266             }
267         }
268 
269         /** @hide */
getSendingUserId()270         public int getSendingUserId() {
271             return mSendingUser;
272         }
273 
checkSynchronousHint()274         void checkSynchronousHint() {
275             // Note that we don't assert when receiving the initial sticky value,
276             // since that may have come from an ordered broadcast.  We'll catch
277             // them later when the real broadcast happens again.
278             if (mOrderedHint || mInitialStickyHint) {
279                 return;
280             }
281             RuntimeException e = new RuntimeException(
282                     "BroadcastReceiver trying to return result during a non-ordered broadcast");
283             e.fillInStackTrace();
284             Log.e("BroadcastReceiver", e.getMessage(), e);
285         }
286     }
287 
BroadcastReceiver()288     public BroadcastReceiver() {
289     }
290 
291     /**
292      * This method is called when the BroadcastReceiver is receiving an Intent
293      * broadcast.  During this time you can use the other methods on
294      * BroadcastReceiver to view/modify the current result values.  This method
295      * is always called within the main thread of its process, unless you
296      * explicitly asked for it to be scheduled on a different thread using
297      * {@link android.content.Context#registerReceiver(BroadcastReceiver,
298      * IntentFilter, String, android.os.Handler)}. When it runs on the main
299      * thread you should
300      * never perform long-running operations in it (there is a timeout of
301      * 10 seconds that the system allows before considering the receiver to
302      * be blocked and a candidate to be killed). You cannot launch a popup dialog
303      * in your implementation of onReceive().
304      *
305      * <p><b>If this BroadcastReceiver was launched through a &lt;receiver&gt; tag,
306      * then the object is no longer alive after returning from this
307      * function.</b> This means you should not perform any operations that
308      * return a result to you asynchronously. If you need to perform any follow up
309      * background work, schedule a {@link android.app.job.JobService} with
310      * {@link android.app.job.JobScheduler}.
311      *
312      * If you wish to interact with a service that is already running and previously
313      * bound using {@link android.content.Context#bindService(Intent, ServiceConnection, int) bindService()},
314      * you can use {@link #peekService}.
315      *
316      * <p>The Intent filters used in {@link android.content.Context#registerReceiver}
317      * and in application manifests are <em>not</em> guaranteed to be exclusive. They
318      * are hints to the operating system about how to find suitable recipients. It is
319      * possible for senders to force delivery to specific recipients, bypassing filter
320      * resolution.  For this reason, {@link #onReceive(Context, Intent) onReceive()}
321      * implementations should respond only to known actions, ignoring any unexpected
322      * Intents that they may receive.
323      *
324      * @param context The Context in which the receiver is running.
325      * @param intent The Intent being received.
326      */
onReceive(Context context, Intent intent)327     public abstract void onReceive(Context context, Intent intent);
328 
329     /**
330      * This can be called by an application in {@link #onReceive} to allow
331      * it to keep the broadcast active after returning from that function.
332      * This does <em>not</em> change the expectation of being relatively
333      * responsive to the broadcast, but does allow
334      * the implementation to move work related to it over to another thread
335      * to avoid glitching the main UI thread due to disk IO.
336      *
337      * <p>As a general rule, broadcast receivers are allowed to run for up to 10 seconds
338      * before they system will consider them non-responsive and ANR the app.  Since these usually
339      * execute on the app's main thread, they are already bound by the ~5 second time limit
340      * of various operations that can happen there (not to mention just avoiding UI jank), so
341      * the receive limit is generally not of concern.  However, once you use {@code goAsync}, though
342      * able to be off the main thread, the broadcast execution limit still applies, and that
343      * includes the time spent between calling this method and ultimately
344      * {@link PendingResult#finish() PendingResult.finish()}.</p>
345      *
346      * <p>If you are taking advantage of this method to have more time to execute, it is useful
347      * to know that the available time can be longer in certain situations.  In particular, if
348      * the broadcast you are receiving is not a foreground broadcast (that is, the sender has not
349      * used {@link Intent#FLAG_RECEIVER_FOREGROUND}), then more time is allowed for the receivers
350      * to run, allowing them to execute for 30 seconds or even a bit more.  This is something that
351      * receivers should rarely take advantage of (long work should be punted to another system
352      * facility such as {@link android.app.job.JobScheduler}, {@link android.app.Service}, or
353      * see especially {@link android.support.v4.app.JobIntentService}), but can be useful in
354      * certain rare cases where it is necessary to do some work as soon as the broadcast is
355      * delivered.  Keep in mind that the work you do here will block further broadcasts until
356      * it completes, so taking advantage of this at all excessively can be counter-productive
357      * and cause later events to be received more slowly.</p>
358      *
359      * @return Returns a {@link PendingResult} representing the result of
360      * the active broadcast.  The BroadcastRecord itself is no longer active;
361      * all data and other interaction must go through {@link PendingResult}
362      * APIs.  The {@link PendingResult#finish PendingResult.finish()} method
363      * must be called once processing of the broadcast is done.
364      */
goAsync()365     public final PendingResult goAsync() {
366         PendingResult res = mPendingResult;
367         mPendingResult = null;
368         return res;
369     }
370 
371     /**
372      * Provide a binder to an already-bound service.  This method is synchronous
373      * and will not start the target service if it is not present, so it is safe
374      * to call from {@link #onReceive}.
375      *
376      * For peekService() to return a non null {@link android.os.IBinder} interface
377      * the service must have published it before. In other words some component
378      * must have called {@link android.content.Context#bindService(Intent, ServiceConnection, int)} on it.
379      *
380      * @param myContext The Context that had been passed to {@link #onReceive(Context, Intent)}
381      * @param service Identifies the already-bound service you wish to use. See
382      * {@link android.content.Context#bindService(Intent, ServiceConnection, int)}
383      * for more information.
384      */
peekService(Context myContext, Intent service)385     public IBinder peekService(Context myContext, Intent service) {
386         IActivityManager am = ActivityManager.getService();
387         IBinder binder = null;
388         try {
389             service.prepareToLeaveProcess(myContext);
390             binder = am.peekService(service, service.resolveTypeIfNeeded(
391                     myContext.getContentResolver()), myContext.getOpPackageName());
392         } catch (RemoteException e) {
393         }
394         return binder;
395     }
396 
397     /**
398      * Change the current result code of this broadcast; only works with
399      * broadcasts sent through
400      * {@link Context#sendOrderedBroadcast(Intent, String)
401      * Context.sendOrderedBroadcast}.  Often uses the
402      * Activity {@link android.app.Activity#RESULT_CANCELED} and
403      * {@link android.app.Activity#RESULT_OK} constants, though the
404      * actual meaning of this value is ultimately up to the broadcaster.
405      *
406      * <p class="note">This method does not work with non-ordered broadcasts such
407      * as those sent with {@link Context#sendBroadcast(Intent)
408      * Context.sendBroadcast}</p>
409      *
410      * @param code The new result code.
411      *
412      * @see #setResult(int, String, Bundle)
413      */
setResultCode(int code)414     public final void setResultCode(int code) {
415         checkSynchronousHint();
416         mPendingResult.mResultCode = code;
417     }
418 
419     /**
420      * Retrieve the current result code, as set by the previous receiver.
421      *
422      * @return int The current result code.
423      */
getResultCode()424     public final int getResultCode() {
425         return mPendingResult != null ? mPendingResult.mResultCode : 0;
426     }
427 
428     /**
429      * Change the current result data of this broadcast; only works with
430      * broadcasts sent through
431      * {@link Context#sendOrderedBroadcast(Intent, String)
432      * Context.sendOrderedBroadcast}.  This is an arbitrary
433      * string whose interpretation is up to the broadcaster.
434      *
435      * <p><strong>This method does not work with non-ordered broadcasts such
436      * as those sent with {@link Context#sendBroadcast(Intent)
437      * Context.sendBroadcast}</strong></p>
438      *
439      * @param data The new result data; may be null.
440      *
441      * @see #setResult(int, String, Bundle)
442      */
setResultData(String data)443     public final void setResultData(String data) {
444         checkSynchronousHint();
445         mPendingResult.mResultData = data;
446     }
447 
448     /**
449      * Retrieve the current result data, as set by the previous receiver.
450      * Often this is null.
451      *
452      * @return String The current result data; may be null.
453      */
getResultData()454     public final String getResultData() {
455         return mPendingResult != null ? mPendingResult.mResultData : null;
456     }
457 
458     /**
459      * Change the current result extras of this broadcast; only works with
460      * broadcasts sent through
461      * {@link Context#sendOrderedBroadcast(Intent, String)
462      * Context.sendOrderedBroadcast}.  This is a Bundle
463      * holding arbitrary data, whose interpretation is up to the
464      * broadcaster.  Can be set to null.  Calling this method completely
465      * replaces the current map (if any).
466      *
467      * <p><strong>This method does not work with non-ordered broadcasts such
468      * as those sent with {@link Context#sendBroadcast(Intent)
469      * Context.sendBroadcast}</strong></p>
470      *
471      * @param extras The new extra data map; may be null.
472      *
473      * @see #setResult(int, String, Bundle)
474      */
setResultExtras(Bundle extras)475     public final void setResultExtras(Bundle extras) {
476         checkSynchronousHint();
477         mPendingResult.mResultExtras = extras;
478     }
479 
480     /**
481      * Retrieve the current result extra data, as set by the previous receiver.
482      * Any changes you make to the returned Map will be propagated to the next
483      * receiver.
484      *
485      * @param makeMap If true then a new empty Map will be made for you if the
486      *                current Map is null; if false you should be prepared to
487      *                receive a null Map.
488      *
489      * @return Map The current extras map.
490      */
getResultExtras(boolean makeMap)491     public final Bundle getResultExtras(boolean makeMap) {
492         if (mPendingResult == null) {
493             return null;
494         }
495         Bundle e = mPendingResult.mResultExtras;
496         if (!makeMap) return e;
497         if (e == null) mPendingResult.mResultExtras = e = new Bundle();
498         return e;
499     }
500 
501     /**
502      * Change all of the result data returned from this broadcasts; only works
503      * with broadcasts sent through
504      * {@link Context#sendOrderedBroadcast(Intent, String)
505      * Context.sendOrderedBroadcast}.  All current result data is replaced
506      * by the value given to this method.
507      *
508      * <p><strong>This method does not work with non-ordered broadcasts such
509      * as those sent with {@link Context#sendBroadcast(Intent)
510      * Context.sendBroadcast}</strong></p>
511      *
512      * @param code The new result code.  Often uses the
513      * Activity {@link android.app.Activity#RESULT_CANCELED} and
514      * {@link android.app.Activity#RESULT_OK} constants, though the
515      * actual meaning of this value is ultimately up to the broadcaster.
516      * @param data The new result data.  This is an arbitrary
517      * string whose interpretation is up to the broadcaster; may be null.
518      * @param extras The new extra data map.  This is a Bundle
519      * holding arbitrary data, whose interpretation is up to the
520      * broadcaster.  Can be set to null.  This completely
521      * replaces the current map (if any).
522      */
setResult(int code, String data, Bundle extras)523     public final void setResult(int code, String data, Bundle extras) {
524         checkSynchronousHint();
525         mPendingResult.mResultCode = code;
526         mPendingResult.mResultData = data;
527         mPendingResult.mResultExtras = extras;
528     }
529 
530     /**
531      * Returns the flag indicating whether or not this receiver should
532      * abort the current broadcast.
533      *
534      * @return True if the broadcast should be aborted.
535      */
getAbortBroadcast()536     public final boolean getAbortBroadcast() {
537         return mPendingResult != null ? mPendingResult.mAbortBroadcast : false;
538     }
539 
540     /**
541      * Sets the flag indicating that this receiver should abort the
542      * current broadcast; only works with broadcasts sent through
543      * {@link Context#sendOrderedBroadcast(Intent, String)
544      * Context.sendOrderedBroadcast}.  This will prevent
545      * any other broadcast receivers from receiving the broadcast. It will still
546      * call {@link #onReceive} of the BroadcastReceiver that the caller of
547      * {@link Context#sendOrderedBroadcast(Intent, String)
548      * Context.sendOrderedBroadcast} passed in.
549      *
550      * <p><strong>This method does not work with non-ordered broadcasts such
551      * as those sent with {@link Context#sendBroadcast(Intent)
552      * Context.sendBroadcast}</strong></p>
553      */
abortBroadcast()554     public final void abortBroadcast() {
555         checkSynchronousHint();
556         mPendingResult.mAbortBroadcast = true;
557     }
558 
559     /**
560      * Clears the flag indicating that this receiver should abort the current
561      * broadcast.
562      */
clearAbortBroadcast()563     public final void clearAbortBroadcast() {
564         if (mPendingResult != null) {
565             mPendingResult.mAbortBroadcast = false;
566         }
567     }
568 
569     /**
570      * Returns true if the receiver is currently processing an ordered
571      * broadcast.
572      */
isOrderedBroadcast()573     public final boolean isOrderedBroadcast() {
574         return mPendingResult != null ? mPendingResult.mOrderedHint : false;
575     }
576 
577     /**
578      * Returns true if the receiver is currently processing the initial
579      * value of a sticky broadcast -- that is, the value that was last
580      * broadcast and is currently held in the sticky cache, so this is
581      * not directly the result of a broadcast right now.
582      */
isInitialStickyBroadcast()583     public final boolean isInitialStickyBroadcast() {
584         return mPendingResult != null ? mPendingResult.mInitialStickyHint : false;
585     }
586 
587     /**
588      * For internal use, sets the hint about whether this BroadcastReceiver is
589      * running in ordered mode.
590      */
setOrderedHint(boolean isOrdered)591     public final void setOrderedHint(boolean isOrdered) {
592         // Accidentally left in the SDK.
593     }
594 
595     /**
596      * For internal use to set the result data that is active. @hide
597      */
setPendingResult(PendingResult result)598     public final void setPendingResult(PendingResult result) {
599         mPendingResult = result;
600     }
601 
602     /**
603      * For internal use to set the result data that is active. @hide
604      */
getPendingResult()605     public final PendingResult getPendingResult() {
606         return mPendingResult;
607     }
608 
609     /** @hide */
getSendingUserId()610     public int getSendingUserId() {
611         return mPendingResult.mSendingUser;
612     }
613 
614     /**
615      * Control inclusion of debugging help for mismatched
616      * calls to {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
617      * Context.registerReceiver()}.
618      * If called with true, before given to registerReceiver(), then the
619      * callstack of the following {@link Context#unregisterReceiver(BroadcastReceiver)
620      * Context.unregisterReceiver()} call is retained, to be printed if a later
621      * incorrect unregister call is made.  Note that doing this requires retaining
622      * information about the BroadcastReceiver for the lifetime of the app,
623      * resulting in a leak -- this should only be used for debugging.
624      */
setDebugUnregister(boolean debug)625     public final void setDebugUnregister(boolean debug) {
626         mDebugUnregister = debug;
627     }
628 
629     /**
630      * Return the last value given to {@link #setDebugUnregister}.
631      */
getDebugUnregister()632     public final boolean getDebugUnregister() {
633         return mDebugUnregister;
634     }
635 
checkSynchronousHint()636     void checkSynchronousHint() {
637         if (mPendingResult == null) {
638             throw new IllegalStateException("Call while result is not pending");
639         }
640 
641         // Note that we don't assert when receiving the initial sticky value,
642         // since that may have come from an ordered broadcast.  We'll catch
643         // them later when the real broadcast happens again.
644         if (mPendingResult.mOrderedHint || mPendingResult.mInitialStickyHint) {
645             return;
646         }
647         RuntimeException e = new RuntimeException(
648                 "BroadcastReceiver trying to return result during a non-ordered broadcast");
649         e.fillInStackTrace();
650         Log.e("BroadcastReceiver", e.getMessage(), e);
651     }
652 }
653 
654