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