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