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 IllegalStateException("Unable to get package info for "
366                    + mPackageName + "; is system dying?", e);
367        }
368        if (pi == null) {
369            throw new IllegalStateException("Unable to get package info for "
370                    + mPackageName + "; is package not installed?");
371        }
372        /*
373         * Two possible indications that this package could be
374         * sharing its virtual machine with other packages:
375         *
376         * 1.) the sharedUserId attribute is set in the manifest,
377         *     indicating a request to share a VM with other
378         *     packages with the same sharedUserId.
379         *
380         * 2.) the application element of the manifest has an
381         *     attribute specifying a non-default process name,
382         *     indicating the desire to run in another packages VM.
383         */
384        boolean sharedUserIdSet = (pi.sharedUserId != null);
385        boolean processNameNotDefault =
386            (pi.applicationInfo != null &&
387             !mPackageName.equals(pi.applicationInfo.processName));
388        boolean sharable = (sharedUserIdSet || processNameNotDefault);
389        ClassLoader contextClassLoader =
390            (sharable)
391            ? new WarningContextClassLoader()
392            : mClassLoader;
393        Thread.currentThread().setContextClassLoader(contextClassLoader);
394    }
395
396    private static class WarningContextClassLoader extends ClassLoader {
397
398        private static boolean warned = false;
399
400        private void warn(String methodName) {
401            if (warned) {
402                return;
403            }
404            warned = true;
405            Thread.currentThread().setContextClassLoader(getParent());
406            Slog.w(ActivityThread.TAG, "ClassLoader." + methodName + ": " +
407                  "The class loader returned by " +
408                  "Thread.getContextClassLoader() may fail for processes " +
409                  "that host multiple applications. You should explicitly " +
410                  "specify a context class loader. For example: " +
411                  "Thread.setContextClassLoader(getClass().getClassLoader());");
412        }
413
414        @Override public URL getResource(String resName) {
415            warn("getResource");
416            return getParent().getResource(resName);
417        }
418
419        @Override public Enumeration<URL> getResources(String resName) throws IOException {
420            warn("getResources");
421            return getParent().getResources(resName);
422        }
423
424        @Override public InputStream getResourceAsStream(String resName) {
425            warn("getResourceAsStream");
426            return getParent().getResourceAsStream(resName);
427        }
428
429        @Override public Class<?> loadClass(String className) throws ClassNotFoundException {
430            warn("loadClass");
431            return getParent().loadClass(className);
432        }
433
434        @Override public void setClassAssertionStatus(String cname, boolean enable) {
435            warn("setClassAssertionStatus");
436            getParent().setClassAssertionStatus(cname, enable);
437        }
438
439        @Override public void setPackageAssertionStatus(String pname, boolean enable) {
440            warn("setPackageAssertionStatus");
441            getParent().setPackageAssertionStatus(pname, enable);
442        }
443
444        @Override public void setDefaultAssertionStatus(boolean enable) {
445            warn("setDefaultAssertionStatus");
446            getParent().setDefaultAssertionStatus(enable);
447        }
448
449        @Override public void clearAssertionStatus() {
450            warn("clearAssertionStatus");
451            getParent().clearAssertionStatus();
452        }
453    }
454
455    public String getAppDir() {
456        return mAppDir;
457    }
458
459    public String getLibDir() {
460        return mLibDir;
461    }
462
463    public String getResDir() {
464        return mResDir;
465    }
466
467    public String getDataDir() {
468        return mDataDir;
469    }
470
471    public File getDataDirFile() {
472        return mDataDirFile;
473    }
474
475    public AssetManager getAssets(ActivityThread mainThread) {
476        return getResources(mainThread).getAssets();
477    }
478
479    public Resources getResources(ActivityThread mainThread) {
480        if (mResources == null) {
481            mResources = mainThread.getTopLevelResources(mResDir,
482                    Display.DEFAULT_DISPLAY, null, this);
483        }
484        return mResources;
485    }
486
487    public Application makeApplication(boolean forceDefaultAppClass,
488            Instrumentation instrumentation) {
489        if (mApplication != null) {
490            return mApplication;
491        }
492
493        Application app = null;
494
495        String appClass = mApplicationInfo.className;
496        if (forceDefaultAppClass || (appClass == null)) {
497            appClass = "android.app.Application";
498        }
499
500        try {
501            java.lang.ClassLoader cl = getClassLoader();
502            ContextImpl appContext = new ContextImpl();
503            appContext.init(this, null, mActivityThread);
504            app = mActivityThread.mInstrumentation.newApplication(
505                    cl, appClass, appContext);
506            appContext.setOuterContext(app);
507        } catch (Exception e) {
508            if (!mActivityThread.mInstrumentation.onException(app, e)) {
509                throw new RuntimeException(
510                    "Unable to instantiate application " + appClass
511                    + ": " + e.toString(), e);
512            }
513        }
514        mActivityThread.mAllApplications.add(app);
515        mApplication = app;
516
517        if (instrumentation != null) {
518            try {
519                instrumentation.callApplicationOnCreate(app);
520            } catch (Exception e) {
521                if (!instrumentation.onException(app, e)) {
522                    throw new RuntimeException(
523                        "Unable to create application " + app.getClass().getName()
524                        + ": " + e.toString(), e);
525                }
526            }
527        }
528
529        return app;
530    }
531
532    public void removeContextRegistrations(Context context,
533            String who, String what) {
534        final boolean reportRegistrationLeaks = StrictMode.vmRegistrationLeaksEnabled();
535        HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> rmap =
536            mReceivers.remove(context);
537        if (rmap != null) {
538            Iterator<LoadedApk.ReceiverDispatcher> it = rmap.values().iterator();
539            while (it.hasNext()) {
540                LoadedApk.ReceiverDispatcher rd = it.next();
541                IntentReceiverLeaked leak = new IntentReceiverLeaked(
542                        what + " " + who + " has leaked IntentReceiver "
543                        + rd.getIntentReceiver() + " that was " +
544                        "originally registered here. Are you missing a " +
545                        "call to unregisterReceiver()?");
546                leak.setStackTrace(rd.getLocation().getStackTrace());
547                Slog.e(ActivityThread.TAG, leak.getMessage(), leak);
548                if (reportRegistrationLeaks) {
549                    StrictMode.onIntentReceiverLeaked(leak);
550                }
551                try {
552                    ActivityManagerNative.getDefault().unregisterReceiver(
553                            rd.getIIntentReceiver());
554                } catch (RemoteException e) {
555                    // system crashed, nothing we can do
556                }
557            }
558        }
559        mUnregisteredReceivers.remove(context);
560        //Slog.i(TAG, "Receiver registrations: " + mReceivers);
561        HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> smap =
562            mServices.remove(context);
563        if (smap != null) {
564            Iterator<LoadedApk.ServiceDispatcher> it = smap.values().iterator();
565            while (it.hasNext()) {
566                LoadedApk.ServiceDispatcher sd = it.next();
567                ServiceConnectionLeaked leak = new ServiceConnectionLeaked(
568                        what + " " + who + " has leaked ServiceConnection "
569                        + sd.getServiceConnection() + " that was originally bound here");
570                leak.setStackTrace(sd.getLocation().getStackTrace());
571                Slog.e(ActivityThread.TAG, leak.getMessage(), leak);
572                if (reportRegistrationLeaks) {
573                    StrictMode.onServiceConnectionLeaked(leak);
574                }
575                try {
576                    ActivityManagerNative.getDefault().unbindService(
577                            sd.getIServiceConnection());
578                } catch (RemoteException e) {
579                    // system crashed, nothing we can do
580                }
581                sd.doForget();
582            }
583        }
584        mUnboundServices.remove(context);
585        //Slog.i(TAG, "Service registrations: " + mServices);
586    }
587
588    public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
589            Context context, Handler handler,
590            Instrumentation instrumentation, boolean registered) {
591        synchronized (mReceivers) {
592            LoadedApk.ReceiverDispatcher rd = null;
593            HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
594            if (registered) {
595                map = mReceivers.get(context);
596                if (map != null) {
597                    rd = map.get(r);
598                }
599            }
600            if (rd == null) {
601                rd = new ReceiverDispatcher(r, context, handler,
602                        instrumentation, registered);
603                if (registered) {
604                    if (map == null) {
605                        map = new HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
606                        mReceivers.put(context, map);
607                    }
608                    map.put(r, rd);
609                }
610            } else {
611                rd.validate(context, handler);
612            }
613            rd.mForgotten = false;
614            return rd.getIIntentReceiver();
615        }
616    }
617
618    public IIntentReceiver forgetReceiverDispatcher(Context context,
619            BroadcastReceiver r) {
620        synchronized (mReceivers) {
621            HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = mReceivers.get(context);
622            LoadedApk.ReceiverDispatcher rd = null;
623            if (map != null) {
624                rd = map.get(r);
625                if (rd != null) {
626                    map.remove(r);
627                    if (map.size() == 0) {
628                        mReceivers.remove(context);
629                    }
630                    if (r.getDebugUnregister()) {
631                        HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder
632                                = mUnregisteredReceivers.get(context);
633                        if (holder == null) {
634                            holder = new HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
635                            mUnregisteredReceivers.put(context, holder);
636                        }
637                        RuntimeException ex = new IllegalArgumentException(
638                                "Originally unregistered here:");
639                        ex.fillInStackTrace();
640                        rd.setUnregisterLocation(ex);
641                        holder.put(r, rd);
642                    }
643                    rd.mForgotten = true;
644                    return rd.getIIntentReceiver();
645                }
646            }
647            HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder
648                    = mUnregisteredReceivers.get(context);
649            if (holder != null) {
650                rd = holder.get(r);
651                if (rd != null) {
652                    RuntimeException ex = rd.getUnregisterLocation();
653                    throw new IllegalArgumentException(
654                            "Unregistering Receiver " + r
655                            + " that was already unregistered", ex);
656                }
657            }
658            if (context == null) {
659                throw new IllegalStateException("Unbinding Receiver " + r
660                        + " from Context that is no longer in use: " + context);
661            } else {
662                throw new IllegalArgumentException("Receiver not registered: " + r);
663            }
664
665        }
666    }
667
668    static final class ReceiverDispatcher {
669
670        final static class InnerReceiver extends IIntentReceiver.Stub {
671            final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
672            final LoadedApk.ReceiverDispatcher mStrongRef;
673
674            InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
675                mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
676                mStrongRef = strong ? rd : null;
677            }
678            public void performReceive(Intent intent, int resultCode, String data,
679                    Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
680                LoadedApk.ReceiverDispatcher rd = mDispatcher.get();
681                if (ActivityThread.DEBUG_BROADCAST) {
682                    int seq = intent.getIntExtra("seq", -1);
683                    Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction() + " seq=" + seq
684                            + " to " + (rd != null ? rd.mReceiver : null));
685                }
686                if (rd != null) {
687                    rd.performReceive(intent, resultCode, data, extras,
688                            ordered, sticky, sendingUser);
689                } else {
690                    // The activity manager dispatched a broadcast to a registered
691                    // receiver in this process, but before it could be delivered the
692                    // receiver was unregistered.  Acknowledge the broadcast on its
693                    // behalf so that the system's broadcast sequence can continue.
694                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
695                            "Finishing broadcast to unregistered receiver");
696                    IActivityManager mgr = ActivityManagerNative.getDefault();
697                    try {
698                        if (extras != null) {
699                            extras.setAllowFds(false);
700                        }
701                        mgr.finishReceiver(this, resultCode, data, extras, false);
702                    } catch (RemoteException e) {
703                        Slog.w(ActivityThread.TAG, "Couldn't finish broadcast to unregistered receiver");
704                    }
705                }
706            }
707        }
708
709        final IIntentReceiver.Stub mIIntentReceiver;
710        final BroadcastReceiver mReceiver;
711        final Context mContext;
712        final Handler mActivityThread;
713        final Instrumentation mInstrumentation;
714        final boolean mRegistered;
715        final IntentReceiverLeaked mLocation;
716        RuntimeException mUnregisterLocation;
717        boolean mForgotten;
718
719        final class Args extends BroadcastReceiver.PendingResult implements Runnable {
720            private Intent mCurIntent;
721            private final boolean mOrdered;
722
723            public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
724                    boolean ordered, boolean sticky, int sendingUser) {
725                super(resultCode, resultData, resultExtras,
726                        mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED,
727                        ordered, sticky, mIIntentReceiver.asBinder(), sendingUser);
728                mCurIntent = intent;
729                mOrdered = ordered;
730            }
731
732            public void run() {
733                final BroadcastReceiver receiver = mReceiver;
734                final boolean ordered = mOrdered;
735
736                if (ActivityThread.DEBUG_BROADCAST) {
737                    int seq = mCurIntent.getIntExtra("seq", -1);
738                    Slog.i(ActivityThread.TAG, "Dispatching broadcast " + mCurIntent.getAction()
739                            + " seq=" + seq + " to " + mReceiver);
740                    Slog.i(ActivityThread.TAG, "  mRegistered=" + mRegistered
741                            + " mOrderedHint=" + ordered);
742                }
743
744                final IActivityManager mgr = ActivityManagerNative.getDefault();
745                final Intent intent = mCurIntent;
746                mCurIntent = null;
747
748                if (receiver == null || mForgotten) {
749                    if (mRegistered && ordered) {
750                        if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
751                                "Finishing null broadcast to " + mReceiver);
752                        sendFinished(mgr);
753                    }
754                    return;
755                }
756
757                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg");
758                try {
759                    ClassLoader cl =  mReceiver.getClass().getClassLoader();
760                    intent.setExtrasClassLoader(cl);
761                    setExtrasClassLoader(cl);
762                    receiver.setPendingResult(this);
763                    receiver.onReceive(mContext, intent);
764                } catch (Exception e) {
765                    if (mRegistered && ordered) {
766                        if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
767                                "Finishing failed broadcast to " + mReceiver);
768                        sendFinished(mgr);
769                    }
770                    if (mInstrumentation == null ||
771                            !mInstrumentation.onException(mReceiver, e)) {
772                        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
773                        throw new RuntimeException(
774                            "Error receiving broadcast " + intent
775                            + " in " + mReceiver, e);
776                    }
777                }
778
779                if (receiver.getPendingResult() != null) {
780                    finish();
781                }
782                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
783            }
784        }
785
786        ReceiverDispatcher(BroadcastReceiver receiver, Context context,
787                Handler activityThread, Instrumentation instrumentation,
788                boolean registered) {
789            if (activityThread == null) {
790                throw new NullPointerException("Handler must not be null");
791            }
792
793            mIIntentReceiver = new InnerReceiver(this, !registered);
794            mReceiver = receiver;
795            mContext = context;
796            mActivityThread = activityThread;
797            mInstrumentation = instrumentation;
798            mRegistered = registered;
799            mLocation = new IntentReceiverLeaked(null);
800            mLocation.fillInStackTrace();
801        }
802
803        void validate(Context context, Handler activityThread) {
804            if (mContext != context) {
805                throw new IllegalStateException(
806                    "Receiver " + mReceiver +
807                    " registered with differing Context (was " +
808                    mContext + " now " + context + ")");
809            }
810            if (mActivityThread != activityThread) {
811                throw new IllegalStateException(
812                    "Receiver " + mReceiver +
813                    " registered with differing handler (was " +
814                    mActivityThread + " now " + activityThread + ")");
815            }
816        }
817
818        IntentReceiverLeaked getLocation() {
819            return mLocation;
820        }
821
822        BroadcastReceiver getIntentReceiver() {
823            return mReceiver;
824        }
825
826        IIntentReceiver getIIntentReceiver() {
827            return mIIntentReceiver;
828        }
829
830        void setUnregisterLocation(RuntimeException ex) {
831            mUnregisterLocation = ex;
832        }
833
834        RuntimeException getUnregisterLocation() {
835            return mUnregisterLocation;
836        }
837
838        public void performReceive(Intent intent, int resultCode, String data,
839                Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
840            if (ActivityThread.DEBUG_BROADCAST) {
841                int seq = intent.getIntExtra("seq", -1);
842                Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq
843                        + " to " + mReceiver);
844            }
845            Args args = new Args(intent, resultCode, data, extras, ordered,
846                    sticky, sendingUser);
847            if (!mActivityThread.post(args)) {
848                if (mRegistered && ordered) {
849                    IActivityManager mgr = ActivityManagerNative.getDefault();
850                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
851                            "Finishing sync broadcast to " + mReceiver);
852                    args.sendFinished(mgr);
853                }
854            }
855        }
856
857    }
858
859    public final IServiceConnection getServiceDispatcher(ServiceConnection c,
860            Context context, Handler handler, int flags) {
861        synchronized (mServices) {
862            LoadedApk.ServiceDispatcher sd = null;
863            HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
864            if (map != null) {
865                sd = map.get(c);
866            }
867            if (sd == null) {
868                sd = new ServiceDispatcher(c, context, handler, flags);
869                if (map == null) {
870                    map = new HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
871                    mServices.put(context, map);
872                }
873                map.put(c, sd);
874            } else {
875                sd.validate(context, handler);
876            }
877            return sd.getIServiceConnection();
878        }
879    }
880
881    public final IServiceConnection forgetServiceDispatcher(Context context,
882            ServiceConnection c) {
883        synchronized (mServices) {
884            HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> map
885                    = mServices.get(context);
886            LoadedApk.ServiceDispatcher sd = null;
887            if (map != null) {
888                sd = map.get(c);
889                if (sd != null) {
890                    map.remove(c);
891                    sd.doForget();
892                    if (map.size() == 0) {
893                        mServices.remove(context);
894                    }
895                    if ((sd.getFlags()&Context.BIND_DEBUG_UNBIND) != 0) {
896                        HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder
897                                = mUnboundServices.get(context);
898                        if (holder == null) {
899                            holder = new HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
900                            mUnboundServices.put(context, holder);
901                        }
902                        RuntimeException ex = new IllegalArgumentException(
903                                "Originally unbound here:");
904                        ex.fillInStackTrace();
905                        sd.setUnbindLocation(ex);
906                        holder.put(c, sd);
907                    }
908                    return sd.getIServiceConnection();
909                }
910            }
911            HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder
912                    = mUnboundServices.get(context);
913            if (holder != null) {
914                sd = holder.get(c);
915                if (sd != null) {
916                    RuntimeException ex = sd.getUnbindLocation();
917                    throw new IllegalArgumentException(
918                            "Unbinding Service " + c
919                            + " that was already unbound", ex);
920                }
921            }
922            if (context == null) {
923                throw new IllegalStateException("Unbinding Service " + c
924                        + " from Context that is no longer in use: " + context);
925            } else {
926                throw new IllegalArgumentException("Service not registered: " + c);
927            }
928        }
929    }
930
931    static final class ServiceDispatcher {
932        private final ServiceDispatcher.InnerConnection mIServiceConnection;
933        private final ServiceConnection mConnection;
934        private final Context mContext;
935        private final Handler mActivityThread;
936        private final ServiceConnectionLeaked mLocation;
937        private final int mFlags;
938
939        private RuntimeException mUnbindLocation;
940
941        private boolean mDied;
942        private boolean mForgotten;
943
944        private static class ConnectionInfo {
945            IBinder binder;
946            IBinder.DeathRecipient deathMonitor;
947        }
948
949        private static class InnerConnection extends IServiceConnection.Stub {
950            final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
951
952            InnerConnection(LoadedApk.ServiceDispatcher sd) {
953                mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
954            }
955
956            public void connected(ComponentName name, IBinder service) throws RemoteException {
957                LoadedApk.ServiceDispatcher sd = mDispatcher.get();
958                if (sd != null) {
959                    sd.connected(name, service);
960                }
961            }
962        }
963
964        private final HashMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections
965            = new HashMap<ComponentName, ServiceDispatcher.ConnectionInfo>();
966
967        ServiceDispatcher(ServiceConnection conn,
968                Context context, Handler activityThread, int flags) {
969            mIServiceConnection = new InnerConnection(this);
970            mConnection = conn;
971            mContext = context;
972            mActivityThread = activityThread;
973            mLocation = new ServiceConnectionLeaked(null);
974            mLocation.fillInStackTrace();
975            mFlags = flags;
976        }
977
978        void validate(Context context, Handler activityThread) {
979            if (mContext != context) {
980                throw new RuntimeException(
981                    "ServiceConnection " + mConnection +
982                    " registered with differing Context (was " +
983                    mContext + " now " + context + ")");
984            }
985            if (mActivityThread != activityThread) {
986                throw new RuntimeException(
987                    "ServiceConnection " + mConnection +
988                    " registered with differing handler (was " +
989                    mActivityThread + " now " + activityThread + ")");
990            }
991        }
992
993        void doForget() {
994            synchronized(this) {
995                Iterator<ServiceDispatcher.ConnectionInfo> it = mActiveConnections.values().iterator();
996                while (it.hasNext()) {
997                    ServiceDispatcher.ConnectionInfo ci = it.next();
998                    ci.binder.unlinkToDeath(ci.deathMonitor, 0);
999                }
1000                mActiveConnections.clear();
1001                mForgotten = true;
1002            }
1003        }
1004
1005        ServiceConnectionLeaked getLocation() {
1006            return mLocation;
1007        }
1008
1009        ServiceConnection getServiceConnection() {
1010            return mConnection;
1011        }
1012
1013        IServiceConnection getIServiceConnection() {
1014            return mIServiceConnection;
1015        }
1016
1017        int getFlags() {
1018            return mFlags;
1019        }
1020
1021        void setUnbindLocation(RuntimeException ex) {
1022            mUnbindLocation = ex;
1023        }
1024
1025        RuntimeException getUnbindLocation() {
1026            return mUnbindLocation;
1027        }
1028
1029        public void connected(ComponentName name, IBinder service) {
1030            if (mActivityThread != null) {
1031                mActivityThread.post(new RunConnection(name, service, 0));
1032            } else {
1033                doConnected(name, service);
1034            }
1035        }
1036
1037        public void death(ComponentName name, IBinder service) {
1038            ServiceDispatcher.ConnectionInfo old;
1039
1040            synchronized (this) {
1041                mDied = true;
1042                old = mActiveConnections.remove(name);
1043                if (old == null || old.binder != service) {
1044                    // Death for someone different than who we last
1045                    // reported...  just ignore it.
1046                    return;
1047                }
1048                old.binder.unlinkToDeath(old.deathMonitor, 0);
1049            }
1050
1051            if (mActivityThread != null) {
1052                mActivityThread.post(new RunConnection(name, service, 1));
1053            } else {
1054                doDeath(name, service);
1055            }
1056        }
1057
1058        public void doConnected(ComponentName name, IBinder service) {
1059            ServiceDispatcher.ConnectionInfo old;
1060            ServiceDispatcher.ConnectionInfo info;
1061
1062            synchronized (this) {
1063                if (mForgotten) {
1064                    // We unbound before receiving the connection; ignore
1065                    // any connection received.
1066                    return;
1067                }
1068                old = mActiveConnections.get(name);
1069                if (old != null && old.binder == service) {
1070                    // Huh, already have this one.  Oh well!
1071                    return;
1072                }
1073
1074                if (service != null) {
1075                    // A new service is being connected... set it all up.
1076                    mDied = false;
1077                    info = new ConnectionInfo();
1078                    info.binder = service;
1079                    info.deathMonitor = new DeathMonitor(name, service);
1080                    try {
1081                        service.linkToDeath(info.deathMonitor, 0);
1082                        mActiveConnections.put(name, info);
1083                    } catch (RemoteException e) {
1084                        // This service was dead before we got it...  just
1085                        // don't do anything with it.
1086                        mActiveConnections.remove(name);
1087                        return;
1088                    }
1089
1090                } else {
1091                    // The named service is being disconnected... clean up.
1092                    mActiveConnections.remove(name);
1093                }
1094
1095                if (old != null) {
1096                    old.binder.unlinkToDeath(old.deathMonitor, 0);
1097                }
1098            }
1099
1100            // If there was an old service, it is not disconnected.
1101            if (old != null) {
1102                mConnection.onServiceDisconnected(name);
1103            }
1104            // If there is a new service, it is now connected.
1105            if (service != null) {
1106                mConnection.onServiceConnected(name, service);
1107            }
1108        }
1109
1110        public void doDeath(ComponentName name, IBinder service) {
1111            mConnection.onServiceDisconnected(name);
1112        }
1113
1114        private final class RunConnection implements Runnable {
1115            RunConnection(ComponentName name, IBinder service, int command) {
1116                mName = name;
1117                mService = service;
1118                mCommand = command;
1119            }
1120
1121            public void run() {
1122                if (mCommand == 0) {
1123                    doConnected(mName, mService);
1124                } else if (mCommand == 1) {
1125                    doDeath(mName, mService);
1126                }
1127            }
1128
1129            final ComponentName mName;
1130            final IBinder mService;
1131            final int mCommand;
1132        }
1133
1134        private final class DeathMonitor implements IBinder.DeathRecipient
1135        {
1136            DeathMonitor(ComponentName name, IBinder service) {
1137                mName = name;
1138                mService = service;
1139            }
1140
1141            public void binderDied() {
1142                death(mName, mService);
1143            }
1144
1145            final ComponentName mName;
1146            final IBinder mService;
1147        }
1148    }
1149}
1150