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