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