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