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