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