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