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