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