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