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