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