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