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