1 /* 2 * Copyright (C) 2010 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.app; 18 19 import com.android.internal.util.ArrayUtils; 20 21 import android.content.BroadcastReceiver; 22 import android.content.ComponentName; 23 import android.content.Context; 24 import android.content.IIntentReceiver; 25 import android.content.Intent; 26 import android.content.ServiceConnection; 27 import android.content.pm.ApplicationInfo; 28 import android.content.pm.IPackageManager; 29 import android.content.pm.PackageManager; 30 import android.content.res.AssetManager; 31 import android.content.res.CompatibilityInfo; 32 import android.content.res.Resources; 33 import android.os.Bundle; 34 import android.os.Handler; 35 import android.os.IBinder; 36 import android.os.Process; 37 import android.os.RemoteException; 38 import android.os.StrictMode; 39 import android.util.AndroidRuntimeException; 40 import android.util.Slog; 41 import android.view.CompatibilityInfoHolder; 42 43 import java.io.File; 44 import java.io.IOException; 45 import java.io.InputStream; 46 import java.lang.ref.WeakReference; 47 import java.net.URL; 48 import java.util.Enumeration; 49 import java.util.HashMap; 50 import java.util.Iterator; 51 52 final class IntentReceiverLeaked extends AndroidRuntimeException { 53 public IntentReceiverLeaked(String msg) { 54 super(msg); 55 } 56 } 57 58 final class ServiceConnectionLeaked extends AndroidRuntimeException { 59 public ServiceConnectionLeaked(String msg) { 60 super(msg); 61 } 62 } 63 64 /** 65 * Local state maintained about a currently loaded .apk. 66 * @hide 67 */ 68 public final class LoadedApk { 69 70 private final ActivityThread mActivityThread; 71 private final ApplicationInfo mApplicationInfo; 72 final String mPackageName; 73 private final String mAppDir; 74 private final String mResDir; 75 private final String[] mSharedLibraries; 76 private final String mDataDir; 77 private final String mLibDir; 78 private final File mDataDirFile; 79 private final ClassLoader mBaseClassLoader; 80 private final boolean mSecurityViolation; 81 private final boolean mIncludeCode; 82 public final CompatibilityInfoHolder mCompatibilityInfo = new CompatibilityInfoHolder(); 83 Resources mResources; 84 private ClassLoader mClassLoader; 85 private Application mApplication; 86 87 private final HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mReceivers 88 = new HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>(); 89 private final HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mUnregisteredReceivers 90 = new HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>(); 91 private final HashMap<Context, HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices 92 = new HashMap<Context, HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>>(); 93 private final HashMap<Context, HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mUnboundServices 94 = new HashMap<Context, HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>>(); 95 96 int mClientCount = 0; 97 98 Application getApplication() { 99 return mApplication; 100 } 101 102 /** 103 * Create information about a new .apk 104 * 105 * NOTE: This constructor is called with ActivityThread's lock held, 106 * so MUST NOT call back out to the activity manager. 107 */ 108 public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo, 109 CompatibilityInfo compatInfo, 110 ActivityThread mainThread, ClassLoader baseLoader, 111 boolean securityViolation, boolean includeCode) { 112 mActivityThread = activityThread; 113 mApplicationInfo = aInfo; 114 mPackageName = aInfo.packageName; 115 mAppDir = aInfo.sourceDir; 116 mResDir = aInfo.uid == Process.myUid() ? aInfo.sourceDir 117 : aInfo.publicSourceDir; 118 mSharedLibraries = aInfo.sharedLibraryFiles; 119 mDataDir = aInfo.dataDir; 120 mDataDirFile = mDataDir != null ? new File(mDataDir) : null; 121 mLibDir = aInfo.nativeLibraryDir; 122 mBaseClassLoader = baseLoader; 123 mSecurityViolation = securityViolation; 124 mIncludeCode = includeCode; 125 mCompatibilityInfo.set(compatInfo); 126 127 if (mAppDir == null) { 128 if (ActivityThread.mSystemContext == null) { 129 ActivityThread.mSystemContext = 130 ContextImpl.createSystemContext(mainThread); 131 ActivityThread.mSystemContext.getResources().updateConfiguration( 132 mainThread.getConfiguration(), 133 mainThread.getDisplayMetricsLocked(compatInfo, false), 134 compatInfo); 135 //Slog.i(TAG, "Created system resources " 136 // + mSystemContext.getResources() + ": " 137 // + mSystemContext.getResources().getConfiguration()); 138 } 139 mClassLoader = ActivityThread.mSystemContext.getClassLoader(); 140 mResources = ActivityThread.mSystemContext.getResources(); 141 } 142 } 143 144 public LoadedApk(ActivityThread activityThread, String name, 145 Context systemContext, ApplicationInfo info, CompatibilityInfo compatInfo) { 146 mActivityThread = activityThread; 147 mApplicationInfo = info != null ? info : new ApplicationInfo(); 148 mApplicationInfo.packageName = name; 149 mPackageName = name; 150 mAppDir = null; 151 mResDir = null; 152 mSharedLibraries = null; 153 mDataDir = null; 154 mDataDirFile = null; 155 mLibDir = null; 156 mBaseClassLoader = null; 157 mSecurityViolation = false; 158 mIncludeCode = true; 159 mClassLoader = systemContext.getClassLoader(); 160 mResources = systemContext.getResources(); 161 mCompatibilityInfo.set(compatInfo); 162 } 163 164 public String getPackageName() { 165 return mPackageName; 166 } 167 168 public ApplicationInfo getApplicationInfo() { 169 return mApplicationInfo; 170 } 171 172 public boolean isSecurityViolation() { 173 return mSecurityViolation; 174 } 175 176 /** 177 * Gets the array of shared libraries that are listed as 178 * used by the given package. 179 * 180 * @param packageName the name of the package (note: not its 181 * file name) 182 * @return null-ok; the array of shared libraries, each one 183 * a fully-qualified path 184 */ 185 private static String[] getLibrariesFor(String packageName) { 186 ApplicationInfo ai = null; 187 try { 188 ai = ActivityThread.getPackageManager().getApplicationInfo(packageName, 189 PackageManager.GET_SHARED_LIBRARY_FILES); 190 } catch (RemoteException e) { 191 throw new AssertionError(e); 192 } 193 194 if (ai == null) { 195 return null; 196 } 197 198 return ai.sharedLibraryFiles; 199 } 200 201 /** 202 * Combines two arrays (of library names) such that they are 203 * concatenated in order but are devoid of duplicates. The 204 * result is a single string with the names of the libraries 205 * separated by colons, or <code>null</code> if both lists 206 * were <code>null</code> or empty. 207 * 208 * @param list1 null-ok; the first list 209 * @param list2 null-ok; the second list 210 * @return null-ok; the combination 211 */ 212 private static String combineLibs(String[] list1, String[] list2) { 213 StringBuilder result = new StringBuilder(300); 214 boolean first = true; 215 216 if (list1 != null) { 217 for (String s : list1) { 218 if (first) { 219 first = false; 220 } else { 221 result.append(':'); 222 } 223 result.append(s); 224 } 225 } 226 227 // Only need to check for duplicates if list1 was non-empty. 228 boolean dupCheck = !first; 229 230 if (list2 != null) { 231 for (String s : list2) { 232 if (dupCheck && ArrayUtils.contains(list1, s)) { 233 continue; 234 } 235 236 if (first) { 237 first = false; 238 } else { 239 result.append(':'); 240 } 241 result.append(s); 242 } 243 } 244 245 return result.toString(); 246 } 247 248 public ClassLoader getClassLoader() { 249 synchronized (this) { 250 if (mClassLoader != null) { 251 return mClassLoader; 252 } 253 254 if (mIncludeCode && !mPackageName.equals("android")) { 255 String zip = mAppDir; 256 257 /* 258 * The following is a bit of a hack to inject 259 * instrumentation into the system: If the app 260 * being started matches one of the instrumentation names, 261 * then we combine both the "instrumentation" and 262 * "instrumented" app into the path, along with the 263 * concatenation of both apps' shared library lists. 264 */ 265 266 String instrumentationAppDir = 267 mActivityThread.mInstrumentationAppDir; 268 String instrumentationAppPackage = 269 mActivityThread.mInstrumentationAppPackage; 270 String instrumentedAppDir = 271 mActivityThread.mInstrumentedAppDir; 272 String[] instrumentationLibs = null; 273 274 if (mAppDir.equals(instrumentationAppDir) 275 || mAppDir.equals(instrumentedAppDir)) { 276 zip = instrumentationAppDir + ":" + instrumentedAppDir; 277 if (! instrumentedAppDir.equals(instrumentationAppDir)) { 278 instrumentationLibs = 279 getLibrariesFor(instrumentationAppPackage); 280 } 281 } 282 283 if ((mSharedLibraries != null) || 284 (instrumentationLibs != null)) { 285 zip = 286 combineLibs(mSharedLibraries, instrumentationLibs) 287 + ':' + zip; 288 } 289 290 /* 291 * With all the combination done (if necessary, actually 292 * create the class loader. 293 */ 294 295 if (ActivityThread.localLOGV) 296 Slog.v(ActivityThread.TAG, "Class path: " + zip + ", JNI path: " + mLibDir); 297 298 // Temporarily disable logging of disk reads on the Looper thread 299 // as this is early and necessary. 300 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); 301 302 mClassLoader = 303 ApplicationLoaders.getDefault().getClassLoader( 304 zip, mLibDir, mBaseClassLoader); 305 initializeJavaContextClassLoader(); 306 307 StrictMode.setThreadPolicy(oldPolicy); 308 } else { 309 if (mBaseClassLoader == null) { 310 mClassLoader = ClassLoader.getSystemClassLoader(); 311 } else { 312 mClassLoader = mBaseClassLoader; 313 } 314 } 315 return mClassLoader; 316 } 317 } 318 319 /** 320 * Setup value for Thread.getContextClassLoader(). If the 321 * package will not run in in a VM with other packages, we set 322 * the Java context ClassLoader to the 323 * PackageInfo.getClassLoader value. However, if this VM can 324 * contain multiple packages, we intead set the Java context 325 * ClassLoader to a proxy that will warn about the use of Java 326 * context ClassLoaders and then fall through to use the 327 * system ClassLoader. 328 * 329 * <p> Note that this is similar to but not the same as the 330 * android.content.Context.getClassLoader(). While both 331 * context class loaders are typically set to the 332 * PathClassLoader used to load the package archive in the 333 * single application per VM case, a single Android process 334 * may contain several Contexts executing on one thread with 335 * their own logical ClassLoaders while the Java context 336 * ClassLoader is a thread local. This is why in the case when 337 * we have multiple packages per VM we do not set the Java 338 * context ClassLoader to an arbitrary but instead warn the 339 * user to set their own if we detect that they are using a 340 * Java library that expects it to be set. 341 */ 342 private void initializeJavaContextClassLoader() { 343 IPackageManager pm = ActivityThread.getPackageManager(); 344 android.content.pm.PackageInfo pi; 345 try { 346 pi = pm.getPackageInfo(mPackageName, 0); 347 } catch (RemoteException e) { 348 throw new AssertionError(e); 349 } 350 /* 351 * Two possible indications that this package could be 352 * sharing its virtual machine with other packages: 353 * 354 * 1.) the sharedUserId attribute is set in the manifest, 355 * indicating a request to share a VM with other 356 * packages with the same sharedUserId. 357 * 358 * 2.) the application element of the manifest has an 359 * attribute specifying a non-default process name, 360 * indicating the desire to run in another packages VM. 361 */ 362 boolean sharedUserIdSet = (pi.sharedUserId != null); 363 boolean processNameNotDefault = 364 (pi.applicationInfo != null && 365 !mPackageName.equals(pi.applicationInfo.processName)); 366 boolean sharable = (sharedUserIdSet || processNameNotDefault); 367 ClassLoader contextClassLoader = 368 (sharable) 369 ? new WarningContextClassLoader() 370 : mClassLoader; 371 Thread.currentThread().setContextClassLoader(contextClassLoader); 372 } 373 374 private static class WarningContextClassLoader extends ClassLoader { 375 376 private static boolean warned = false; 377 378 private void warn(String methodName) { 379 if (warned) { 380 return; 381 } 382 warned = true; 383 Thread.currentThread().setContextClassLoader(getParent()); 384 Slog.w(ActivityThread.TAG, "ClassLoader." + methodName + ": " + 385 "The class loader returned by " + 386 "Thread.getContextClassLoader() may fail for processes " + 387 "that host multiple applications. You should explicitly " + 388 "specify a context class loader. For example: " + 389 "Thread.setContextClassLoader(getClass().getClassLoader());"); 390 } 391 392 @Override public URL getResource(String resName) { 393 warn("getResource"); 394 return getParent().getResource(resName); 395 } 396 397 @Override public Enumeration<URL> getResources(String resName) throws IOException { 398 warn("getResources"); 399 return getParent().getResources(resName); 400 } 401 402 @Override public InputStream getResourceAsStream(String resName) { 403 warn("getResourceAsStream"); 404 return getParent().getResourceAsStream(resName); 405 } 406 407 @Override public Class<?> loadClass(String className) throws ClassNotFoundException { 408 warn("loadClass"); 409 return getParent().loadClass(className); 410 } 411 412 @Override public void setClassAssertionStatus(String cname, boolean enable) { 413 warn("setClassAssertionStatus"); 414 getParent().setClassAssertionStatus(cname, enable); 415 } 416 417 @Override public void setPackageAssertionStatus(String pname, boolean enable) { 418 warn("setPackageAssertionStatus"); 419 getParent().setPackageAssertionStatus(pname, enable); 420 } 421 422 @Override public void setDefaultAssertionStatus(boolean enable) { 423 warn("setDefaultAssertionStatus"); 424 getParent().setDefaultAssertionStatus(enable); 425 } 426 427 @Override public void clearAssertionStatus() { 428 warn("clearAssertionStatus"); 429 getParent().clearAssertionStatus(); 430 } 431 } 432 433 public String getAppDir() { 434 return mAppDir; 435 } 436 437 public String getResDir() { 438 return mResDir; 439 } 440 441 public String getDataDir() { 442 return mDataDir; 443 } 444 445 public File getDataDirFile() { 446 return mDataDirFile; 447 } 448 449 public AssetManager getAssets(ActivityThread mainThread) { 450 return getResources(mainThread).getAssets(); 451 } 452 453 public Resources getResources(ActivityThread mainThread) { 454 if (mResources == null) { 455 mResources = mainThread.getTopLevelResources(mResDir, this); 456 } 457 return mResources; 458 } 459 460 public Application makeApplication(boolean forceDefaultAppClass, 461 Instrumentation instrumentation) { 462 if (mApplication != null) { 463 return mApplication; 464 } 465 466 Application app = null; 467 468 String appClass = mApplicationInfo.className; 469 if (forceDefaultAppClass || (appClass == null)) { 470 appClass = "android.app.Application"; 471 } 472 473 try { 474 java.lang.ClassLoader cl = getClassLoader(); 475 ContextImpl appContext = new ContextImpl(); 476 appContext.init(this, null, mActivityThread); 477 app = mActivityThread.mInstrumentation.newApplication( 478 cl, appClass, appContext); 479 appContext.setOuterContext(app); 480 } catch (Exception e) { 481 if (!mActivityThread.mInstrumentation.onException(app, e)) { 482 throw new RuntimeException( 483 "Unable to instantiate application " + appClass 484 + ": " + e.toString(), e); 485 } 486 } 487 mActivityThread.mAllApplications.add(app); 488 mApplication = app; 489 490 if (instrumentation != null) { 491 try { 492 instrumentation.callApplicationOnCreate(app); 493 } catch (Exception e) { 494 if (!instrumentation.onException(app, e)) { 495 throw new RuntimeException( 496 "Unable to create application " + app.getClass().getName() 497 + ": " + e.toString(), e); 498 } 499 } 500 } 501 502 return app; 503 } 504 505 public void removeContextRegistrations(Context context, 506 String who, String what) { 507 HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> rmap = 508 mReceivers.remove(context); 509 if (rmap != null) { 510 Iterator<LoadedApk.ReceiverDispatcher> it = rmap.values().iterator(); 511 while (it.hasNext()) { 512 LoadedApk.ReceiverDispatcher rd = it.next(); 513 IntentReceiverLeaked leak = new IntentReceiverLeaked( 514 what + " " + who + " has leaked IntentReceiver " 515 + rd.getIntentReceiver() + " that was " + 516 "originally registered here. Are you missing a " + 517 "call to unregisterReceiver()?"); 518 leak.setStackTrace(rd.getLocation().getStackTrace()); 519 Slog.e(ActivityThread.TAG, leak.getMessage(), leak); 520 try { 521 ActivityManagerNative.getDefault().unregisterReceiver( 522 rd.getIIntentReceiver()); 523 } catch (RemoteException e) { 524 // system crashed, nothing we can do 525 } 526 } 527 } 528 mUnregisteredReceivers.remove(context); 529 //Slog.i(TAG, "Receiver registrations: " + mReceivers); 530 HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> smap = 531 mServices.remove(context); 532 if (smap != null) { 533 Iterator<LoadedApk.ServiceDispatcher> it = smap.values().iterator(); 534 while (it.hasNext()) { 535 LoadedApk.ServiceDispatcher sd = it.next(); 536 ServiceConnectionLeaked leak = new ServiceConnectionLeaked( 537 what + " " + who + " has leaked ServiceConnection " 538 + sd.getServiceConnection() + " that was originally bound here"); 539 leak.setStackTrace(sd.getLocation().getStackTrace()); 540 Slog.e(ActivityThread.TAG, leak.getMessage(), leak); 541 try { 542 ActivityManagerNative.getDefault().unbindService( 543 sd.getIServiceConnection()); 544 } catch (RemoteException e) { 545 // system crashed, nothing we can do 546 } 547 sd.doForget(); 548 } 549 } 550 mUnboundServices.remove(context); 551 //Slog.i(TAG, "Service registrations: " + mServices); 552 } 553 554 public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r, 555 Context context, Handler handler, 556 Instrumentation instrumentation, boolean registered) { 557 synchronized (mReceivers) { 558 LoadedApk.ReceiverDispatcher rd = null; 559 HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null; 560 if (registered) { 561 map = mReceivers.get(context); 562 if (map != null) { 563 rd = map.get(r); 564 } 565 } 566 if (rd == null) { 567 rd = new ReceiverDispatcher(r, context, handler, 568 instrumentation, registered); 569 if (registered) { 570 if (map == null) { 571 map = new HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>(); 572 mReceivers.put(context, map); 573 } 574 map.put(r, rd); 575 } 576 } else { 577 rd.validate(context, handler); 578 } 579 rd.mForgotten = false; 580 return rd.getIIntentReceiver(); 581 } 582 } 583 584 public IIntentReceiver forgetReceiverDispatcher(Context context, 585 BroadcastReceiver r) { 586 synchronized (mReceivers) { 587 HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = mReceivers.get(context); 588 LoadedApk.ReceiverDispatcher rd = null; 589 if (map != null) { 590 rd = map.get(r); 591 if (rd != null) { 592 map.remove(r); 593 if (map.size() == 0) { 594 mReceivers.remove(context); 595 } 596 if (r.getDebugUnregister()) { 597 HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder 598 = mUnregisteredReceivers.get(context); 599 if (holder == null) { 600 holder = new HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>(); 601 mUnregisteredReceivers.put(context, holder); 602 } 603 RuntimeException ex = new IllegalArgumentException( 604 "Originally unregistered here:"); 605 ex.fillInStackTrace(); 606 rd.setUnregisterLocation(ex); 607 holder.put(r, rd); 608 } 609 rd.mForgotten = true; 610 return rd.getIIntentReceiver(); 611 } 612 } 613 HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder 614 = mUnregisteredReceivers.get(context); 615 if (holder != null) { 616 rd = holder.get(r); 617 if (rd != null) { 618 RuntimeException ex = rd.getUnregisterLocation(); 619 throw new IllegalArgumentException( 620 "Unregistering Receiver " + r 621 + " that was already unregistered", ex); 622 } 623 } 624 if (context == null) { 625 throw new IllegalStateException("Unbinding Receiver " + r 626 + " from Context that is no longer in use: " + context); 627 } else { 628 throw new IllegalArgumentException("Receiver not registered: " + r); 629 } 630 631 } 632 } 633 634 static final class ReceiverDispatcher { 635 636 final static class InnerReceiver extends IIntentReceiver.Stub { 637 final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher; 638 final LoadedApk.ReceiverDispatcher mStrongRef; 639 640 InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) { 641 mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd); 642 mStrongRef = strong ? rd : null; 643 } 644 public void performReceive(Intent intent, int resultCode, 645 String data, Bundle extras, boolean ordered, boolean sticky) { 646 LoadedApk.ReceiverDispatcher rd = mDispatcher.get(); 647 if (ActivityThread.DEBUG_BROADCAST) { 648 int seq = intent.getIntExtra("seq", -1); 649 Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction() + " seq=" + seq 650 + " to " + (rd != null ? rd.mReceiver : null)); 651 } 652 if (rd != null) { 653 rd.performReceive(intent, resultCode, data, extras, 654 ordered, sticky); 655 } else { 656 // The activity manager dispatched a broadcast to a registered 657 // receiver in this process, but before it could be delivered the 658 // receiver was unregistered. Acknowledge the broadcast on its 659 // behalf so that the system's broadcast sequence can continue. 660 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, 661 "Finishing broadcast to unregistered receiver"); 662 IActivityManager mgr = ActivityManagerNative.getDefault(); 663 try { 664 if (extras != null) { 665 extras.setAllowFds(false); 666 } 667 mgr.finishReceiver(this, resultCode, data, extras, false); 668 } catch (RemoteException e) { 669 Slog.w(ActivityThread.TAG, "Couldn't finish broadcast to unregistered receiver"); 670 } 671 } 672 } 673 } 674 675 final IIntentReceiver.Stub mIIntentReceiver; 676 final BroadcastReceiver mReceiver; 677 final Context mContext; 678 final Handler mActivityThread; 679 final Instrumentation mInstrumentation; 680 final boolean mRegistered; 681 final IntentReceiverLeaked mLocation; 682 RuntimeException mUnregisterLocation; 683 boolean mForgotten; 684 685 final class Args extends BroadcastReceiver.PendingResult implements Runnable { 686 private Intent mCurIntent; 687 private final boolean mOrdered; 688 689 public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras, 690 boolean ordered, boolean sticky) { 691 super(resultCode, resultData, resultExtras, 692 mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, 693 ordered, sticky, mIIntentReceiver.asBinder()); 694 mCurIntent = intent; 695 mOrdered = ordered; 696 } 697 698 public void run() { 699 final BroadcastReceiver receiver = mReceiver; 700 final boolean ordered = mOrdered; 701 702 if (ActivityThread.DEBUG_BROADCAST) { 703 int seq = mCurIntent.getIntExtra("seq", -1); 704 Slog.i(ActivityThread.TAG, "Dispatching broadcast " + mCurIntent.getAction() 705 + " seq=" + seq + " to " + mReceiver); 706 Slog.i(ActivityThread.TAG, " mRegistered=" + mRegistered 707 + " mOrderedHint=" + ordered); 708 } 709 710 final IActivityManager mgr = ActivityManagerNative.getDefault(); 711 final Intent intent = mCurIntent; 712 mCurIntent = null; 713 714 if (receiver == null || mForgotten) { 715 if (mRegistered && ordered) { 716 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, 717 "Finishing null broadcast to " + mReceiver); 718 sendFinished(mgr); 719 } 720 return; 721 } 722 723 try { 724 ClassLoader cl = mReceiver.getClass().getClassLoader(); 725 intent.setExtrasClassLoader(cl); 726 setExtrasClassLoader(cl); 727 receiver.setPendingResult(this); 728 receiver.onReceive(mContext, intent); 729 } catch (Exception e) { 730 if (mRegistered && ordered) { 731 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, 732 "Finishing failed broadcast to " + mReceiver); 733 sendFinished(mgr); 734 } 735 if (mInstrumentation == null || 736 !mInstrumentation.onException(mReceiver, e)) { 737 throw new RuntimeException( 738 "Error receiving broadcast " + intent 739 + " in " + mReceiver, e); 740 } 741 } 742 743 if (receiver.getPendingResult() != null) { 744 finish(); 745 } 746 } 747 } 748 749 ReceiverDispatcher(BroadcastReceiver receiver, Context context, 750 Handler activityThread, Instrumentation instrumentation, 751 boolean registered) { 752 if (activityThread == null) { 753 throw new NullPointerException("Handler must not be null"); 754 } 755 756 mIIntentReceiver = new InnerReceiver(this, !registered); 757 mReceiver = receiver; 758 mContext = context; 759 mActivityThread = activityThread; 760 mInstrumentation = instrumentation; 761 mRegistered = registered; 762 mLocation = new IntentReceiverLeaked(null); 763 mLocation.fillInStackTrace(); 764 } 765 766 void validate(Context context, Handler activityThread) { 767 if (mContext != context) { 768 throw new IllegalStateException( 769 "Receiver " + mReceiver + 770 " registered with differing Context (was " + 771 mContext + " now " + context + ")"); 772 } 773 if (mActivityThread != activityThread) { 774 throw new IllegalStateException( 775 "Receiver " + mReceiver + 776 " registered with differing handler (was " + 777 mActivityThread + " now " + activityThread + ")"); 778 } 779 } 780 781 IntentReceiverLeaked getLocation() { 782 return mLocation; 783 } 784 785 BroadcastReceiver getIntentReceiver() { 786 return mReceiver; 787 } 788 789 IIntentReceiver getIIntentReceiver() { 790 return mIIntentReceiver; 791 } 792 793 void setUnregisterLocation(RuntimeException ex) { 794 mUnregisterLocation = ex; 795 } 796 797 RuntimeException getUnregisterLocation() { 798 return mUnregisterLocation; 799 } 800 801 public void performReceive(Intent intent, int resultCode, 802 String data, Bundle extras, boolean ordered, boolean sticky) { 803 if (ActivityThread.DEBUG_BROADCAST) { 804 int seq = intent.getIntExtra("seq", -1); 805 Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq 806 + " to " + mReceiver); 807 } 808 Args args = new Args(intent, resultCode, data, extras, ordered, sticky); 809 if (!mActivityThread.post(args)) { 810 if (mRegistered && ordered) { 811 IActivityManager mgr = ActivityManagerNative.getDefault(); 812 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, 813 "Finishing sync broadcast to " + mReceiver); 814 args.sendFinished(mgr); 815 } 816 } 817 } 818 819 } 820 821 public final IServiceConnection getServiceDispatcher(ServiceConnection c, 822 Context context, Handler handler, int flags) { 823 synchronized (mServices) { 824 LoadedApk.ServiceDispatcher sd = null; 825 HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context); 826 if (map != null) { 827 sd = map.get(c); 828 } 829 if (sd == null) { 830 sd = new ServiceDispatcher(c, context, handler, flags); 831 if (map == null) { 832 map = new HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>(); 833 mServices.put(context, map); 834 } 835 map.put(c, sd); 836 } else { 837 sd.validate(context, handler); 838 } 839 return sd.getIServiceConnection(); 840 } 841 } 842 843 public final IServiceConnection forgetServiceDispatcher(Context context, 844 ServiceConnection c) { 845 synchronized (mServices) { 846 HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> map 847 = mServices.get(context); 848 LoadedApk.ServiceDispatcher sd = null; 849 if (map != null) { 850 sd = map.get(c); 851 if (sd != null) { 852 map.remove(c); 853 sd.doForget(); 854 if (map.size() == 0) { 855 mServices.remove(context); 856 } 857 if ((sd.getFlags()&Context.BIND_DEBUG_UNBIND) != 0) { 858 HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder 859 = mUnboundServices.get(context); 860 if (holder == null) { 861 holder = new HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>(); 862 mUnboundServices.put(context, holder); 863 } 864 RuntimeException ex = new IllegalArgumentException( 865 "Originally unbound here:"); 866 ex.fillInStackTrace(); 867 sd.setUnbindLocation(ex); 868 holder.put(c, sd); 869 } 870 return sd.getIServiceConnection(); 871 } 872 } 873 HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder 874 = mUnboundServices.get(context); 875 if (holder != null) { 876 sd = holder.get(c); 877 if (sd != null) { 878 RuntimeException ex = sd.getUnbindLocation(); 879 throw new IllegalArgumentException( 880 "Unbinding Service " + c 881 + " that was already unbound", ex); 882 } 883 } 884 if (context == null) { 885 throw new IllegalStateException("Unbinding Service " + c 886 + " from Context that is no longer in use: " + context); 887 } else { 888 throw new IllegalArgumentException("Service not registered: " + c); 889 } 890 } 891 } 892 893 static final class ServiceDispatcher { 894 private final ServiceDispatcher.InnerConnection mIServiceConnection; 895 private final ServiceConnection mConnection; 896 private final Context mContext; 897 private final Handler mActivityThread; 898 private final ServiceConnectionLeaked mLocation; 899 private final int mFlags; 900 901 private RuntimeException mUnbindLocation; 902 903 private boolean mDied; 904 905 private static class ConnectionInfo { 906 IBinder binder; 907 IBinder.DeathRecipient deathMonitor; 908 } 909 910 private static class InnerConnection extends IServiceConnection.Stub { 911 final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher; 912 913 InnerConnection(LoadedApk.ServiceDispatcher sd) { 914 mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd); 915 } 916 917 public void connected(ComponentName name, IBinder service) throws RemoteException { 918 LoadedApk.ServiceDispatcher sd = mDispatcher.get(); 919 if (sd != null) { 920 sd.connected(name, service); 921 } 922 } 923 } 924 925 private final HashMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections 926 = new HashMap<ComponentName, ServiceDispatcher.ConnectionInfo>(); 927 928 ServiceDispatcher(ServiceConnection conn, 929 Context context, Handler activityThread, int flags) { 930 mIServiceConnection = new InnerConnection(this); 931 mConnection = conn; 932 mContext = context; 933 mActivityThread = activityThread; 934 mLocation = new ServiceConnectionLeaked(null); 935 mLocation.fillInStackTrace(); 936 mFlags = flags; 937 } 938 939 void validate(Context context, Handler activityThread) { 940 if (mContext != context) { 941 throw new RuntimeException( 942 "ServiceConnection " + mConnection + 943 " registered with differing Context (was " + 944 mContext + " now " + context + ")"); 945 } 946 if (mActivityThread != activityThread) { 947 throw new RuntimeException( 948 "ServiceConnection " + mConnection + 949 " registered with differing handler (was " + 950 mActivityThread + " now " + activityThread + ")"); 951 } 952 } 953 954 void doForget() { 955 synchronized(this) { 956 Iterator<ServiceDispatcher.ConnectionInfo> it = mActiveConnections.values().iterator(); 957 while (it.hasNext()) { 958 ServiceDispatcher.ConnectionInfo ci = it.next(); 959 ci.binder.unlinkToDeath(ci.deathMonitor, 0); 960 } 961 mActiveConnections.clear(); 962 } 963 } 964 965 ServiceConnectionLeaked getLocation() { 966 return mLocation; 967 } 968 969 ServiceConnection getServiceConnection() { 970 return mConnection; 971 } 972 973 IServiceConnection getIServiceConnection() { 974 return mIServiceConnection; 975 } 976 977 int getFlags() { 978 return mFlags; 979 } 980 981 void setUnbindLocation(RuntimeException ex) { 982 mUnbindLocation = ex; 983 } 984 985 RuntimeException getUnbindLocation() { 986 return mUnbindLocation; 987 } 988 989 public void connected(ComponentName name, IBinder service) { 990 if (mActivityThread != null) { 991 mActivityThread.post(new RunConnection(name, service, 0)); 992 } else { 993 doConnected(name, service); 994 } 995 } 996 997 public void death(ComponentName name, IBinder service) { 998 ServiceDispatcher.ConnectionInfo old; 999 1000 synchronized (this) { 1001 mDied = true; 1002 old = mActiveConnections.remove(name); 1003 if (old == null || old.binder != service) { 1004 // Death for someone different than who we last 1005 // reported... just ignore it. 1006 return; 1007 } 1008 old.binder.unlinkToDeath(old.deathMonitor, 0); 1009 } 1010 1011 if (mActivityThread != null) { 1012 mActivityThread.post(new RunConnection(name, service, 1)); 1013 } else { 1014 doDeath(name, service); 1015 } 1016 } 1017 1018 public void doConnected(ComponentName name, IBinder service) { 1019 ServiceDispatcher.ConnectionInfo old; 1020 ServiceDispatcher.ConnectionInfo info; 1021 1022 synchronized (this) { 1023 old = mActiveConnections.get(name); 1024 if (old != null && old.binder == service) { 1025 // Huh, already have this one. Oh well! 1026 return; 1027 } 1028 1029 if (service != null) { 1030 // A new service is being connected... set it all up. 1031 mDied = false; 1032 info = new ConnectionInfo(); 1033 info.binder = service; 1034 info.deathMonitor = new DeathMonitor(name, service); 1035 try { 1036 service.linkToDeath(info.deathMonitor, 0); 1037 mActiveConnections.put(name, info); 1038 } catch (RemoteException e) { 1039 // This service was dead before we got it... just 1040 // don't do anything with it. 1041 mActiveConnections.remove(name); 1042 return; 1043 } 1044 1045 } else { 1046 // The named service is being disconnected... clean up. 1047 mActiveConnections.remove(name); 1048 } 1049 1050 if (old != null) { 1051 old.binder.unlinkToDeath(old.deathMonitor, 0); 1052 } 1053 } 1054 1055 // If there was an old service, it is not disconnected. 1056 if (old != null) { 1057 mConnection.onServiceDisconnected(name); 1058 } 1059 // If there is a new service, it is now connected. 1060 if (service != null) { 1061 mConnection.onServiceConnected(name, service); 1062 } 1063 } 1064 1065 public void doDeath(ComponentName name, IBinder service) { 1066 mConnection.onServiceDisconnected(name); 1067 } 1068 1069 private final class RunConnection implements Runnable { 1070 RunConnection(ComponentName name, IBinder service, int command) { 1071 mName = name; 1072 mService = service; 1073 mCommand = command; 1074 } 1075 1076 public void run() { 1077 if (mCommand == 0) { 1078 doConnected(mName, mService); 1079 } else if (mCommand == 1) { 1080 doDeath(mName, mService); 1081 } 1082 } 1083 1084 final ComponentName mName; 1085 final IBinder mService; 1086 final int mCommand; 1087 } 1088 1089 private final class DeathMonitor implements IBinder.DeathRecipient 1090 { 1091 DeathMonitor(ComponentName name, IBinder service) { 1092 mName = name; 1093 mService = service; 1094 } 1095 1096 public void binderDied() { 1097 death(mName, mService); 1098 } 1099 1100 final ComponentName mName; 1101 final IBinder mService; 1102 } 1103 } 1104 } 1105