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