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