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