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