LoadedApk.java revision 39bfee5e3674faea992c32204abc1c03429b8cda
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 android.text.TextUtils; 20import android.util.ArrayMap; 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.FileUtils; 35import android.os.Handler; 36import android.os.IBinder; 37import android.os.Process; 38import android.os.RemoteException; 39import android.os.StrictMode; 40import android.os.Trace; 41import android.os.UserHandle; 42import android.util.AndroidRuntimeException; 43import android.util.Log; 44import android.util.Slog; 45import android.util.SparseArray; 46import android.view.DisplayAdjustments; 47import android.view.Display; 48import android.os.SystemProperties; 49 50import dalvik.system.VMRuntime; 51 52import java.io.File; 53import java.io.IOException; 54import java.io.InputStream; 55import java.lang.ref.WeakReference; 56import java.lang.reflect.InvocationTargetException; 57import java.lang.reflect.Method; 58import java.net.URL; 59import java.util.List; 60import java.util.ArrayList; 61import java.util.Arrays; 62import java.util.Collections; 63import java.util.Enumeration; 64import java.util.Objects; 65 66final class IntentReceiverLeaked extends AndroidRuntimeException { 67 public IntentReceiverLeaked(String msg) { 68 super(msg); 69 } 70} 71 72final class ServiceConnectionLeaked extends AndroidRuntimeException { 73 public ServiceConnectionLeaked(String msg) { 74 super(msg); 75 } 76} 77 78/** 79 * Local state maintained about a currently loaded .apk. 80 * @hide 81 */ 82public final class LoadedApk { 83 84 private static final String TAG = "LoadedApk"; 85 86 private final ActivityThread mActivityThread; 87 final String mPackageName; 88 private ApplicationInfo mApplicationInfo; 89 private String mAppDir; 90 private String mResDir; 91 private String[] mSplitAppDirs; 92 private String[] mSplitResDirs; 93 private String[] mOverlayDirs; 94 private String[] mSharedLibraries; 95 private String mDataDir; 96 private String mLibDir; 97 private File mDataDirFile; 98 private File mDeviceEncryptedDataDirFile; 99 private File mCredentialEncryptedDataDirFile; 100 private final ClassLoader mBaseClassLoader; 101 private final boolean mSecurityViolation; 102 private final boolean mIncludeCode; 103 private final boolean mRegisterPackage; 104 private final DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments(); 105 /** WARNING: This may change. Don't hold external references to it. */ 106 Resources mResources; 107 private ClassLoader mClassLoader; 108 private Application mApplication; 109 110 private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers 111 = new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>(); 112 private final ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mUnregisteredReceivers 113 = new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>(); 114 private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices 115 = new ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>>(); 116 private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mUnboundServices 117 = new ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>>(); 118 119 int mClientCount = 0; 120 121 Application getApplication() { 122 return mApplication; 123 } 124 125 /** 126 * Create information about a new .apk 127 * 128 * NOTE: This constructor is called with ActivityThread's lock held, 129 * so MUST NOT call back out to the activity manager. 130 */ 131 public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo, 132 CompatibilityInfo compatInfo, ClassLoader baseLoader, 133 boolean securityViolation, boolean includeCode, boolean registerPackage) { 134 135 mActivityThread = activityThread; 136 setApplicationInfo(aInfo); 137 mPackageName = aInfo.packageName; 138 mBaseClassLoader = baseLoader; 139 mSecurityViolation = securityViolation; 140 mIncludeCode = includeCode; 141 mRegisterPackage = registerPackage; 142 mDisplayAdjustments.setCompatibilityInfo(compatInfo); 143 } 144 145 private static ApplicationInfo adjustNativeLibraryPaths(ApplicationInfo info) { 146 // If we're dealing with a multi-arch application that has both 147 // 32 and 64 bit shared libraries, we might need to choose the secondary 148 // depending on what the current runtime's instruction set is. 149 if (info.primaryCpuAbi != null && info.secondaryCpuAbi != null) { 150 final String runtimeIsa = VMRuntime.getRuntime().vmInstructionSet(); 151 152 // Get the instruction set that the libraries of secondary Abi is supported. 153 // In presence of a native bridge this might be different than the one secondary Abi used. 154 String secondaryIsa = VMRuntime.getInstructionSet(info.secondaryCpuAbi); 155 final String secondaryDexCodeIsa = SystemProperties.get("ro.dalvik.vm.isa." + secondaryIsa); 156 secondaryIsa = secondaryDexCodeIsa.isEmpty() ? secondaryIsa : secondaryDexCodeIsa; 157 158 // If the runtimeIsa is the same as the primary isa, then we do nothing. 159 // Everything will be set up correctly because info.nativeLibraryDir will 160 // correspond to the right ISA. 161 if (runtimeIsa.equals(secondaryIsa)) { 162 final ApplicationInfo modified = new ApplicationInfo(info); 163 modified.nativeLibraryDir = modified.secondaryNativeLibraryDir; 164 modified.primaryCpuAbi = modified.secondaryCpuAbi; 165 return modified; 166 } 167 } 168 169 return info; 170 } 171 172 /** 173 * Create information about the system package. 174 * Must call {@link #installSystemApplicationInfo} later. 175 */ 176 LoadedApk(ActivityThread activityThread) { 177 mActivityThread = activityThread; 178 mApplicationInfo = new ApplicationInfo(); 179 mApplicationInfo.packageName = "android"; 180 mPackageName = "android"; 181 mAppDir = null; 182 mResDir = null; 183 mSplitAppDirs = null; 184 mSplitResDirs = null; 185 mOverlayDirs = null; 186 mSharedLibraries = null; 187 mDataDir = null; 188 mDataDirFile = null; 189 mDeviceEncryptedDataDirFile = null; 190 mCredentialEncryptedDataDirFile = null; 191 mLibDir = null; 192 mBaseClassLoader = null; 193 mSecurityViolation = false; 194 mIncludeCode = true; 195 mRegisterPackage = false; 196 mClassLoader = ClassLoader.getSystemClassLoader(); 197 mResources = Resources.getSystem(); 198 } 199 200 /** 201 * Sets application info about the system package. 202 */ 203 void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) { 204 assert info.packageName.equals("android"); 205 mApplicationInfo = info; 206 mClassLoader = classLoader; 207 } 208 209 public String getPackageName() { 210 return mPackageName; 211 } 212 213 public ApplicationInfo getApplicationInfo() { 214 return mApplicationInfo; 215 } 216 217 public int getTargetSdkVersion() { 218 return mApplicationInfo.targetSdkVersion; 219 } 220 221 public boolean isSecurityViolation() { 222 return mSecurityViolation; 223 } 224 225 public CompatibilityInfo getCompatibilityInfo() { 226 return mDisplayAdjustments.getCompatibilityInfo(); 227 } 228 229 public void setCompatibilityInfo(CompatibilityInfo compatInfo) { 230 mDisplayAdjustments.setCompatibilityInfo(compatInfo); 231 } 232 233 /** 234 * Gets the array of shared libraries that are listed as 235 * used by the given package. 236 * 237 * @param packageName the name of the package (note: not its 238 * file name) 239 * @return null-ok; the array of shared libraries, each one 240 * a fully-qualified path 241 */ 242 private static String[] getLibrariesFor(String packageName) { 243 ApplicationInfo ai = null; 244 try { 245 ai = ActivityThread.getPackageManager().getApplicationInfo(packageName, 246 PackageManager.GET_SHARED_LIBRARY_FILES, UserHandle.myUserId()); 247 } catch (RemoteException e) { 248 throw e.rethrowFromSystemServer(); 249 } 250 251 if (ai == null) { 252 return null; 253 } 254 255 return ai.sharedLibraryFiles; 256 } 257 258 public void updateApplicationInfo(ApplicationInfo aInfo, List<String> oldPaths) { 259 setApplicationInfo(aInfo); 260 261 final List<String> newPaths = new ArrayList<>(); 262 makePaths(mActivityThread, aInfo, newPaths, null /*libPaths*/); 263 final List<String> addedPaths = new ArrayList<>(newPaths.size()); 264 265 if (oldPaths != null) { 266 for (String path : newPaths) { 267 final String apkName = path.substring(path.lastIndexOf(File.separator)); 268 boolean match = false; 269 for (String oldPath : oldPaths) { 270 final String oldApkName = oldPath.substring(path.lastIndexOf(File.separator)); 271 if (apkName.equals(oldApkName)) { 272 match = true; 273 break; 274 } 275 } 276 if (!match) { 277 addedPaths.add(path); 278 } 279 } 280 } else { 281 addedPaths.addAll(newPaths); 282 } 283 synchronized (this) { 284 mClassLoader = createOrUpdateClassLoaderLocked(addedPaths); 285 if (mResources != null) { 286 mResources = mActivityThread.getNewTopLevelResources(mResDir, mSplitResDirs, 287 mOverlayDirs, mApplicationInfo.sharedLibraryFiles, Display.DEFAULT_DISPLAY, 288 null /*overrideConfiguration*/, this); 289 } 290 } 291 } 292 293 private void setApplicationInfo(ApplicationInfo aInfo) { 294 final int myUid = Process.myUid(); 295 aInfo = adjustNativeLibraryPaths(aInfo); 296 mApplicationInfo = aInfo; 297 mAppDir = aInfo.sourceDir; 298 mResDir = aInfo.uid == myUid ? aInfo.sourceDir : aInfo.publicSourceDir; 299 mSplitAppDirs = aInfo.splitSourceDirs; 300 mSplitResDirs = aInfo.uid == myUid ? aInfo.splitSourceDirs : aInfo.splitPublicSourceDirs; 301 mOverlayDirs = aInfo.resourceDirs; 302 mSharedLibraries = aInfo.sharedLibraryFiles; 303 mDataDir = aInfo.dataDir; 304 mLibDir = aInfo.nativeLibraryDir; 305 mDataDirFile = FileUtils.newFileOrNull(aInfo.dataDir); 306 mDeviceEncryptedDataDirFile = FileUtils.newFileOrNull(aInfo.deviceEncryptedDataDir); 307 mCredentialEncryptedDataDirFile = FileUtils.newFileOrNull(aInfo.credentialEncryptedDataDir); 308 } 309 310 public static void makePaths(ActivityThread activityThread, ApplicationInfo aInfo, 311 List<String> outZipPaths, List<String> outLibPaths) { 312 final String appDir = aInfo.sourceDir; 313 final String[] splitAppDirs = aInfo.splitSourceDirs; 314 final String libDir = aInfo.nativeLibraryDir; 315 final String[] sharedLibraries = aInfo.sharedLibraryFiles; 316 317 outZipPaths.clear(); 318 outZipPaths.add(appDir); 319 if (splitAppDirs != null) { 320 Collections.addAll(outZipPaths, splitAppDirs); 321 } 322 323 if (outLibPaths != null) { 324 outLibPaths.clear(); 325 } 326 327 /* 328 * The following is a bit of a hack to inject 329 * instrumentation into the system: If the app 330 * being started matches one of the instrumentation names, 331 * then we combine both the "instrumentation" and 332 * "instrumented" app into the path, along with the 333 * concatenation of both apps' shared library lists. 334 */ 335 336 String instrumentationPackageName = activityThread.mInstrumentationPackageName; 337 String instrumentationAppDir = activityThread.mInstrumentationAppDir; 338 String[] instrumentationSplitAppDirs = activityThread.mInstrumentationSplitAppDirs; 339 String instrumentationLibDir = activityThread.mInstrumentationLibDir; 340 341 String instrumentedAppDir = activityThread.mInstrumentedAppDir; 342 String[] instrumentedSplitAppDirs = activityThread.mInstrumentedSplitAppDirs; 343 String instrumentedLibDir = activityThread.mInstrumentedLibDir; 344 String[] instrumentationLibs = null; 345 346 if (appDir.equals(instrumentationAppDir) 347 || appDir.equals(instrumentedAppDir)) { 348 outZipPaths.clear(); 349 outZipPaths.add(instrumentationAppDir); 350 if (instrumentationSplitAppDirs != null) { 351 Collections.addAll(outZipPaths, instrumentationSplitAppDirs); 352 } 353 outZipPaths.add(instrumentedAppDir); 354 if (instrumentedSplitAppDirs != null) { 355 Collections.addAll(outZipPaths, instrumentedSplitAppDirs); 356 } 357 358 if (outLibPaths != null) { 359 outLibPaths.add(instrumentationLibDir); 360 outLibPaths.add(instrumentedLibDir); 361 } 362 363 if (!instrumentedAppDir.equals(instrumentationAppDir)) { 364 instrumentationLibs = getLibrariesFor(instrumentationPackageName); 365 } 366 } 367 368 if (outLibPaths != null) { 369 if (outLibPaths.isEmpty()) { 370 outLibPaths.add(libDir); 371 } 372 373 // Add path to libraries in apk for current abi. Do this now because more entries 374 // will be added to zipPaths that shouldn't be part of the library path. 375 if (aInfo.primaryCpuAbi != null) { 376 for (String apk : outZipPaths) { 377 outLibPaths.add(apk + "!/lib/" + aInfo.primaryCpuAbi); 378 } 379 } 380 381 if (aInfo.isSystemApp() && !aInfo.isUpdatedSystemApp()) { 382 // Add path to system libraries to libPaths; 383 // Access to system libs should be limited 384 // to bundled applications; this is why updated 385 // system apps are not included. 386 outLibPaths.add(System.getProperty("java.library.path")); 387 } 388 } 389 390 if (sharedLibraries != null) { 391 for (String lib : sharedLibraries) { 392 if (!outZipPaths.contains(lib)) { 393 outZipPaths.add(0, lib); 394 } 395 } 396 } 397 398 if (instrumentationLibs != null) { 399 for (String lib : instrumentationLibs) { 400 if (!outZipPaths.contains(lib)) { 401 outZipPaths.add(0, lib); 402 } 403 } 404 } 405 406 final String zip = TextUtils.join(File.pathSeparator, outZipPaths); 407 } 408 409 private ClassLoader createOrUpdateClassLoaderLocked(List<String> addedPaths) { 410 final ClassLoader classLoader; 411 if (mIncludeCode && !mPackageName.equals("android")) { 412 // Avoid the binder call when the package is the current application package. 413 // The activity manager will perform ensure that dexopt is performed before 414 // spinning up the process. 415 if (!Objects.equals(mPackageName, ActivityThread.currentPackageName())) { 416 VMRuntime.getRuntime().vmInstructionSet(); 417 try { 418 ActivityThread.getPackageManager().notifyPackageUse(mPackageName); 419 } catch (RemoteException re) { 420 throw re.rethrowFromSystemServer(); 421 } 422 } 423 424 final List<String> zipPaths = new ArrayList<>(); 425 final List<String> libPaths = new ArrayList<>(); 426 427 if (mRegisterPackage) { 428 try { 429 ActivityManagerNative.getDefault().addPackageDependency(mPackageName); 430 } catch (RemoteException e) { 431 throw e.rethrowFromSystemServer(); 432 } 433 } 434 435 makePaths(mActivityThread, mApplicationInfo, zipPaths, libPaths); 436 final String zip = TextUtils.join(File.pathSeparator, zipPaths); 437 final boolean isBundledApp = mApplicationInfo.isSystemApp() 438 && !mApplicationInfo.isUpdatedSystemApp(); 439 String libraryPermittedPath = mDataDir; 440 if (isBundledApp) { 441 // This is necessary to grant bundled apps access to 442 // libraries located in subdirectories of /system/lib 443 libraryPermittedPath += File.pathSeparator + 444 System.getProperty("java.library.path"); 445 } 446 // DO NOT SHIP: this is a workaround for apps loading native libraries 447 // provided by 3rd party apps using absolute path instead of corresponding 448 // classloader; see http://b/26954419 for example. 449 if (mApplicationInfo.targetSdkVersion <= 23) { 450 libraryPermittedPath += File.pathSeparator + "/data/app"; 451 } 452 // ----------------------------------------------------------------------------- 453 454 final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths); 455 456 /* 457 * With all the combination done (if necessary, actually 458 * create the class loader. 459 */ 460 461 if (ActivityThread.localLOGV) 462 Slog.v(ActivityThread.TAG, "Class path: " + zip + 463 ", JNI path: " + librarySearchPath); 464 465 if (mClassLoader == null) { 466 // Temporarily disable logging of disk reads on the Looper thread 467 // as this is early and necessary. 468 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); 469 470 classLoader = ApplicationLoaders.getDefault().getClassLoader(zip, 471 mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath, 472 libraryPermittedPath, mBaseClassLoader); 473 474 StrictMode.setThreadPolicy(oldPolicy); 475 } else if (addedPaths != null && addedPaths.size() > 0) { 476 final String add = TextUtils.join(File.pathSeparator, addedPaths); 477 ApplicationLoaders.getDefault().addPath(mClassLoader, add); 478 classLoader = mClassLoader; 479 } else { 480 classLoader = mClassLoader; 481 } 482 } else { 483 if (mClassLoader == null) { 484 if (mBaseClassLoader == null) { 485 classLoader = ClassLoader.getSystemClassLoader(); 486 } else { 487 classLoader = mBaseClassLoader; 488 } 489 } else { 490 classLoader = mClassLoader; 491 } 492 } 493 return classLoader; 494 } 495 496 public ClassLoader getClassLoader() { 497 synchronized (this) { 498 if (mClassLoader == null) { 499 mClassLoader = createOrUpdateClassLoaderLocked(null /*addedPaths*/); 500 } 501 return mClassLoader; 502 } 503 } 504 505 /** 506 * Setup value for Thread.getContextClassLoader(). If the 507 * package will not run in in a VM with other packages, we set 508 * the Java context ClassLoader to the 509 * PackageInfo.getClassLoader value. However, if this VM can 510 * contain multiple packages, we intead set the Java context 511 * ClassLoader to a proxy that will warn about the use of Java 512 * context ClassLoaders and then fall through to use the 513 * system ClassLoader. 514 * 515 * <p> Note that this is similar to but not the same as the 516 * android.content.Context.getClassLoader(). While both 517 * context class loaders are typically set to the 518 * PathClassLoader used to load the package archive in the 519 * single application per VM case, a single Android process 520 * may contain several Contexts executing on one thread with 521 * their own logical ClassLoaders while the Java context 522 * ClassLoader is a thread local. This is why in the case when 523 * we have multiple packages per VM we do not set the Java 524 * context ClassLoader to an arbitrary but instead warn the 525 * user to set their own if we detect that they are using a 526 * Java library that expects it to be set. 527 */ 528 private void initializeJavaContextClassLoader() { 529 IPackageManager pm = ActivityThread.getPackageManager(); 530 android.content.pm.PackageInfo pi; 531 try { 532 pi = pm.getPackageInfo(mPackageName, PackageManager.MATCH_DEBUG_TRIAGED_MISSING, 533 UserHandle.myUserId()); 534 } catch (RemoteException e) { 535 throw e.rethrowFromSystemServer(); 536 } 537 if (pi == null) { 538 throw new IllegalStateException("Unable to get package info for " 539 + mPackageName + "; is package not installed?"); 540 } 541 /* 542 * Two possible indications that this package could be 543 * sharing its virtual machine with other packages: 544 * 545 * 1.) the sharedUserId attribute is set in the manifest, 546 * indicating a request to share a VM with other 547 * packages with the same sharedUserId. 548 * 549 * 2.) the application element of the manifest has an 550 * attribute specifying a non-default process name, 551 * indicating the desire to run in another packages VM. 552 */ 553 boolean sharedUserIdSet = (pi.sharedUserId != null); 554 boolean processNameNotDefault = 555 (pi.applicationInfo != null && 556 !mPackageName.equals(pi.applicationInfo.processName)); 557 boolean sharable = (sharedUserIdSet || processNameNotDefault); 558 ClassLoader contextClassLoader = 559 (sharable) 560 ? new WarningContextClassLoader() 561 : mClassLoader; 562 Thread.currentThread().setContextClassLoader(contextClassLoader); 563 } 564 565 private static class WarningContextClassLoader extends ClassLoader { 566 567 private static boolean warned = false; 568 569 private void warn(String methodName) { 570 if (warned) { 571 return; 572 } 573 warned = true; 574 Thread.currentThread().setContextClassLoader(getParent()); 575 Slog.w(ActivityThread.TAG, "ClassLoader." + methodName + ": " + 576 "The class loader returned by " + 577 "Thread.getContextClassLoader() may fail for processes " + 578 "that host multiple applications. You should explicitly " + 579 "specify a context class loader. For example: " + 580 "Thread.setContextClassLoader(getClass().getClassLoader());"); 581 } 582 583 @Override public URL getResource(String resName) { 584 warn("getResource"); 585 return getParent().getResource(resName); 586 } 587 588 @Override public Enumeration<URL> getResources(String resName) throws IOException { 589 warn("getResources"); 590 return getParent().getResources(resName); 591 } 592 593 @Override public InputStream getResourceAsStream(String resName) { 594 warn("getResourceAsStream"); 595 return getParent().getResourceAsStream(resName); 596 } 597 598 @Override public Class<?> loadClass(String className) throws ClassNotFoundException { 599 warn("loadClass"); 600 return getParent().loadClass(className); 601 } 602 603 @Override public void setClassAssertionStatus(String cname, boolean enable) { 604 warn("setClassAssertionStatus"); 605 getParent().setClassAssertionStatus(cname, enable); 606 } 607 608 @Override public void setPackageAssertionStatus(String pname, boolean enable) { 609 warn("setPackageAssertionStatus"); 610 getParent().setPackageAssertionStatus(pname, enable); 611 } 612 613 @Override public void setDefaultAssertionStatus(boolean enable) { 614 warn("setDefaultAssertionStatus"); 615 getParent().setDefaultAssertionStatus(enable); 616 } 617 618 @Override public void clearAssertionStatus() { 619 warn("clearAssertionStatus"); 620 getParent().clearAssertionStatus(); 621 } 622 } 623 624 public String getAppDir() { 625 return mAppDir; 626 } 627 628 public String getLibDir() { 629 return mLibDir; 630 } 631 632 public String getResDir() { 633 return mResDir; 634 } 635 636 public String[] getSplitAppDirs() { 637 return mSplitAppDirs; 638 } 639 640 public String[] getSplitResDirs() { 641 return mSplitResDirs; 642 } 643 644 public String[] getOverlayDirs() { 645 return mOverlayDirs; 646 } 647 648 public String getDataDir() { 649 return mDataDir; 650 } 651 652 public File getDataDirFile() { 653 return mDataDirFile; 654 } 655 656 public File getDeviceEncryptedDataDirFile() { 657 return mDeviceEncryptedDataDirFile; 658 } 659 660 public File getCredentialEncryptedDataDirFile() { 661 return mCredentialEncryptedDataDirFile; 662 } 663 664 public AssetManager getAssets(ActivityThread mainThread) { 665 return getResources(mainThread).getAssets(); 666 } 667 668 public Resources getResources(ActivityThread mainThread) { 669 if (mResources == null) { 670 mResources = mainThread.getTopLevelResources(mResDir, mSplitResDirs, mOverlayDirs, 671 mApplicationInfo.sharedLibraryFiles, Display.DEFAULT_DISPLAY, null, this); 672 } 673 return mResources; 674 } 675 676 public Application makeApplication(boolean forceDefaultAppClass, 677 Instrumentation instrumentation) { 678 if (mApplication != null) { 679 return mApplication; 680 } 681 682 Application app = null; 683 684 String appClass = mApplicationInfo.className; 685 if (forceDefaultAppClass || (appClass == null)) { 686 appClass = "android.app.Application"; 687 } 688 689 try { 690 java.lang.ClassLoader cl = getClassLoader(); 691 if (!mPackageName.equals("android")) { 692 initializeJavaContextClassLoader(); 693 } 694 ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this); 695 app = mActivityThread.mInstrumentation.newApplication( 696 cl, appClass, appContext); 697 appContext.setOuterContext(app); 698 } catch (Exception e) { 699 if (!mActivityThread.mInstrumentation.onException(app, e)) { 700 throw new RuntimeException( 701 "Unable to instantiate application " + appClass 702 + ": " + e.toString(), e); 703 } 704 } 705 mActivityThread.mAllApplications.add(app); 706 mApplication = app; 707 708 if (instrumentation != null) { 709 try { 710 instrumentation.callApplicationOnCreate(app); 711 } catch (Exception e) { 712 if (!instrumentation.onException(app, e)) { 713 throw new RuntimeException( 714 "Unable to create application " + app.getClass().getName() 715 + ": " + e.toString(), e); 716 } 717 } 718 } 719 720 // Rewrite the R 'constants' for all library apks. 721 SparseArray<String> packageIdentifiers = getAssets(mActivityThread) 722 .getAssignedPackageIdentifiers(); 723 final int N = packageIdentifiers.size(); 724 for (int i = 0; i < N; i++) { 725 final int id = packageIdentifiers.keyAt(i); 726 if (id == 0x01 || id == 0x7f) { 727 continue; 728 } 729 730 rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id); 731 } 732 733 return app; 734 } 735 736 private void rewriteRValues(ClassLoader cl, String packageName, int id) { 737 final Class<?> rClazz; 738 try { 739 rClazz = cl.loadClass(packageName + ".R"); 740 } catch (ClassNotFoundException e) { 741 // This is not necessarily an error, as some packages do not ship with resources 742 // (or they do not need rewriting). 743 Log.i(TAG, "No resource references to update in package " + packageName); 744 return; 745 } 746 747 final Method callback; 748 try { 749 callback = rClazz.getMethod("onResourcesLoaded", int.class); 750 } catch (NoSuchMethodException e) { 751 // No rewriting to be done. 752 return; 753 } 754 755 Throwable cause; 756 try { 757 callback.invoke(null, id); 758 return; 759 } catch (IllegalAccessException e) { 760 cause = e; 761 } catch (InvocationTargetException e) { 762 cause = e.getCause(); 763 } 764 765 throw new RuntimeException("Failed to rewrite resource references for " + packageName, 766 cause); 767 } 768 769 public void removeContextRegistrations(Context context, 770 String who, String what) { 771 final boolean reportRegistrationLeaks = StrictMode.vmRegistrationLeaksEnabled(); 772 synchronized (mReceivers) { 773 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> rmap = 774 mReceivers.remove(context); 775 if (rmap != null) { 776 for (int i = 0; i < rmap.size(); i++) { 777 LoadedApk.ReceiverDispatcher rd = rmap.valueAt(i); 778 IntentReceiverLeaked leak = new IntentReceiverLeaked( 779 what + " " + who + " has leaked IntentReceiver " 780 + rd.getIntentReceiver() + " that was " + 781 "originally registered here. Are you missing a " + 782 "call to unregisterReceiver()?"); 783 leak.setStackTrace(rd.getLocation().getStackTrace()); 784 Slog.e(ActivityThread.TAG, leak.getMessage(), leak); 785 if (reportRegistrationLeaks) { 786 StrictMode.onIntentReceiverLeaked(leak); 787 } 788 try { 789 ActivityManagerNative.getDefault().unregisterReceiver( 790 rd.getIIntentReceiver()); 791 } catch (RemoteException e) { 792 throw e.rethrowFromSystemServer(); 793 } 794 } 795 } 796 mUnregisteredReceivers.remove(context); 797 } 798 799 synchronized (mServices) { 800 //Slog.i(TAG, "Receiver registrations: " + mReceivers); 801 ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> smap = 802 mServices.remove(context); 803 if (smap != null) { 804 for (int i = 0; i < smap.size(); i++) { 805 LoadedApk.ServiceDispatcher sd = smap.valueAt(i); 806 ServiceConnectionLeaked leak = new ServiceConnectionLeaked( 807 what + " " + who + " has leaked ServiceConnection " 808 + sd.getServiceConnection() + " that was originally bound here"); 809 leak.setStackTrace(sd.getLocation().getStackTrace()); 810 Slog.e(ActivityThread.TAG, leak.getMessage(), leak); 811 if (reportRegistrationLeaks) { 812 StrictMode.onServiceConnectionLeaked(leak); 813 } 814 try { 815 ActivityManagerNative.getDefault().unbindService( 816 sd.getIServiceConnection()); 817 } catch (RemoteException e) { 818 throw e.rethrowFromSystemServer(); 819 } 820 sd.doForget(); 821 } 822 } 823 mUnboundServices.remove(context); 824 //Slog.i(TAG, "Service registrations: " + mServices); 825 } 826 } 827 828 public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r, 829 Context context, Handler handler, 830 Instrumentation instrumentation, boolean registered) { 831 synchronized (mReceivers) { 832 LoadedApk.ReceiverDispatcher rd = null; 833 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null; 834 if (registered) { 835 map = mReceivers.get(context); 836 if (map != null) { 837 rd = map.get(r); 838 } 839 } 840 if (rd == null) { 841 rd = new ReceiverDispatcher(r, context, handler, 842 instrumentation, registered); 843 if (registered) { 844 if (map == null) { 845 map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>(); 846 mReceivers.put(context, map); 847 } 848 map.put(r, rd); 849 } 850 } else { 851 rd.validate(context, handler); 852 } 853 rd.mForgotten = false; 854 return rd.getIIntentReceiver(); 855 } 856 } 857 858 public IIntentReceiver forgetReceiverDispatcher(Context context, 859 BroadcastReceiver r) { 860 synchronized (mReceivers) { 861 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = mReceivers.get(context); 862 LoadedApk.ReceiverDispatcher rd = null; 863 if (map != null) { 864 rd = map.get(r); 865 if (rd != null) { 866 map.remove(r); 867 if (map.size() == 0) { 868 mReceivers.remove(context); 869 } 870 if (r.getDebugUnregister()) { 871 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder 872 = mUnregisteredReceivers.get(context); 873 if (holder == null) { 874 holder = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>(); 875 mUnregisteredReceivers.put(context, holder); 876 } 877 RuntimeException ex = new IllegalArgumentException( 878 "Originally unregistered here:"); 879 ex.fillInStackTrace(); 880 rd.setUnregisterLocation(ex); 881 holder.put(r, rd); 882 } 883 rd.mForgotten = true; 884 return rd.getIIntentReceiver(); 885 } 886 } 887 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder 888 = mUnregisteredReceivers.get(context); 889 if (holder != null) { 890 rd = holder.get(r); 891 if (rd != null) { 892 RuntimeException ex = rd.getUnregisterLocation(); 893 throw new IllegalArgumentException( 894 "Unregistering Receiver " + r 895 + " that was already unregistered", ex); 896 } 897 } 898 if (context == null) { 899 throw new IllegalStateException("Unbinding Receiver " + r 900 + " from Context that is no longer in use: " + context); 901 } else { 902 throw new IllegalArgumentException("Receiver not registered: " + r); 903 } 904 905 } 906 } 907 908 static final class ReceiverDispatcher { 909 910 final static class InnerReceiver extends IIntentReceiver.Stub { 911 final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher; 912 final LoadedApk.ReceiverDispatcher mStrongRef; 913 914 InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) { 915 mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd); 916 mStrongRef = strong ? rd : null; 917 } 918 public void performReceive(Intent intent, int resultCode, String data, 919 Bundle extras, boolean ordered, boolean sticky, int sendingUser) { 920 LoadedApk.ReceiverDispatcher rd = mDispatcher.get(); 921 if (ActivityThread.DEBUG_BROADCAST) { 922 int seq = intent.getIntExtra("seq", -1); 923 Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction() + " seq=" + seq 924 + " to " + (rd != null ? rd.mReceiver : null)); 925 } 926 if (rd != null) { 927 rd.performReceive(intent, resultCode, data, extras, 928 ordered, sticky, sendingUser); 929 } else { 930 // The activity manager dispatched a broadcast to a registered 931 // receiver in this process, but before it could be delivered the 932 // receiver was unregistered. Acknowledge the broadcast on its 933 // behalf so that the system's broadcast sequence can continue. 934 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, 935 "Finishing broadcast to unregistered receiver"); 936 IActivityManager mgr = ActivityManagerNative.getDefault(); 937 try { 938 if (extras != null) { 939 extras.setAllowFds(false); 940 } 941 mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags()); 942 } catch (RemoteException e) { 943 throw e.rethrowFromSystemServer(); 944 } 945 } 946 } 947 } 948 949 final IIntentReceiver.Stub mIIntentReceiver; 950 final BroadcastReceiver mReceiver; 951 final Context mContext; 952 final Handler mActivityThread; 953 final Instrumentation mInstrumentation; 954 final boolean mRegistered; 955 final IntentReceiverLeaked mLocation; 956 RuntimeException mUnregisterLocation; 957 boolean mForgotten; 958 959 final class Args extends BroadcastReceiver.PendingResult implements Runnable { 960 private Intent mCurIntent; 961 private final boolean mOrdered; 962 963 public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras, 964 boolean ordered, boolean sticky, int sendingUser) { 965 super(resultCode, resultData, resultExtras, 966 mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered, 967 sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags()); 968 mCurIntent = intent; 969 mOrdered = ordered; 970 } 971 972 public void run() { 973 final BroadcastReceiver receiver = mReceiver; 974 final boolean ordered = mOrdered; 975 976 if (ActivityThread.DEBUG_BROADCAST) { 977 int seq = mCurIntent.getIntExtra("seq", -1); 978 Slog.i(ActivityThread.TAG, "Dispatching broadcast " + mCurIntent.getAction() 979 + " seq=" + seq + " to " + mReceiver); 980 Slog.i(ActivityThread.TAG, " mRegistered=" + mRegistered 981 + " mOrderedHint=" + ordered); 982 } 983 984 final IActivityManager mgr = ActivityManagerNative.getDefault(); 985 final Intent intent = mCurIntent; 986 mCurIntent = null; 987 988 if (receiver == null || mForgotten) { 989 if (mRegistered && ordered) { 990 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, 991 "Finishing null broadcast to " + mReceiver); 992 sendFinished(mgr); 993 } 994 return; 995 } 996 997 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg"); 998 try { 999 ClassLoader cl = mReceiver.getClass().getClassLoader(); 1000 intent.setExtrasClassLoader(cl); 1001 setExtrasClassLoader(cl); 1002 receiver.setPendingResult(this); 1003 receiver.onReceive(mContext, intent); 1004 } catch (Exception e) { 1005 if (mRegistered && ordered) { 1006 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, 1007 "Finishing failed broadcast to " + mReceiver); 1008 sendFinished(mgr); 1009 } 1010 if (mInstrumentation == null || 1011 !mInstrumentation.onException(mReceiver, e)) { 1012 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 1013 throw new RuntimeException( 1014 "Error receiving broadcast " + intent 1015 + " in " + mReceiver, e); 1016 } 1017 } 1018 1019 if (receiver.getPendingResult() != null) { 1020 finish(); 1021 } 1022 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 1023 } 1024 } 1025 1026 ReceiverDispatcher(BroadcastReceiver receiver, Context context, 1027 Handler activityThread, Instrumentation instrumentation, 1028 boolean registered) { 1029 if (activityThread == null) { 1030 throw new NullPointerException("Handler must not be null"); 1031 } 1032 1033 mIIntentReceiver = new InnerReceiver(this, !registered); 1034 mReceiver = receiver; 1035 mContext = context; 1036 mActivityThread = activityThread; 1037 mInstrumentation = instrumentation; 1038 mRegistered = registered; 1039 mLocation = new IntentReceiverLeaked(null); 1040 mLocation.fillInStackTrace(); 1041 } 1042 1043 void validate(Context context, Handler activityThread) { 1044 if (mContext != context) { 1045 throw new IllegalStateException( 1046 "Receiver " + mReceiver + 1047 " registered with differing Context (was " + 1048 mContext + " now " + context + ")"); 1049 } 1050 if (mActivityThread != activityThread) { 1051 throw new IllegalStateException( 1052 "Receiver " + mReceiver + 1053 " registered with differing handler (was " + 1054 mActivityThread + " now " + activityThread + ")"); 1055 } 1056 } 1057 1058 IntentReceiverLeaked getLocation() { 1059 return mLocation; 1060 } 1061 1062 BroadcastReceiver getIntentReceiver() { 1063 return mReceiver; 1064 } 1065 1066 IIntentReceiver getIIntentReceiver() { 1067 return mIIntentReceiver; 1068 } 1069 1070 void setUnregisterLocation(RuntimeException ex) { 1071 mUnregisterLocation = ex; 1072 } 1073 1074 RuntimeException getUnregisterLocation() { 1075 return mUnregisterLocation; 1076 } 1077 1078 public void performReceive(Intent intent, int resultCode, String data, 1079 Bundle extras, boolean ordered, boolean sticky, int sendingUser) { 1080 if (ActivityThread.DEBUG_BROADCAST) { 1081 int seq = intent.getIntExtra("seq", -1); 1082 Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq 1083 + " to " + mReceiver); 1084 } 1085 Args args = new Args(intent, resultCode, data, extras, ordered, 1086 sticky, sendingUser); 1087 if (!mActivityThread.post(args)) { 1088 if (mRegistered && ordered) { 1089 IActivityManager mgr = ActivityManagerNative.getDefault(); 1090 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, 1091 "Finishing sync broadcast to " + mReceiver); 1092 args.sendFinished(mgr); 1093 } 1094 } 1095 } 1096 1097 } 1098 1099 public final IServiceConnection getServiceDispatcher(ServiceConnection c, 1100 Context context, Handler handler, int flags) { 1101 synchronized (mServices) { 1102 LoadedApk.ServiceDispatcher sd = null; 1103 ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context); 1104 if (map != null) { 1105 sd = map.get(c); 1106 } 1107 if (sd == null) { 1108 sd = new ServiceDispatcher(c, context, handler, flags); 1109 if (map == null) { 1110 map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>(); 1111 mServices.put(context, map); 1112 } 1113 map.put(c, sd); 1114 } else { 1115 sd.validate(context, handler); 1116 } 1117 return sd.getIServiceConnection(); 1118 } 1119 } 1120 1121 public final IServiceConnection forgetServiceDispatcher(Context context, 1122 ServiceConnection c) { 1123 synchronized (mServices) { 1124 ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map 1125 = mServices.get(context); 1126 LoadedApk.ServiceDispatcher sd = null; 1127 if (map != null) { 1128 sd = map.get(c); 1129 if (sd != null) { 1130 map.remove(c); 1131 sd.doForget(); 1132 if (map.size() == 0) { 1133 mServices.remove(context); 1134 } 1135 if ((sd.getFlags()&Context.BIND_DEBUG_UNBIND) != 0) { 1136 ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder 1137 = mUnboundServices.get(context); 1138 if (holder == null) { 1139 holder = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>(); 1140 mUnboundServices.put(context, holder); 1141 } 1142 RuntimeException ex = new IllegalArgumentException( 1143 "Originally unbound here:"); 1144 ex.fillInStackTrace(); 1145 sd.setUnbindLocation(ex); 1146 holder.put(c, sd); 1147 } 1148 return sd.getIServiceConnection(); 1149 } 1150 } 1151 ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder 1152 = mUnboundServices.get(context); 1153 if (holder != null) { 1154 sd = holder.get(c); 1155 if (sd != null) { 1156 RuntimeException ex = sd.getUnbindLocation(); 1157 throw new IllegalArgumentException( 1158 "Unbinding Service " + c 1159 + " that was already unbound", ex); 1160 } 1161 } 1162 if (context == null) { 1163 throw new IllegalStateException("Unbinding Service " + c 1164 + " from Context that is no longer in use: " + context); 1165 } else { 1166 throw new IllegalArgumentException("Service not registered: " + c); 1167 } 1168 } 1169 } 1170 1171 static final class ServiceDispatcher { 1172 private final ServiceDispatcher.InnerConnection mIServiceConnection; 1173 private final ServiceConnection mConnection; 1174 private final Context mContext; 1175 private final Handler mActivityThread; 1176 private final ServiceConnectionLeaked mLocation; 1177 private final int mFlags; 1178 1179 private RuntimeException mUnbindLocation; 1180 1181 private boolean mForgotten; 1182 1183 private static class ConnectionInfo { 1184 IBinder binder; 1185 IBinder.DeathRecipient deathMonitor; 1186 } 1187 1188 private static class InnerConnection extends IServiceConnection.Stub { 1189 final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher; 1190 1191 InnerConnection(LoadedApk.ServiceDispatcher sd) { 1192 mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd); 1193 } 1194 1195 public void connected(ComponentName name, IBinder service) throws RemoteException { 1196 LoadedApk.ServiceDispatcher sd = mDispatcher.get(); 1197 if (sd != null) { 1198 sd.connected(name, service); 1199 } 1200 } 1201 } 1202 1203 private final ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections 1204 = new ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo>(); 1205 1206 ServiceDispatcher(ServiceConnection conn, 1207 Context context, Handler activityThread, int flags) { 1208 mIServiceConnection = new InnerConnection(this); 1209 mConnection = conn; 1210 mContext = context; 1211 mActivityThread = activityThread; 1212 mLocation = new ServiceConnectionLeaked(null); 1213 mLocation.fillInStackTrace(); 1214 mFlags = flags; 1215 } 1216 1217 void validate(Context context, Handler activityThread) { 1218 if (mContext != context) { 1219 throw new RuntimeException( 1220 "ServiceConnection " + mConnection + 1221 " registered with differing Context (was " + 1222 mContext + " now " + context + ")"); 1223 } 1224 if (mActivityThread != activityThread) { 1225 throw new RuntimeException( 1226 "ServiceConnection " + mConnection + 1227 " registered with differing handler (was " + 1228 mActivityThread + " now " + activityThread + ")"); 1229 } 1230 } 1231 1232 void doForget() { 1233 synchronized(this) { 1234 for (int i=0; i<mActiveConnections.size(); i++) { 1235 ServiceDispatcher.ConnectionInfo ci = mActiveConnections.valueAt(i); 1236 ci.binder.unlinkToDeath(ci.deathMonitor, 0); 1237 } 1238 mActiveConnections.clear(); 1239 mForgotten = true; 1240 } 1241 } 1242 1243 ServiceConnectionLeaked getLocation() { 1244 return mLocation; 1245 } 1246 1247 ServiceConnection getServiceConnection() { 1248 return mConnection; 1249 } 1250 1251 IServiceConnection getIServiceConnection() { 1252 return mIServiceConnection; 1253 } 1254 1255 int getFlags() { 1256 return mFlags; 1257 } 1258 1259 void setUnbindLocation(RuntimeException ex) { 1260 mUnbindLocation = ex; 1261 } 1262 1263 RuntimeException getUnbindLocation() { 1264 return mUnbindLocation; 1265 } 1266 1267 public void connected(ComponentName name, IBinder service) { 1268 if (mActivityThread != null) { 1269 mActivityThread.post(new RunConnection(name, service, 0)); 1270 } else { 1271 doConnected(name, service); 1272 } 1273 } 1274 1275 public void death(ComponentName name, IBinder service) { 1276 ServiceDispatcher.ConnectionInfo old; 1277 1278 synchronized (this) { 1279 old = mActiveConnections.remove(name); 1280 if (old == null || old.binder != service) { 1281 // Death for someone different than who we last 1282 // reported... just ignore it. 1283 return; 1284 } 1285 old.binder.unlinkToDeath(old.deathMonitor, 0); 1286 } 1287 1288 if (mActivityThread != null) { 1289 mActivityThread.post(new RunConnection(name, service, 1)); 1290 } else { 1291 doDeath(name, service); 1292 } 1293 } 1294 1295 public void doConnected(ComponentName name, IBinder service) { 1296 ServiceDispatcher.ConnectionInfo old; 1297 ServiceDispatcher.ConnectionInfo info; 1298 1299 synchronized (this) { 1300 if (mForgotten) { 1301 // We unbound before receiving the connection; ignore 1302 // any connection received. 1303 return; 1304 } 1305 old = mActiveConnections.get(name); 1306 if (old != null && old.binder == service) { 1307 // Huh, already have this one. Oh well! 1308 return; 1309 } 1310 1311 if (service != null) { 1312 // A new service is being connected... set it all up. 1313 info = new ConnectionInfo(); 1314 info.binder = service; 1315 info.deathMonitor = new DeathMonitor(name, service); 1316 try { 1317 service.linkToDeath(info.deathMonitor, 0); 1318 mActiveConnections.put(name, info); 1319 } catch (RemoteException e) { 1320 // This service was dead before we got it... just 1321 // don't do anything with it. 1322 mActiveConnections.remove(name); 1323 return; 1324 } 1325 1326 } else { 1327 // The named service is being disconnected... clean up. 1328 mActiveConnections.remove(name); 1329 } 1330 1331 if (old != null) { 1332 old.binder.unlinkToDeath(old.deathMonitor, 0); 1333 } 1334 } 1335 1336 // If there was an old service, it is not disconnected. 1337 if (old != null) { 1338 mConnection.onServiceDisconnected(name); 1339 } 1340 // If there is a new service, it is now connected. 1341 if (service != null) { 1342 mConnection.onServiceConnected(name, service); 1343 } 1344 } 1345 1346 public void doDeath(ComponentName name, IBinder service) { 1347 mConnection.onServiceDisconnected(name); 1348 } 1349 1350 private final class RunConnection implements Runnable { 1351 RunConnection(ComponentName name, IBinder service, int command) { 1352 mName = name; 1353 mService = service; 1354 mCommand = command; 1355 } 1356 1357 public void run() { 1358 if (mCommand == 0) { 1359 doConnected(mName, mService); 1360 } else if (mCommand == 1) { 1361 doDeath(mName, mService); 1362 } 1363 } 1364 1365 final ComponentName mName; 1366 final IBinder mService; 1367 final int mCommand; 1368 } 1369 1370 private final class DeathMonitor implements IBinder.DeathRecipient 1371 { 1372 DeathMonitor(ComponentName name, IBinder service) { 1373 mName = name; 1374 mService = service; 1375 } 1376 1377 public void binderDied() { 1378 death(mName, mService); 1379 } 1380 1381 final ComponentName mName; 1382 final IBinder mService; 1383 } 1384 } 1385} 1386