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