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 17package android.content; 18 19import android.app.ActivityManager; 20import android.app.ActivityThread; 21import android.app.IActivityManager; 22import android.app.QueuedWork; 23import android.os.Bundle; 24import android.os.IBinder; 25import android.os.RemoteException; 26import android.util.Log; 27import 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 */ 45public 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 <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 */ 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