LoadedApk.java revision 8091edbffbacbf80eebe0ed646e6ec9f6aafe5be
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        ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> rmap =
636                mReceivers.remove(context);
637        if (rmap != null) {
638            for (int i=0; i<rmap.size(); i++) {
639                LoadedApk.ReceiverDispatcher rd = rmap.valueAt(i);
640                IntentReceiverLeaked leak = new IntentReceiverLeaked(
641                        what + " " + who + " has leaked IntentReceiver "
642                        + rd.getIntentReceiver() + " that was " +
643                        "originally registered here. Are you missing a " +
644                        "call to unregisterReceiver()?");
645                leak.setStackTrace(rd.getLocation().getStackTrace());
646                Slog.e(ActivityThread.TAG, leak.getMessage(), leak);
647                if (reportRegistrationLeaks) {
648                    StrictMode.onIntentReceiverLeaked(leak);
649                }
650                try {
651                    ActivityManagerNative.getDefault().unregisterReceiver(
652                            rd.getIIntentReceiver());
653                } catch (RemoteException e) {
654                    // system crashed, nothing we can do
655                }
656            }
657        }
658        mUnregisteredReceivers.remove(context);
659        //Slog.i(TAG, "Receiver registrations: " + mReceivers);
660        ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> smap =
661            mServices.remove(context);
662        if (smap != null) {
663            for (int i=0; i<smap.size(); i++) {
664                LoadedApk.ServiceDispatcher sd = smap.valueAt(i);
665                ServiceConnectionLeaked leak = new ServiceConnectionLeaked(
666                        what + " " + who + " has leaked ServiceConnection "
667                        + sd.getServiceConnection() + " that was originally bound here");
668                leak.setStackTrace(sd.getLocation().getStackTrace());
669                Slog.e(ActivityThread.TAG, leak.getMessage(), leak);
670                if (reportRegistrationLeaks) {
671                    StrictMode.onServiceConnectionLeaked(leak);
672                }
673                try {
674                    ActivityManagerNative.getDefault().unbindService(
675                            sd.getIServiceConnection());
676                } catch (RemoteException e) {
677                    // system crashed, nothing we can do
678                }
679                sd.doForget();
680            }
681        }
682        mUnboundServices.remove(context);
683        //Slog.i(TAG, "Service registrations: " + mServices);
684    }
685
686    public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
687            Context context, Handler handler,
688            Instrumentation instrumentation, boolean registered) {
689        synchronized (mReceivers) {
690            LoadedApk.ReceiverDispatcher rd = null;
691            ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
692            if (registered) {
693                map = mReceivers.get(context);
694                if (map != null) {
695                    rd = map.get(r);
696                }
697            }
698            if (rd == null) {
699                rd = new ReceiverDispatcher(r, context, handler,
700                        instrumentation, registered);
701                if (registered) {
702                    if (map == null) {
703                        map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
704                        mReceivers.put(context, map);
705                    }
706                    map.put(r, rd);
707                }
708            } else {
709                rd.validate(context, handler);
710            }
711            rd.mForgotten = false;
712            return rd.getIIntentReceiver();
713        }
714    }
715
716    public IIntentReceiver forgetReceiverDispatcher(Context context,
717            BroadcastReceiver r) {
718        synchronized (mReceivers) {
719            ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = mReceivers.get(context);
720            LoadedApk.ReceiverDispatcher rd = null;
721            if (map != null) {
722                rd = map.get(r);
723                if (rd != null) {
724                    map.remove(r);
725                    if (map.size() == 0) {
726                        mReceivers.remove(context);
727                    }
728                    if (r.getDebugUnregister()) {
729                        ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder
730                                = mUnregisteredReceivers.get(context);
731                        if (holder == null) {
732                            holder = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
733                            mUnregisteredReceivers.put(context, holder);
734                        }
735                        RuntimeException ex = new IllegalArgumentException(
736                                "Originally unregistered here:");
737                        ex.fillInStackTrace();
738                        rd.setUnregisterLocation(ex);
739                        holder.put(r, rd);
740                    }
741                    rd.mForgotten = true;
742                    return rd.getIIntentReceiver();
743                }
744            }
745            ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder
746                    = mUnregisteredReceivers.get(context);
747            if (holder != null) {
748                rd = holder.get(r);
749                if (rd != null) {
750                    RuntimeException ex = rd.getUnregisterLocation();
751                    throw new IllegalArgumentException(
752                            "Unregistering Receiver " + r
753                            + " that was already unregistered", ex);
754                }
755            }
756            if (context == null) {
757                throw new IllegalStateException("Unbinding Receiver " + r
758                        + " from Context that is no longer in use: " + context);
759            } else {
760                throw new IllegalArgumentException("Receiver not registered: " + r);
761            }
762
763        }
764    }
765
766    static final class ReceiverDispatcher {
767
768        final static class InnerReceiver extends IIntentReceiver.Stub {
769            final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
770            final LoadedApk.ReceiverDispatcher mStrongRef;
771
772            InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
773                mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
774                mStrongRef = strong ? rd : null;
775            }
776            public void performReceive(Intent intent, int resultCode, String data,
777                    Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
778                LoadedApk.ReceiverDispatcher rd = mDispatcher.get();
779                if (ActivityThread.DEBUG_BROADCAST) {
780                    int seq = intent.getIntExtra("seq", -1);
781                    Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction() + " seq=" + seq
782                            + " to " + (rd != null ? rd.mReceiver : null));
783                }
784                if (rd != null) {
785                    rd.performReceive(intent, resultCode, data, extras,
786                            ordered, sticky, sendingUser);
787                } else {
788                    // The activity manager dispatched a broadcast to a registered
789                    // receiver in this process, but before it could be delivered the
790                    // receiver was unregistered.  Acknowledge the broadcast on its
791                    // behalf so that the system's broadcast sequence can continue.
792                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
793                            "Finishing broadcast to unregistered receiver");
794                    IActivityManager mgr = ActivityManagerNative.getDefault();
795                    try {
796                        if (extras != null) {
797                            extras.setAllowFds(false);
798                        }
799                        mgr.finishReceiver(this, resultCode, data, extras, false);
800                    } catch (RemoteException e) {
801                        Slog.w(ActivityThread.TAG, "Couldn't finish broadcast to unregistered receiver");
802                    }
803                }
804            }
805        }
806
807        final IIntentReceiver.Stub mIIntentReceiver;
808        final BroadcastReceiver mReceiver;
809        final Context mContext;
810        final Handler mActivityThread;
811        final Instrumentation mInstrumentation;
812        final boolean mRegistered;
813        final IntentReceiverLeaked mLocation;
814        RuntimeException mUnregisterLocation;
815        boolean mForgotten;
816
817        final class Args extends BroadcastReceiver.PendingResult implements Runnable {
818            private Intent mCurIntent;
819            private final boolean mOrdered;
820
821            public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
822                    boolean ordered, boolean sticky, int sendingUser) {
823                super(resultCode, resultData, resultExtras,
824                        mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED,
825                        ordered, sticky, mIIntentReceiver.asBinder(), sendingUser);
826                mCurIntent = intent;
827                mOrdered = ordered;
828            }
829
830            public void run() {
831                final BroadcastReceiver receiver = mReceiver;
832                final boolean ordered = mOrdered;
833
834                if (ActivityThread.DEBUG_BROADCAST) {
835                    int seq = mCurIntent.getIntExtra("seq", -1);
836                    Slog.i(ActivityThread.TAG, "Dispatching broadcast " + mCurIntent.getAction()
837                            + " seq=" + seq + " to " + mReceiver);
838                    Slog.i(ActivityThread.TAG, "  mRegistered=" + mRegistered
839                            + " mOrderedHint=" + ordered);
840                }
841
842                final IActivityManager mgr = ActivityManagerNative.getDefault();
843                final Intent intent = mCurIntent;
844                mCurIntent = null;
845
846                if (receiver == null || mForgotten) {
847                    if (mRegistered && ordered) {
848                        if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
849                                "Finishing null broadcast to " + mReceiver);
850                        sendFinished(mgr);
851                    }
852                    return;
853                }
854
855                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg");
856                try {
857                    ClassLoader cl =  mReceiver.getClass().getClassLoader();
858                    intent.setExtrasClassLoader(cl);
859                    setExtrasClassLoader(cl);
860                    receiver.setPendingResult(this);
861                    receiver.onReceive(mContext, intent);
862                } catch (Exception e) {
863                    if (mRegistered && ordered) {
864                        if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
865                                "Finishing failed broadcast to " + mReceiver);
866                        sendFinished(mgr);
867                    }
868                    if (mInstrumentation == null ||
869                            !mInstrumentation.onException(mReceiver, e)) {
870                        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
871                        throw new RuntimeException(
872                            "Error receiving broadcast " + intent
873                            + " in " + mReceiver, e);
874                    }
875                }
876
877                if (receiver.getPendingResult() != null) {
878                    finish();
879                }
880                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
881            }
882        }
883
884        ReceiverDispatcher(BroadcastReceiver receiver, Context context,
885                Handler activityThread, Instrumentation instrumentation,
886                boolean registered) {
887            if (activityThread == null) {
888                throw new NullPointerException("Handler must not be null");
889            }
890
891            mIIntentReceiver = new InnerReceiver(this, !registered);
892            mReceiver = receiver;
893            mContext = context;
894            mActivityThread = activityThread;
895            mInstrumentation = instrumentation;
896            mRegistered = registered;
897            mLocation = new IntentReceiverLeaked(null);
898            mLocation.fillInStackTrace();
899        }
900
901        void validate(Context context, Handler activityThread) {
902            if (mContext != context) {
903                throw new IllegalStateException(
904                    "Receiver " + mReceiver +
905                    " registered with differing Context (was " +
906                    mContext + " now " + context + ")");
907            }
908            if (mActivityThread != activityThread) {
909                throw new IllegalStateException(
910                    "Receiver " + mReceiver +
911                    " registered with differing handler (was " +
912                    mActivityThread + " now " + activityThread + ")");
913            }
914        }
915
916        IntentReceiverLeaked getLocation() {
917            return mLocation;
918        }
919
920        BroadcastReceiver getIntentReceiver() {
921            return mReceiver;
922        }
923
924        IIntentReceiver getIIntentReceiver() {
925            return mIIntentReceiver;
926        }
927
928        void setUnregisterLocation(RuntimeException ex) {
929            mUnregisterLocation = ex;
930        }
931
932        RuntimeException getUnregisterLocation() {
933            return mUnregisterLocation;
934        }
935
936        public void performReceive(Intent intent, int resultCode, String data,
937                Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
938            if (ActivityThread.DEBUG_BROADCAST) {
939                int seq = intent.getIntExtra("seq", -1);
940                Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq
941                        + " to " + mReceiver);
942            }
943            Args args = new Args(intent, resultCode, data, extras, ordered,
944                    sticky, sendingUser);
945            if (!mActivityThread.post(args)) {
946                if (mRegistered && ordered) {
947                    IActivityManager mgr = ActivityManagerNative.getDefault();
948                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
949                            "Finishing sync broadcast to " + mReceiver);
950                    args.sendFinished(mgr);
951                }
952            }
953        }
954
955    }
956
957    public final IServiceConnection getServiceDispatcher(ServiceConnection c,
958            Context context, Handler handler, int flags) {
959        synchronized (mServices) {
960            LoadedApk.ServiceDispatcher sd = null;
961            ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
962            if (map != null) {
963                sd = map.get(c);
964            }
965            if (sd == null) {
966                sd = new ServiceDispatcher(c, context, handler, flags);
967                if (map == null) {
968                    map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
969                    mServices.put(context, map);
970                }
971                map.put(c, sd);
972            } else {
973                sd.validate(context, handler);
974            }
975            return sd.getIServiceConnection();
976        }
977    }
978
979    public final IServiceConnection forgetServiceDispatcher(Context context,
980            ServiceConnection c) {
981        synchronized (mServices) {
982            ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map
983                    = mServices.get(context);
984            LoadedApk.ServiceDispatcher sd = null;
985            if (map != null) {
986                sd = map.get(c);
987                if (sd != null) {
988                    map.remove(c);
989                    sd.doForget();
990                    if (map.size() == 0) {
991                        mServices.remove(context);
992                    }
993                    if ((sd.getFlags()&Context.BIND_DEBUG_UNBIND) != 0) {
994                        ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder
995                                = mUnboundServices.get(context);
996                        if (holder == null) {
997                            holder = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
998                            mUnboundServices.put(context, holder);
999                        }
1000                        RuntimeException ex = new IllegalArgumentException(
1001                                "Originally unbound here:");
1002                        ex.fillInStackTrace();
1003                        sd.setUnbindLocation(ex);
1004                        holder.put(c, sd);
1005                    }
1006                    return sd.getIServiceConnection();
1007                }
1008            }
1009            ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder
1010                    = mUnboundServices.get(context);
1011            if (holder != null) {
1012                sd = holder.get(c);
1013                if (sd != null) {
1014                    RuntimeException ex = sd.getUnbindLocation();
1015                    throw new IllegalArgumentException(
1016                            "Unbinding Service " + c
1017                            + " that was already unbound", ex);
1018                }
1019            }
1020            if (context == null) {
1021                throw new IllegalStateException("Unbinding Service " + c
1022                        + " from Context that is no longer in use: " + context);
1023            } else {
1024                throw new IllegalArgumentException("Service not registered: " + c);
1025            }
1026        }
1027    }
1028
1029    static final class ServiceDispatcher {
1030        private final ServiceDispatcher.InnerConnection mIServiceConnection;
1031        private final ServiceConnection mConnection;
1032        private final Context mContext;
1033        private final Handler mActivityThread;
1034        private final ServiceConnectionLeaked mLocation;
1035        private final int mFlags;
1036
1037        private RuntimeException mUnbindLocation;
1038
1039        private boolean mDied;
1040        private boolean mForgotten;
1041
1042        private static class ConnectionInfo {
1043            IBinder binder;
1044            IBinder.DeathRecipient deathMonitor;
1045        }
1046
1047        private static class InnerConnection extends IServiceConnection.Stub {
1048            final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
1049
1050            InnerConnection(LoadedApk.ServiceDispatcher sd) {
1051                mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
1052            }
1053
1054            public void connected(ComponentName name, IBinder service) throws RemoteException {
1055                LoadedApk.ServiceDispatcher sd = mDispatcher.get();
1056                if (sd != null) {
1057                    sd.connected(name, service);
1058                }
1059            }
1060        }
1061
1062        private final ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections
1063            = new ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo>();
1064
1065        ServiceDispatcher(ServiceConnection conn,
1066                Context context, Handler activityThread, int flags) {
1067            mIServiceConnection = new InnerConnection(this);
1068            mConnection = conn;
1069            mContext = context;
1070            mActivityThread = activityThread;
1071            mLocation = new ServiceConnectionLeaked(null);
1072            mLocation.fillInStackTrace();
1073            mFlags = flags;
1074        }
1075
1076        void validate(Context context, Handler activityThread) {
1077            if (mContext != context) {
1078                throw new RuntimeException(
1079                    "ServiceConnection " + mConnection +
1080                    " registered with differing Context (was " +
1081                    mContext + " now " + context + ")");
1082            }
1083            if (mActivityThread != activityThread) {
1084                throw new RuntimeException(
1085                    "ServiceConnection " + mConnection +
1086                    " registered with differing handler (was " +
1087                    mActivityThread + " now " + activityThread + ")");
1088            }
1089        }
1090
1091        void doForget() {
1092            synchronized(this) {
1093                for (int i=0; i<mActiveConnections.size(); i++) {
1094                    ServiceDispatcher.ConnectionInfo ci = mActiveConnections.valueAt(i);
1095                    ci.binder.unlinkToDeath(ci.deathMonitor, 0);
1096                }
1097                mActiveConnections.clear();
1098                mForgotten = true;
1099            }
1100        }
1101
1102        ServiceConnectionLeaked getLocation() {
1103            return mLocation;
1104        }
1105
1106        ServiceConnection getServiceConnection() {
1107            return mConnection;
1108        }
1109
1110        IServiceConnection getIServiceConnection() {
1111            return mIServiceConnection;
1112        }
1113
1114        int getFlags() {
1115            return mFlags;
1116        }
1117
1118        void setUnbindLocation(RuntimeException ex) {
1119            mUnbindLocation = ex;
1120        }
1121
1122        RuntimeException getUnbindLocation() {
1123            return mUnbindLocation;
1124        }
1125
1126        public void connected(ComponentName name, IBinder service) {
1127            if (mActivityThread != null) {
1128                mActivityThread.post(new RunConnection(name, service, 0));
1129            } else {
1130                doConnected(name, service);
1131            }
1132        }
1133
1134        public void death(ComponentName name, IBinder service) {
1135            ServiceDispatcher.ConnectionInfo old;
1136
1137            synchronized (this) {
1138                mDied = true;
1139                old = mActiveConnections.remove(name);
1140                if (old == null || old.binder != service) {
1141                    // Death for someone different than who we last
1142                    // reported...  just ignore it.
1143                    return;
1144                }
1145                old.binder.unlinkToDeath(old.deathMonitor, 0);
1146            }
1147
1148            if (mActivityThread != null) {
1149                mActivityThread.post(new RunConnection(name, service, 1));
1150            } else {
1151                doDeath(name, service);
1152            }
1153        }
1154
1155        public void doConnected(ComponentName name, IBinder service) {
1156            ServiceDispatcher.ConnectionInfo old;
1157            ServiceDispatcher.ConnectionInfo info;
1158
1159            synchronized (this) {
1160                if (mForgotten) {
1161                    // We unbound before receiving the connection; ignore
1162                    // any connection received.
1163                    return;
1164                }
1165                old = mActiveConnections.get(name);
1166                if (old != null && old.binder == service) {
1167                    // Huh, already have this one.  Oh well!
1168                    return;
1169                }
1170
1171                if (service != null) {
1172                    // A new service is being connected... set it all up.
1173                    mDied = false;
1174                    info = new ConnectionInfo();
1175                    info.binder = service;
1176                    info.deathMonitor = new DeathMonitor(name, service);
1177                    try {
1178                        service.linkToDeath(info.deathMonitor, 0);
1179                        mActiveConnections.put(name, info);
1180                    } catch (RemoteException e) {
1181                        // This service was dead before we got it...  just
1182                        // don't do anything with it.
1183                        mActiveConnections.remove(name);
1184                        return;
1185                    }
1186
1187                } else {
1188                    // The named service is being disconnected... clean up.
1189                    mActiveConnections.remove(name);
1190                }
1191
1192                if (old != null) {
1193                    old.binder.unlinkToDeath(old.deathMonitor, 0);
1194                }
1195            }
1196
1197            // If there was an old service, it is not disconnected.
1198            if (old != null) {
1199                mConnection.onServiceDisconnected(name);
1200            }
1201            // If there is a new service, it is now connected.
1202            if (service != null) {
1203                mConnection.onServiceConnected(name, service);
1204            }
1205        }
1206
1207        public void doDeath(ComponentName name, IBinder service) {
1208            mConnection.onServiceDisconnected(name);
1209        }
1210
1211        private final class RunConnection implements Runnable {
1212            RunConnection(ComponentName name, IBinder service, int command) {
1213                mName = name;
1214                mService = service;
1215                mCommand = command;
1216            }
1217
1218            public void run() {
1219                if (mCommand == 0) {
1220                    doConnected(mName, mService);
1221                } else if (mCommand == 1) {
1222                    doDeath(mName, mService);
1223                }
1224            }
1225
1226            final ComponentName mName;
1227            final IBinder mService;
1228            final int mCommand;
1229        }
1230
1231        private final class DeathMonitor implements IBinder.DeathRecipient
1232        {
1233            DeathMonitor(ComponentName name, IBinder service) {
1234                mName = name;
1235                mService = service;
1236            }
1237
1238            public void binderDied() {
1239                death(mName, mService);
1240            }
1241
1242            final ComponentName mName;
1243            final IBinder mService;
1244        }
1245    }
1246}
1247