Home | History | Annotate | Download | only in content
      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 */
     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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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 */
    238         public void setExtrasClassLoader(ClassLoader cl) {
    239             if (mResultExtras != null) {
    240                 mResultExtras.setClassLoader(cl);
    241             }
    242         }
    243 
    244         /** @hide */
    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 */
    270         public int getSendingUserId() {
    271             return mSendingUser;
    272         }
    273 
    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 
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    605     public final PendingResult getPendingResult() {
    606         return mPendingResult;
    607     }
    608 
    609     /** @hide */
    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      */
    625     public final void setDebugUnregister(boolean debug) {
    626         mDebugUnregister = debug;
    627     }
    628 
    629     /**
    630      * Return the last value given to {@link #setDebugUnregister}.
    631      */
    632     public final boolean getDebugUnregister() {
    633         return mDebugUnregister;
    634     }
    635 
    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