LoadedApk.java revision 8a372a0a280127743ce9a7ce4b6198c7a02d2a4f
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.content.BroadcastReceiver; 20import android.content.ComponentName; 21import android.content.Context; 22import android.content.IIntentReceiver; 23import android.content.Intent; 24import android.content.ServiceConnection; 25import android.content.pm.ApplicationInfo; 26import android.content.pm.IPackageManager; 27import android.content.pm.PackageManager; 28import android.content.res.AssetManager; 29import android.content.res.CompatibilityInfo; 30import android.content.res.Resources; 31import android.os.Bundle; 32import android.os.FileUtils; 33import android.os.Handler; 34import android.os.IBinder; 35import android.os.Process; 36import android.os.RemoteException; 37import android.os.StrictMode; 38import android.os.SystemProperties; 39import android.os.Trace; 40import android.os.UserHandle; 41import android.text.TextUtils; 42import android.util.AndroidRuntimeException; 43import android.util.ArrayMap; 44import android.util.Log; 45import android.util.Slog; 46import android.util.SparseArray; 47import android.view.Display; 48import android.view.DisplayAdjustments; 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.ArrayList; 60import java.util.Collections; 61import java.util.Enumeration; 62import java.util.List; 63import java.util.Objects; 64 65final class IntentReceiverLeaked extends AndroidRuntimeException { 66 public IntentReceiverLeaked(String msg) { 67 super(msg); 68 } 69} 70 71final class ServiceConnectionLeaked extends AndroidRuntimeException { 72 public ServiceConnectionLeaked(String msg) { 73 super(msg); 74 } 75} 76 77/** 78 * Local state maintained about a currently loaded .apk. 79 * @hide 80 */ 81public final class LoadedApk { 82 83 private static final String TAG = "LoadedApk"; 84 85 private final ActivityThread mActivityThread; 86 final String mPackageName; 87 private ApplicationInfo mApplicationInfo; 88 private String mAppDir; 89 private String mResDir; 90 private String[] mSplitAppDirs; 91 private String[] mSplitResDirs; 92 private String[] mOverlayDirs; 93 private String[] mSharedLibraries; 94 private String mDataDir; 95 private String mLibDir; 96 private File mDataDirFile; 97 private File mDeviceProtectedDataDirFile; 98 private File mCredentialProtectedDataDirFile; 99 private final ClassLoader mBaseClassLoader; 100 private final boolean mSecurityViolation; 101 private final boolean mIncludeCode; 102 private final boolean mRegisterPackage; 103 private final DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments(); 104 /** WARNING: This may change. Don't hold external references to it. */ 105 Resources mResources; 106 private ClassLoader mClassLoader; 107 private Application mApplication; 108 109 private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers 110 = new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>(); 111 private final ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mUnregisteredReceivers 112 = new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>(); 113 private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices 114 = new ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>>(); 115 private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mUnboundServices 116 = new ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>>(); 117 118 int mClientCount = 0; 119 120 Application getApplication() { 121 return mApplication; 122 } 123 124 /** 125 * Create information about a new .apk 126 * 127 * NOTE: This constructor is called with ActivityThread's lock held, 128 * so MUST NOT call back out to the activity manager. 129 */ 130 public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo, 131 CompatibilityInfo compatInfo, ClassLoader baseLoader, 132 boolean securityViolation, boolean includeCode, boolean registerPackage) { 133 134 mActivityThread = activityThread; 135 setApplicationInfo(aInfo); 136 mPackageName = aInfo.packageName; 137 mBaseClassLoader = baseLoader; 138 mSecurityViolation = securityViolation; 139 mIncludeCode = includeCode; 140 mRegisterPackage = registerPackage; 141 mDisplayAdjustments.setCompatibilityInfo(compatInfo); 142 } 143 144 private static ApplicationInfo adjustNativeLibraryPaths(ApplicationInfo info) { 145 // If we're dealing with a multi-arch application that has both 146 // 32 and 64 bit shared libraries, we might need to choose the secondary 147 // depending on what the current runtime's instruction set is. 148 if (info.primaryCpuAbi != null && info.secondaryCpuAbi != null) { 149 final String runtimeIsa = VMRuntime.getRuntime().vmInstructionSet(); 150 151 // Get the instruction set that the libraries of secondary Abi is supported. 152 // In presence of a native bridge this might be different than the one secondary Abi used. 153 String secondaryIsa = VMRuntime.getInstructionSet(info.secondaryCpuAbi); 154 final String secondaryDexCodeIsa = SystemProperties.get("ro.dalvik.vm.isa." + secondaryIsa); 155 secondaryIsa = secondaryDexCodeIsa.isEmpty() ? secondaryIsa : secondaryDexCodeIsa; 156 157 // If the runtimeIsa is the same as the primary isa, then we do nothing. 158 // Everything will be set up correctly because info.nativeLibraryDir will 159 // correspond to the right ISA. 160 if (runtimeIsa.equals(secondaryIsa)) { 161 final ApplicationInfo modified = new ApplicationInfo(info); 162 modified.nativeLibraryDir = modified.secondaryNativeLibraryDir; 163 modified.primaryCpuAbi = modified.secondaryCpuAbi; 164 return modified; 165 } 166 } 167 168 return info; 169 } 170 171 /** 172 * Create information about the system package. 173 * Must call {@link #installSystemApplicationInfo} later. 174 */ 175 LoadedApk(ActivityThread activityThread) { 176 mActivityThread = activityThread; 177 mApplicationInfo = new ApplicationInfo(); 178 mApplicationInfo.packageName = "android"; 179 mPackageName = "android"; 180 mAppDir = null; 181 mResDir = null; 182 mSplitAppDirs = null; 183 mSplitResDirs = null; 184 mOverlayDirs = null; 185 mSharedLibraries = null; 186 mDataDir = null; 187 mDataDirFile = null; 188 mDeviceProtectedDataDirFile = null; 189 mCredentialProtectedDataDirFile = null; 190 mLibDir = null; 191 mBaseClassLoader = null; 192 mSecurityViolation = false; 193 mIncludeCode = true; 194 mRegisterPackage = false; 195 mClassLoader = ClassLoader.getSystemClassLoader(); 196 mResources = Resources.getSystem(); 197 } 198 199 /** 200 * Sets application info about the system package. 201 */ 202 void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) { 203 assert info.packageName.equals("android"); 204 mApplicationInfo = info; 205 mClassLoader = classLoader; 206 } 207 208 public String getPackageName() { 209 return mPackageName; 210 } 211 212 public ApplicationInfo getApplicationInfo() { 213 return mApplicationInfo; 214 } 215 216 public int getTargetSdkVersion() { 217 return mApplicationInfo.targetSdkVersion; 218 } 219 220 public boolean isSecurityViolation() { 221 return mSecurityViolation; 222 } 223 224 public CompatibilityInfo getCompatibilityInfo() { 225 return mDisplayAdjustments.getCompatibilityInfo(); 226 } 227 228 public void setCompatibilityInfo(CompatibilityInfo compatInfo) { 229 mDisplayAdjustments.setCompatibilityInfo(compatInfo); 230 } 231 232 /** 233 * Gets the array of shared libraries that are listed as 234 * used by the given package. 235 * 236 * @param packageName the name of the package (note: not its 237 * file name) 238 * @return null-ok; the array of shared libraries, each one 239 * a fully-qualified path 240 */ 241 private static String[] getLibrariesFor(String packageName) { 242 ApplicationInfo ai = null; 243 try { 244 ai = ActivityThread.getPackageManager().getApplicationInfo(packageName, 245 PackageManager.GET_SHARED_LIBRARY_FILES, UserHandle.myUserId()); 246 } catch (RemoteException e) { 247 throw e.rethrowFromSystemServer(); 248 } 249 250 if (ai == null) { 251 return null; 252 } 253 254 return ai.sharedLibraryFiles; 255 } 256 257 public void updateApplicationInfo(ApplicationInfo aInfo, List<String> oldPaths) { 258 setApplicationInfo(aInfo); 259 260 final List<String> newPaths = new ArrayList<>(); 261 makePaths(mActivityThread, aInfo, newPaths, null /*libPaths*/); 262 final List<String> addedPaths = new ArrayList<>(newPaths.size()); 263 264 if (oldPaths != null) { 265 for (String path : newPaths) { 266 final String apkName = path.substring(path.lastIndexOf(File.separator)); 267 boolean match = false; 268 for (String oldPath : oldPaths) { 269 final String oldApkName = oldPath.substring(path.lastIndexOf(File.separator)); 270 if (apkName.equals(oldApkName)) { 271 match = true; 272 break; 273 } 274 } 275 if (!match) { 276 addedPaths.add(path); 277 } 278 } 279 } else { 280 addedPaths.addAll(newPaths); 281 } 282 synchronized (this) { 283 createOrUpdateClassLoaderLocked(addedPaths); 284 if (mResources != null) { 285 mResources = mActivityThread.getTopLevelResources(mResDir, mSplitResDirs, 286 mOverlayDirs, mApplicationInfo.sharedLibraryFiles, Display.DEFAULT_DISPLAY, 287 this); 288 } 289 } 290 } 291 292 private void setApplicationInfo(ApplicationInfo aInfo) { 293 final int myUid = Process.myUid(); 294 aInfo = adjustNativeLibraryPaths(aInfo); 295 mApplicationInfo = aInfo; 296 mAppDir = aInfo.sourceDir; 297 mResDir = aInfo.uid == myUid ? aInfo.sourceDir : aInfo.publicSourceDir; 298 mSplitAppDirs = aInfo.splitSourceDirs; 299 mSplitResDirs = aInfo.uid == myUid ? aInfo.splitSourceDirs : aInfo.splitPublicSourceDirs; 300 mOverlayDirs = aInfo.resourceDirs; 301 mSharedLibraries = aInfo.sharedLibraryFiles; 302 mDataDir = aInfo.dataDir; 303 mLibDir = aInfo.nativeLibraryDir; 304 mDataDirFile = FileUtils.newFileOrNull(aInfo.dataDir); 305 mDeviceProtectedDataDirFile = FileUtils.newFileOrNull(aInfo.deviceProtectedDataDir); 306 mCredentialProtectedDataDirFile = FileUtils.newFileOrNull(aInfo.credentialProtectedDataDir); 307 } 308 309 public static void makePaths(ActivityThread activityThread, ApplicationInfo aInfo, 310 List<String> outZipPaths, List<String> outLibPaths) { 311 final String appDir = aInfo.sourceDir; 312 final String[] splitAppDirs = aInfo.splitSourceDirs; 313 final String libDir = aInfo.nativeLibraryDir; 314 final String[] sharedLibraries = aInfo.sharedLibraryFiles; 315 316 outZipPaths.clear(); 317 outZipPaths.add(appDir); 318 if (splitAppDirs != null) { 319 Collections.addAll(outZipPaths, splitAppDirs); 320 } 321 322 if (outLibPaths != null) { 323 outLibPaths.clear(); 324 } 325 326 /* 327 * The following is a bit of a hack to inject 328 * instrumentation into the system: If the app 329 * being started matches one of the instrumentation names, 330 * then we combine both the "instrumentation" and 331 * "instrumented" app into the path, along with the 332 * concatenation of both apps' shared library lists. 333 */ 334 335 String instrumentationPackageName = activityThread.mInstrumentationPackageName; 336 String instrumentationAppDir = activityThread.mInstrumentationAppDir; 337 String[] instrumentationSplitAppDirs = activityThread.mInstrumentationSplitAppDirs; 338 String instrumentationLibDir = activityThread.mInstrumentationLibDir; 339 340 String instrumentedAppDir = activityThread.mInstrumentedAppDir; 341 String[] instrumentedSplitAppDirs = activityThread.mInstrumentedSplitAppDirs; 342 String instrumentedLibDir = activityThread.mInstrumentedLibDir; 343 String[] instrumentationLibs = null; 344 345 if (appDir.equals(instrumentationAppDir) 346 || appDir.equals(instrumentedAppDir)) { 347 outZipPaths.clear(); 348 outZipPaths.add(instrumentationAppDir); 349 if (instrumentationSplitAppDirs != null) { 350 Collections.addAll(outZipPaths, instrumentationSplitAppDirs); 351 } 352 outZipPaths.add(instrumentedAppDir); 353 if (instrumentedSplitAppDirs != null) { 354 Collections.addAll(outZipPaths, instrumentedSplitAppDirs); 355 } 356 357 if (outLibPaths != null) { 358 outLibPaths.add(instrumentationLibDir); 359 outLibPaths.add(instrumentedLibDir); 360 } 361 362 if (!instrumentedAppDir.equals(instrumentationAppDir)) { 363 instrumentationLibs = getLibrariesFor(instrumentationPackageName); 364 } 365 } 366 367 if (outLibPaths != null) { 368 if (outLibPaths.isEmpty()) { 369 outLibPaths.add(libDir); 370 } 371 372 // Add path to libraries in apk for current abi. Do this now because more entries 373 // will be added to zipPaths that shouldn't be part of the library path. 374 if (aInfo.primaryCpuAbi != null) { 375 for (String apk : outZipPaths) { 376 outLibPaths.add(apk + "!/lib/" + aInfo.primaryCpuAbi); 377 } 378 } 379 380 if (aInfo.isSystemApp() && !aInfo.isUpdatedSystemApp()) { 381 // Add path to system libraries to libPaths; 382 // Access to system libs should be limited 383 // to bundled applications; this is why updated 384 // system apps are not included. 385 outLibPaths.add(System.getProperty("java.library.path")); 386 } 387 } 388 389 if (sharedLibraries != null) { 390 for (String lib : sharedLibraries) { 391 if (!outZipPaths.contains(lib)) { 392 outZipPaths.add(0, lib); 393 } 394 } 395 } 396 397 if (instrumentationLibs != null) { 398 for (String lib : instrumentationLibs) { 399 if (!outZipPaths.contains(lib)) { 400 outZipPaths.add(0, lib); 401 } 402 } 403 } 404 } 405 406 private void createOrUpdateClassLoaderLocked(List<String> addedPaths) { 407 if (mPackageName.equals("android")) { 408 if (mClassLoader != null) { 409 // nothing to update 410 return; 411 } 412 413 if (mBaseClassLoader != null) { 414 mClassLoader = mBaseClassLoader; 415 } else { 416 mClassLoader = ClassLoader.getSystemClassLoader(); 417 } 418 419 return; 420 } 421 422 // Avoid the binder call when the package is the current application package. 423 // The activity manager will perform ensure that dexopt is performed before 424 // spinning up the process. 425 if (!Objects.equals(mPackageName, ActivityThread.currentPackageName())) { 426 VMRuntime.getRuntime().vmInstructionSet(); 427 try { 428 ActivityThread.getPackageManager().notifyPackageUse(mPackageName); 429 } catch (RemoteException re) { 430 throw re.rethrowFromSystemServer(); 431 } 432 } 433 434 final List<String> zipPaths = new ArrayList<>(); 435 final List<String> libPaths = new ArrayList<>(); 436 437 if (mRegisterPackage) { 438 try { 439 ActivityManagerNative.getDefault().addPackageDependency(mPackageName); 440 } catch (RemoteException e) { 441 throw e.rethrowFromSystemServer(); 442 } 443 } 444 445 makePaths(mActivityThread, mApplicationInfo, zipPaths, libPaths); 446 final String zip = mIncludeCode ? TextUtils.join(File.pathSeparator, zipPaths) : ""; 447 final boolean isBundledApp = mApplicationInfo.isSystemApp() 448 && !mApplicationInfo.isUpdatedSystemApp(); 449 String libraryPermittedPath = mDataDir; 450 if (isBundledApp) { 451 // This is necessary to grant bundled apps access to 452 // libraries located in subdirectories of /system/lib 453 libraryPermittedPath += File.pathSeparator + 454 System.getProperty("java.library.path"); 455 } 456 // DO NOT SHIP: this is a workaround for apps loading native libraries 457 // provided by 3rd party apps using absolute path instead of corresponding 458 // classloader; see http://b/26954419 for example. 459 if (mApplicationInfo.targetSdkVersion <= 23) { 460 libraryPermittedPath += File.pathSeparator + "/data/app"; 461 } 462 // ----------------------------------------------------------------------------- 463 464 final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths); 465 466 /* 467 * With all the combination done (if necessary, actually 468 * create the class loader. 469 */ 470 471 if (ActivityThread.localLOGV) 472 Slog.v(ActivityThread.TAG, "Class path: " + zip + 473 ", JNI path: " + librarySearchPath); 474 475 if (mClassLoader == null) { 476 // Temporarily disable logging of disk reads on the Looper thread 477 // as this is early and necessary. 478 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); 479 480 mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip, 481 mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath, 482 libraryPermittedPath, mBaseClassLoader); 483 484 StrictMode.setThreadPolicy(oldPolicy); 485 } 486 487 if (addedPaths != null && addedPaths.size() > 0) { 488 final String add = TextUtils.join(File.pathSeparator, addedPaths); 489 ApplicationLoaders.getDefault().addPath(mClassLoader, add); 490 } 491 } 492 493 public ClassLoader getClassLoader() { 494 synchronized (this) { 495 if (mClassLoader == null) { 496 createOrUpdateClassLoaderLocked(null /*addedPaths*/); 497 } 498 return mClassLoader; 499 } 500 } 501 502 /** 503 * Setup value for Thread.getContextClassLoader(). If the 504 * package will not run in in a VM with other packages, we set 505 * the Java context ClassLoader to the 506 * PackageInfo.getClassLoader value. However, if this VM can 507 * contain multiple packages, we intead set the Java context 508 * ClassLoader to a proxy that will warn about the use of Java 509 * context ClassLoaders and then fall through to use the 510 * system ClassLoader. 511 * 512 * <p> Note that this is similar to but not the same as the 513 * android.content.Context.getClassLoader(). While both 514 * context class loaders are typically set to the 515 * PathClassLoader used to load the package archive in the 516 * single application per VM case, a single Android process 517 * may contain several Contexts executing on one thread with 518 * their own logical ClassLoaders while the Java context 519 * ClassLoader is a thread local. This is why in the case when 520 * we have multiple packages per VM we do not set the Java 521 * context ClassLoader to an arbitrary but instead warn the 522 * user to set their own if we detect that they are using a 523 * Java library that expects it to be set. 524 */ 525 private void initializeJavaContextClassLoader() { 526 IPackageManager pm = ActivityThread.getPackageManager(); 527 android.content.pm.PackageInfo pi; 528 try { 529 pi = pm.getPackageInfo(mPackageName, PackageManager.MATCH_DEBUG_TRIAGED_MISSING, 530 UserHandle.myUserId()); 531 } catch (RemoteException e) { 532 throw e.rethrowFromSystemServer(); 533 } 534 if (pi == null) { 535 throw new IllegalStateException("Unable to get package info for " 536 + mPackageName + "; is package not installed?"); 537 } 538 /* 539 * Two possible indications that this package could be 540 * sharing its virtual machine with other packages: 541 * 542 * 1.) the sharedUserId attribute is set in the manifest, 543 * indicating a request to share a VM with other 544 * packages with the same sharedUserId. 545 * 546 * 2.) the application element of the manifest has an 547 * attribute specifying a non-default process name, 548 * indicating the desire to run in another packages VM. 549 */ 550 boolean sharedUserIdSet = (pi.sharedUserId != null); 551 boolean processNameNotDefault = 552 (pi.applicationInfo != null && 553 !mPackageName.equals(pi.applicationInfo.processName)); 554 boolean sharable = (sharedUserIdSet || processNameNotDefault); 555 ClassLoader contextClassLoader = 556 (sharable) 557 ? new WarningContextClassLoader() 558 : mClassLoader; 559 Thread.currentThread().setContextClassLoader(contextClassLoader); 560 } 561 562 private static class WarningContextClassLoader extends ClassLoader { 563 564 private static boolean warned = false; 565 566 private void warn(String methodName) { 567 if (warned) { 568 return; 569 } 570 warned = true; 571 Thread.currentThread().setContextClassLoader(getParent()); 572 Slog.w(ActivityThread.TAG, "ClassLoader." + methodName + ": " + 573 "The class loader returned by " + 574 "Thread.getContextClassLoader() may fail for processes " + 575 "that host multiple applications. You should explicitly " + 576 "specify a context class loader. For example: " + 577 "Thread.setContextClassLoader(getClass().getClassLoader());"); 578 } 579 580 @Override public URL getResource(String resName) { 581 warn("getResource"); 582 return getParent().getResource(resName); 583 } 584 585 @Override public Enumeration<URL> getResources(String resName) throws IOException { 586 warn("getResources"); 587 return getParent().getResources(resName); 588 } 589 590 @Override public InputStream getResourceAsStream(String resName) { 591 warn("getResourceAsStream"); 592 return getParent().getResourceAsStream(resName); 593 } 594 595 @Override public Class<?> loadClass(String className) throws ClassNotFoundException { 596 warn("loadClass"); 597 return getParent().loadClass(className); 598 } 599 600 @Override public void setClassAssertionStatus(String cname, boolean enable) { 601 warn("setClassAssertionStatus"); 602 getParent().setClassAssertionStatus(cname, enable); 603 } 604 605 @Override public void setPackageAssertionStatus(String pname, boolean enable) { 606 warn("setPackageAssertionStatus"); 607 getParent().setPackageAssertionStatus(pname, enable); 608 } 609 610 @Override public void setDefaultAssertionStatus(boolean enable) { 611 warn("setDefaultAssertionStatus"); 612 getParent().setDefaultAssertionStatus(enable); 613 } 614 615 @Override public void clearAssertionStatus() { 616 warn("clearAssertionStatus"); 617 getParent().clearAssertionStatus(); 618 } 619 } 620 621 public String getAppDir() { 622 return mAppDir; 623 } 624 625 public String getLibDir() { 626 return mLibDir; 627 } 628 629 public String getResDir() { 630 return mResDir; 631 } 632 633 public String[] getSplitAppDirs() { 634 return mSplitAppDirs; 635 } 636 637 public String[] getSplitResDirs() { 638 return mSplitResDirs; 639 } 640 641 public String[] getOverlayDirs() { 642 return mOverlayDirs; 643 } 644 645 public String getDataDir() { 646 return mDataDir; 647 } 648 649 public File getDataDirFile() { 650 return mDataDirFile; 651 } 652 653 public File getDeviceProtectedDataDirFile() { 654 return mDeviceProtectedDataDirFile; 655 } 656 657 public File getCredentialProtectedDataDirFile() { 658 return mCredentialProtectedDataDirFile; 659 } 660 661 public AssetManager getAssets(ActivityThread mainThread) { 662 return getResources(mainThread).getAssets(); 663 } 664 665 public Resources getResources(ActivityThread mainThread) { 666 if (mResources == null) { 667 mResources = mainThread.getTopLevelResources(mResDir, mSplitResDirs, mOverlayDirs, 668 mApplicationInfo.sharedLibraryFiles, Display.DEFAULT_DISPLAY, this); 669 } 670 return mResources; 671 } 672 673 public Application makeApplication(boolean forceDefaultAppClass, 674 Instrumentation instrumentation) { 675 if (mApplication != null) { 676 return mApplication; 677 } 678 679 Application app = null; 680 681 String appClass = mApplicationInfo.className; 682 if (forceDefaultAppClass || (appClass == null)) { 683 appClass = "android.app.Application"; 684 } 685 686 try { 687 java.lang.ClassLoader cl = getClassLoader(); 688 if (!mPackageName.equals("android")) { 689 initializeJavaContextClassLoader(); 690 } 691 ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this); 692 app = mActivityThread.mInstrumentation.newApplication( 693 cl, appClass, appContext); 694 appContext.setOuterContext(app); 695 } catch (Exception e) { 696 if (!mActivityThread.mInstrumentation.onException(app, e)) { 697 throw new RuntimeException( 698 "Unable to instantiate application " + appClass 699 + ": " + e.toString(), e); 700 } 701 } 702 mActivityThread.mAllApplications.add(app); 703 mApplication = app; 704 705 if (instrumentation != null) { 706 try { 707 instrumentation.callApplicationOnCreate(app); 708 } catch (Exception e) { 709 if (!instrumentation.onException(app, e)) { 710 throw new RuntimeException( 711 "Unable to create application " + app.getClass().getName() 712 + ": " + e.toString(), e); 713 } 714 } 715 } 716 717 // Rewrite the R 'constants' for all library apks. 718 SparseArray<String> packageIdentifiers = getAssets(mActivityThread) 719 .getAssignedPackageIdentifiers(); 720 final int N = packageIdentifiers.size(); 721 for (int i = 0; i < N; i++) { 722 final int id = packageIdentifiers.keyAt(i); 723 if (id == 0x01 || id == 0x7f) { 724 continue; 725 } 726 727 rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id); 728 } 729 730 return app; 731 } 732 733 private void rewriteRValues(ClassLoader cl, String packageName, int id) { 734 final Class<?> rClazz; 735 try { 736 rClazz = cl.loadClass(packageName + ".R"); 737 } catch (ClassNotFoundException e) { 738 // This is not necessarily an error, as some packages do not ship with resources 739 // (or they do not need rewriting). 740 Log.i(TAG, "No resource references to update in package " + packageName); 741 return; 742 } 743 744 final Method callback; 745 try { 746 callback = rClazz.getMethod("onResourcesLoaded", int.class); 747 } catch (NoSuchMethodException e) { 748 // No rewriting to be done. 749 return; 750 } 751 752 Throwable cause; 753 try { 754 callback.invoke(null, id); 755 return; 756 } catch (IllegalAccessException e) { 757 cause = e; 758 } catch (InvocationTargetException e) { 759 cause = e.getCause(); 760 } 761 762 throw new RuntimeException("Failed to rewrite resource references for " + packageName, 763 cause); 764 } 765 766 public void removeContextRegistrations(Context context, 767 String who, String what) { 768 final boolean reportRegistrationLeaks = StrictMode.vmRegistrationLeaksEnabled(); 769 synchronized (mReceivers) { 770 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> rmap = 771 mReceivers.remove(context); 772 if (rmap != null) { 773 for (int i = 0; i < rmap.size(); i++) { 774 LoadedApk.ReceiverDispatcher rd = rmap.valueAt(i); 775 IntentReceiverLeaked leak = new IntentReceiverLeaked( 776 what + " " + who + " has leaked IntentReceiver " 777 + rd.getIntentReceiver() + " that was " + 778 "originally registered here. Are you missing a " + 779 "call to unregisterReceiver()?"); 780 leak.setStackTrace(rd.getLocation().getStackTrace()); 781 Slog.e(ActivityThread.TAG, leak.getMessage(), leak); 782 if (reportRegistrationLeaks) { 783 StrictMode.onIntentReceiverLeaked(leak); 784 } 785 try { 786 ActivityManagerNative.getDefault().unregisterReceiver( 787 rd.getIIntentReceiver()); 788 } catch (RemoteException e) { 789 throw e.rethrowFromSystemServer(); 790 } 791 } 792 } 793 mUnregisteredReceivers.remove(context); 794 } 795 796 synchronized (mServices) { 797 //Slog.i(TAG, "Receiver registrations: " + mReceivers); 798 ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> smap = 799 mServices.remove(context); 800 if (smap != null) { 801 for (int i = 0; i < smap.size(); i++) { 802 LoadedApk.ServiceDispatcher sd = smap.valueAt(i); 803 ServiceConnectionLeaked leak = new ServiceConnectionLeaked( 804 what + " " + who + " has leaked ServiceConnection " 805 + sd.getServiceConnection() + " that was originally bound here"); 806 leak.setStackTrace(sd.getLocation().getStackTrace()); 807 Slog.e(ActivityThread.TAG, leak.getMessage(), leak); 808 if (reportRegistrationLeaks) { 809 StrictMode.onServiceConnectionLeaked(leak); 810 } 811 try { 812 ActivityManagerNative.getDefault().unbindService( 813 sd.getIServiceConnection()); 814 } catch (RemoteException e) { 815 throw e.rethrowFromSystemServer(); 816 } 817 sd.doForget(); 818 } 819 } 820 mUnboundServices.remove(context); 821 //Slog.i(TAG, "Service registrations: " + mServices); 822 } 823 } 824 825 public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r, 826 Context context, Handler handler, 827 Instrumentation instrumentation, boolean registered) { 828 synchronized (mReceivers) { 829 LoadedApk.ReceiverDispatcher rd = null; 830 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null; 831 if (registered) { 832 map = mReceivers.get(context); 833 if (map != null) { 834 rd = map.get(r); 835 } 836 } 837 if (rd == null) { 838 rd = new ReceiverDispatcher(r, context, handler, 839 instrumentation, registered); 840 if (registered) { 841 if (map == null) { 842 map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>(); 843 mReceivers.put(context, map); 844 } 845 map.put(r, rd); 846 } 847 } else { 848 rd.validate(context, handler); 849 } 850 rd.mForgotten = false; 851 return rd.getIIntentReceiver(); 852 } 853 } 854 855 public IIntentReceiver forgetReceiverDispatcher(Context context, 856 BroadcastReceiver r) { 857 synchronized (mReceivers) { 858 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = mReceivers.get(context); 859 LoadedApk.ReceiverDispatcher rd = null; 860 if (map != null) { 861 rd = map.get(r); 862 if (rd != null) { 863 map.remove(r); 864 if (map.size() == 0) { 865 mReceivers.remove(context); 866 } 867 if (r.getDebugUnregister()) { 868 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder 869 = mUnregisteredReceivers.get(context); 870 if (holder == null) { 871 holder = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>(); 872 mUnregisteredReceivers.put(context, holder); 873 } 874 RuntimeException ex = new IllegalArgumentException( 875 "Originally unregistered here:"); 876 ex.fillInStackTrace(); 877 rd.setUnregisterLocation(ex); 878 holder.put(r, rd); 879 } 880 rd.mForgotten = true; 881 return rd.getIIntentReceiver(); 882 } 883 } 884 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder 885 = mUnregisteredReceivers.get(context); 886 if (holder != null) { 887 rd = holder.get(r); 888 if (rd != null) { 889 RuntimeException ex = rd.getUnregisterLocation(); 890 throw new IllegalArgumentException( 891 "Unregistering Receiver " + r 892 + " that was already unregistered", ex); 893 } 894 } 895 if (context == null) { 896 throw new IllegalStateException("Unbinding Receiver " + r 897 + " from Context that is no longer in use: " + context); 898 } else { 899 throw new IllegalArgumentException("Receiver not registered: " + r); 900 } 901 902 } 903 } 904 905 static final class ReceiverDispatcher { 906 907 final static class InnerReceiver extends IIntentReceiver.Stub { 908 final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher; 909 final LoadedApk.ReceiverDispatcher mStrongRef; 910 911 InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) { 912 mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd); 913 mStrongRef = strong ? rd : null; 914 } 915 916 @Override 917 public void performReceive(Intent intent, int resultCode, String data, 918 Bundle extras, boolean ordered, boolean sticky, int sendingUser) { 919 LoadedApk.ReceiverDispatcher rd = mDispatcher.get(); 920 if (ActivityThread.DEBUG_BROADCAST) { 921 int seq = intent.getIntExtra("seq", -1); 922 Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction() + " seq=" + seq 923 + " to " + (rd != null ? rd.mReceiver : null)); 924 } 925 if (rd != null) { 926 rd.performReceive(intent, resultCode, data, extras, 927 ordered, sticky, sendingUser); 928 } else { 929 // The activity manager dispatched a broadcast to a registered 930 // receiver in this process, but before it could be delivered the 931 // receiver was unregistered. Acknowledge the broadcast on its 932 // behalf so that the system's broadcast sequence can continue. 933 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, 934 "Finishing broadcast to unregistered receiver"); 935 IActivityManager mgr = ActivityManagerNative.getDefault(); 936 try { 937 if (extras != null) { 938 extras.setAllowFds(false); 939 } 940 mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags()); 941 } catch (RemoteException e) { 942 throw e.rethrowFromSystemServer(); 943 } 944 } 945 } 946 } 947 948 final IIntentReceiver.Stub mIIntentReceiver; 949 final BroadcastReceiver mReceiver; 950 final Context mContext; 951 final Handler mActivityThread; 952 final Instrumentation mInstrumentation; 953 final boolean mRegistered; 954 final IntentReceiverLeaked mLocation; 955 RuntimeException mUnregisterLocation; 956 boolean mForgotten; 957 958 final class Args extends BroadcastReceiver.PendingResult implements Runnable { 959 private Intent mCurIntent; 960 private final boolean mOrdered; 961 962 public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras, 963 boolean ordered, boolean sticky, int sendingUser) { 964 super(resultCode, resultData, resultExtras, 965 mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered, 966 sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags()); 967 mCurIntent = intent; 968 mOrdered = ordered; 969 } 970 971 public void run() { 972 final BroadcastReceiver receiver = mReceiver; 973 final boolean ordered = mOrdered; 974 975 if (ActivityThread.DEBUG_BROADCAST) { 976 int seq = mCurIntent.getIntExtra("seq", -1); 977 Slog.i(ActivityThread.TAG, "Dispatching broadcast " + mCurIntent.getAction() 978 + " seq=" + seq + " to " + mReceiver); 979 Slog.i(ActivityThread.TAG, " mRegistered=" + mRegistered 980 + " mOrderedHint=" + ordered); 981 } 982 983 final IActivityManager mgr = ActivityManagerNative.getDefault(); 984 final Intent intent = mCurIntent; 985 mCurIntent = null; 986 987 if (receiver == null || mForgotten) { 988 if (mRegistered && ordered) { 989 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, 990 "Finishing null broadcast to " + mReceiver); 991 sendFinished(mgr); 992 } 993 return; 994 } 995 996 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg"); 997 try { 998 ClassLoader cl = mReceiver.getClass().getClassLoader(); 999 intent.setExtrasClassLoader(cl); 1000 intent.prepareToEnterProcess(); 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