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