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