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