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