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