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