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