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