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