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 AssertionError(e);
    366         }
    367         /*
    368          * Two possible indications that this package could be
    369          * sharing its virtual machine with other packages:
    370          *
    371          * 1.) the sharedUserId attribute is set in the manifest,
    372          *     indicating a request to share a VM with other
    373          *     packages with the same sharedUserId.
    374          *
    375          * 2.) the application element of the manifest has an
    376          *     attribute specifying a non-default process name,
    377          *     indicating the desire to run in another packages VM.
    378          */
    379         boolean sharedUserIdSet = (pi.sharedUserId != null);
    380         boolean processNameNotDefault =
    381             (pi.applicationInfo != null &&
    382              !mPackageName.equals(pi.applicationInfo.processName));
    383         boolean sharable = (sharedUserIdSet || processNameNotDefault);
    384         ClassLoader contextClassLoader =
    385             (sharable)
    386             ? new WarningContextClassLoader()
    387             : mClassLoader;
    388         Thread.currentThread().setContextClassLoader(contextClassLoader);
    389     }
    390 
    391     private static class WarningContextClassLoader extends ClassLoader {
    392 
    393         private static boolean warned = false;
    394 
    395         private void warn(String methodName) {
    396             if (warned) {
    397                 return;
    398             }
    399             warned = true;
    400             Thread.currentThread().setContextClassLoader(getParent());
    401             Slog.w(ActivityThread.TAG, "ClassLoader." + methodName + ": " +
    402                   "The class loader returned by " +
    403                   "Thread.getContextClassLoader() may fail for processes " +
    404                   "that host multiple applications. You should explicitly " +
    405                   "specify a context class loader. For example: " +
    406                   "Thread.setContextClassLoader(getClass().getClassLoader());");
    407         }
    408 
    409         @Override public URL getResource(String resName) {
    410             warn("getResource");
    411             return getParent().getResource(resName);
    412         }
    413 
    414         @Override public Enumeration<URL> getResources(String resName) throws IOException {
    415             warn("getResources");
    416             return getParent().getResources(resName);
    417         }
    418 
    419         @Override public InputStream getResourceAsStream(String resName) {
    420             warn("getResourceAsStream");
    421             return getParent().getResourceAsStream(resName);
    422         }
    423 
    424         @Override public Class<?> loadClass(String className) throws ClassNotFoundException {
    425             warn("loadClass");
    426             return getParent().loadClass(className);
    427         }
    428 
    429         @Override public void setClassAssertionStatus(String cname, boolean enable) {
    430             warn("setClassAssertionStatus");
    431             getParent().setClassAssertionStatus(cname, enable);
    432         }
    433 
    434         @Override public void setPackageAssertionStatus(String pname, boolean enable) {
    435             warn("setPackageAssertionStatus");
    436             getParent().setPackageAssertionStatus(pname, enable);
    437         }
    438 
    439         @Override public void setDefaultAssertionStatus(boolean enable) {
    440             warn("setDefaultAssertionStatus");
    441             getParent().setDefaultAssertionStatus(enable);
    442         }
    443 
    444         @Override public void clearAssertionStatus() {
    445             warn("clearAssertionStatus");
    446             getParent().clearAssertionStatus();
    447         }
    448     }
    449 
    450     public String getAppDir() {
    451         return mAppDir;
    452     }
    453 
    454     public String getLibDir() {
    455         return mLibDir;
    456     }
    457 
    458     public String getResDir() {
    459         return mResDir;
    460     }
    461 
    462     public String getDataDir() {
    463         return mDataDir;
    464     }
    465 
    466     public File getDataDirFile() {
    467         return mDataDirFile;
    468     }
    469 
    470     public AssetManager getAssets(ActivityThread mainThread) {
    471         return getResources(mainThread).getAssets();
    472     }
    473 
    474     public Resources getResources(ActivityThread mainThread) {
    475         if (mResources == null) {
    476             mResources = mainThread.getTopLevelResources(mResDir,
    477                     Display.DEFAULT_DISPLAY, null, this);
    478         }
    479         return mResources;
    480     }
    481 
    482     public Application makeApplication(boolean forceDefaultAppClass,
    483             Instrumentation instrumentation) {
    484         if (mApplication != null) {
    485             return mApplication;
    486         }
    487 
    488         Application app = null;
    489 
    490         String appClass = mApplicationInfo.className;
    491         if (forceDefaultAppClass || (appClass == null)) {
    492             appClass = "android.app.Application";
    493         }
    494 
    495         try {
    496             java.lang.ClassLoader cl = getClassLoader();
    497             ContextImpl appContext = new ContextImpl();
    498             appContext.init(this, null, mActivityThread);
    499             app = mActivityThread.mInstrumentation.newApplication(
    500                     cl, appClass, appContext);
    501             appContext.setOuterContext(app);
    502         } catch (Exception e) {
    503             if (!mActivityThread.mInstrumentation.onException(app, e)) {
    504                 throw new RuntimeException(
    505                     "Unable to instantiate application " + appClass
    506                     + ": " + e.toString(), e);
    507             }
    508         }
    509         mActivityThread.mAllApplications.add(app);
    510         mApplication = app;
    511 
    512         if (instrumentation != null) {
    513             try {
    514                 instrumentation.callApplicationOnCreate(app);
    515             } catch (Exception e) {
    516                 if (!instrumentation.onException(app, e)) {
    517                     throw new RuntimeException(
    518                         "Unable to create application " + app.getClass().getName()
    519                         + ": " + e.toString(), e);
    520                 }
    521             }
    522         }
    523 
    524         return app;
    525     }
    526 
    527     public void removeContextRegistrations(Context context,
    528             String who, String what) {
    529         final boolean reportRegistrationLeaks = StrictMode.vmRegistrationLeaksEnabled();
    530         HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> rmap =
    531             mReceivers.remove(context);
    532         if (rmap != null) {
    533             Iterator<LoadedApk.ReceiverDispatcher> it = rmap.values().iterator();
    534             while (it.hasNext()) {
    535                 LoadedApk.ReceiverDispatcher rd = it.next();
    536                 IntentReceiverLeaked leak = new IntentReceiverLeaked(
    537                         what + " " + who + " has leaked IntentReceiver "
    538                         + rd.getIntentReceiver() + " that was " +
    539                         "originally registered here. Are you missing a " +
    540                         "call to unregisterReceiver()?");
    541                 leak.setStackTrace(rd.getLocation().getStackTrace());
    542                 Slog.e(ActivityThread.TAG, leak.getMessage(), leak);
    543                 if (reportRegistrationLeaks) {
    544                     StrictMode.onIntentReceiverLeaked(leak);
    545                 }
    546                 try {
    547                     ActivityManagerNative.getDefault().unregisterReceiver(
    548                             rd.getIIntentReceiver());
    549                 } catch (RemoteException e) {
    550                     // system crashed, nothing we can do
    551                 }
    552             }
    553         }
    554         mUnregisteredReceivers.remove(context);
    555         //Slog.i(TAG, "Receiver registrations: " + mReceivers);
    556         HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> smap =
    557             mServices.remove(context);
    558         if (smap != null) {
    559             Iterator<LoadedApk.ServiceDispatcher> it = smap.values().iterator();
    560             while (it.hasNext()) {
    561                 LoadedApk.ServiceDispatcher sd = it.next();
    562                 ServiceConnectionLeaked leak = new ServiceConnectionLeaked(
    563                         what + " " + who + " has leaked ServiceConnection "
    564                         + sd.getServiceConnection() + " that was originally bound here");
    565                 leak.setStackTrace(sd.getLocation().getStackTrace());
    566                 Slog.e(ActivityThread.TAG, leak.getMessage(), leak);
    567                 if (reportRegistrationLeaks) {
    568                     StrictMode.onServiceConnectionLeaked(leak);
    569                 }
    570                 try {
    571                     ActivityManagerNative.getDefault().unbindService(
    572                             sd.getIServiceConnection());
    573                 } catch (RemoteException e) {
    574                     // system crashed, nothing we can do
    575                 }
    576                 sd.doForget();
    577             }
    578         }
    579         mUnboundServices.remove(context);
    580         //Slog.i(TAG, "Service registrations: " + mServices);
    581     }
    582 
    583     public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
    584             Context context, Handler handler,
    585             Instrumentation instrumentation, boolean registered) {
    586         synchronized (mReceivers) {
    587             LoadedApk.ReceiverDispatcher rd = null;
    588             HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
    589             if (registered) {
    590                 map = mReceivers.get(context);
    591                 if (map != null) {
    592                     rd = map.get(r);
    593                 }
    594             }
    595             if (rd == null) {
    596                 rd = new ReceiverDispatcher(r, context, handler,
    597                         instrumentation, registered);
    598                 if (registered) {
    599                     if (map == null) {
    600                         map = new HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
    601                         mReceivers.put(context, map);
    602                     }
    603                     map.put(r, rd);
    604                 }
    605             } else {
    606                 rd.validate(context, handler);
    607             }
    608             rd.mForgotten = false;
    609             return rd.getIIntentReceiver();
    610         }
    611     }
    612 
    613     public IIntentReceiver forgetReceiverDispatcher(Context context,
    614             BroadcastReceiver r) {
    615         synchronized (mReceivers) {
    616             HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = mReceivers.get(context);
    617             LoadedApk.ReceiverDispatcher rd = null;
    618             if (map != null) {
    619                 rd = map.get(r);
    620                 if (rd != null) {
    621                     map.remove(r);
    622                     if (map.size() == 0) {
    623                         mReceivers.remove(context);
    624                     }
    625                     if (r.getDebugUnregister()) {
    626                         HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder
    627                                 = mUnregisteredReceivers.get(context);
    628                         if (holder == null) {
    629                             holder = new HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
    630                             mUnregisteredReceivers.put(context, holder);
    631                         }
    632                         RuntimeException ex = new IllegalArgumentException(
    633                                 "Originally unregistered here:");
    634                         ex.fillInStackTrace();
    635                         rd.setUnregisterLocation(ex);
    636                         holder.put(r, rd);
    637                     }
    638                     rd.mForgotten = true;
    639                     return rd.getIIntentReceiver();
    640                 }
    641             }
    642             HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder
    643                     = mUnregisteredReceivers.get(context);
    644             if (holder != null) {
    645                 rd = holder.get(r);
    646                 if (rd != null) {
    647                     RuntimeException ex = rd.getUnregisterLocation();
    648                     throw new IllegalArgumentException(
    649                             "Unregistering Receiver " + r
    650                             + " that was already unregistered", ex);
    651                 }
    652             }
    653             if (context == null) {
    654                 throw new IllegalStateException("Unbinding Receiver " + r
    655                         + " from Context that is no longer in use: " + context);
    656             } else {
    657                 throw new IllegalArgumentException("Receiver not registered: " + r);
    658             }
    659 
    660         }
    661     }
    662 
    663     static final class ReceiverDispatcher {
    664 
    665         final static class InnerReceiver extends IIntentReceiver.Stub {
    666             final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
    667             final LoadedApk.ReceiverDispatcher mStrongRef;
    668 
    669             InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
    670                 mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
    671                 mStrongRef = strong ? rd : null;
    672             }
    673             public void performReceive(Intent intent, int resultCode, String data,
    674                     Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
    675                 LoadedApk.ReceiverDispatcher rd = mDispatcher.get();
    676                 if (ActivityThread.DEBUG_BROADCAST) {
    677                     int seq = intent.getIntExtra("seq", -1);
    678                     Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction() + " seq=" + seq
    679                             + " to " + (rd != null ? rd.mReceiver : null));
    680                 }
    681                 if (rd != null) {
    682                     rd.performReceive(intent, resultCode, data, extras,
    683                             ordered, sticky, sendingUser);
    684                 } else {
    685                     // The activity manager dispatched a broadcast to a registered
    686                     // receiver in this process, but before it could be delivered the
    687                     // receiver was unregistered.  Acknowledge the broadcast on its
    688                     // behalf so that the system's broadcast sequence can continue.
    689                     if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
    690                             "Finishing broadcast to unregistered receiver");
    691                     IActivityManager mgr = ActivityManagerNative.getDefault();
    692                     try {
    693                         if (extras != null) {
    694                             extras.setAllowFds(false);
    695                         }
    696                         mgr.finishReceiver(this, resultCode, data, extras, false);
    697                     } catch (RemoteException e) {
    698                         Slog.w(ActivityThread.TAG, "Couldn't finish broadcast to unregistered receiver");
    699                     }
    700                 }
    701             }
    702         }
    703 
    704         final IIntentReceiver.Stub mIIntentReceiver;
    705         final BroadcastReceiver mReceiver;
    706         final Context mContext;
    707         final Handler mActivityThread;
    708         final Instrumentation mInstrumentation;
    709         final boolean mRegistered;
    710         final IntentReceiverLeaked mLocation;
    711         RuntimeException mUnregisterLocation;
    712         boolean mForgotten;
    713 
    714         final class Args extends BroadcastReceiver.PendingResult implements Runnable {
    715             private Intent mCurIntent;
    716             private final boolean mOrdered;
    717 
    718             public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
    719                     boolean ordered, boolean sticky, int sendingUser) {
    720                 super(resultCode, resultData, resultExtras,
    721                         mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED,
    722                         ordered, sticky, mIIntentReceiver.asBinder(), sendingUser);
    723                 mCurIntent = intent;
    724                 mOrdered = ordered;
    725             }
    726 
    727             public void run() {
    728                 final BroadcastReceiver receiver = mReceiver;
    729                 final boolean ordered = mOrdered;
    730 
    731                 if (ActivityThread.DEBUG_BROADCAST) {
    732                     int seq = mCurIntent.getIntExtra("seq", -1);
    733                     Slog.i(ActivityThread.TAG, "Dispatching broadcast " + mCurIntent.getAction()
    734                             + " seq=" + seq + " to " + mReceiver);
    735                     Slog.i(ActivityThread.TAG, "  mRegistered=" + mRegistered
    736                             + " mOrderedHint=" + ordered);
    737                 }
    738 
    739                 final IActivityManager mgr = ActivityManagerNative.getDefault();
    740                 final Intent intent = mCurIntent;
    741                 mCurIntent = null;
    742 
    743                 if (receiver == null || mForgotten) {
    744                     if (mRegistered && ordered) {
    745                         if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
    746                                 "Finishing null broadcast to " + mReceiver);
    747                         sendFinished(mgr);
    748                     }
    749                     return;
    750                 }
    751 
    752                 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg");
    753                 try {
    754                     ClassLoader cl =  mReceiver.getClass().getClassLoader();
    755                     intent.setExtrasClassLoader(cl);
    756                     setExtrasClassLoader(cl);
    757                     receiver.setPendingResult(this);
    758                     receiver.onReceive(mContext, intent);
    759                 } catch (Exception e) {
    760                     if (mRegistered && ordered) {
    761                         if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
    762                                 "Finishing failed broadcast to " + mReceiver);
    763                         sendFinished(mgr);
    764                     }
    765                     if (mInstrumentation == null ||
    766                             !mInstrumentation.onException(mReceiver, e)) {
    767                         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    768                         throw new RuntimeException(
    769                             "Error receiving broadcast " + intent
    770                             + " in " + mReceiver, e);
    771                     }
    772                 }
    773 
    774                 if (receiver.getPendingResult() != null) {
    775                     finish();
    776                 }
    777                 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    778             }
    779         }
    780 
    781         ReceiverDispatcher(BroadcastReceiver receiver, Context context,
    782                 Handler activityThread, Instrumentation instrumentation,
    783                 boolean registered) {
    784             if (activityThread == null) {
    785                 throw new NullPointerException("Handler must not be null");
    786             }
    787 
    788             mIIntentReceiver = new InnerReceiver(this, !registered);
    789             mReceiver = receiver;
    790             mContext = context;
    791             mActivityThread = activityThread;
    792             mInstrumentation = instrumentation;
    793             mRegistered = registered;
    794             mLocation = new IntentReceiverLeaked(null);
    795             mLocation.fillInStackTrace();
    796         }
    797 
    798         void validate(Context context, Handler activityThread) {
    799             if (mContext != context) {
    800                 throw new IllegalStateException(
    801                     "Receiver " + mReceiver +
    802                     " registered with differing Context (was " +
    803                     mContext + " now " + context + ")");
    804             }
    805             if (mActivityThread != activityThread) {
    806                 throw new IllegalStateException(
    807                     "Receiver " + mReceiver +
    808                     " registered with differing handler (was " +
    809                     mActivityThread + " now " + activityThread + ")");
    810             }
    811         }
    812 
    813         IntentReceiverLeaked getLocation() {
    814             return mLocation;
    815         }
    816 
    817         BroadcastReceiver getIntentReceiver() {
    818             return mReceiver;
    819         }
    820 
    821         IIntentReceiver getIIntentReceiver() {
    822             return mIIntentReceiver;
    823         }
    824 
    825         void setUnregisterLocation(RuntimeException ex) {
    826             mUnregisterLocation = ex;
    827         }
    828 
    829         RuntimeException getUnregisterLocation() {
    830             return mUnregisterLocation;
    831         }
    832 
    833         public void performReceive(Intent intent, int resultCode, String data,
    834                 Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
    835             if (ActivityThread.DEBUG_BROADCAST) {
    836                 int seq = intent.getIntExtra("seq", -1);
    837                 Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq
    838                         + " to " + mReceiver);
    839             }
    840             Args args = new Args(intent, resultCode, data, extras, ordered,
    841                     sticky, sendingUser);
    842             if (!mActivityThread.post(args)) {
    843                 if (mRegistered && ordered) {
    844                     IActivityManager mgr = ActivityManagerNative.getDefault();
    845                     if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
    846                             "Finishing sync broadcast to " + mReceiver);
    847                     args.sendFinished(mgr);
    848                 }
    849             }
    850         }
    851 
    852     }
    853 
    854     public final IServiceConnection getServiceDispatcher(ServiceConnection c,
    855             Context context, Handler handler, int flags) {
    856         synchronized (mServices) {
    857             LoadedApk.ServiceDispatcher sd = null;
    858             HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
    859             if (map != null) {
    860                 sd = map.get(c);
    861             }
    862             if (sd == null) {
    863                 sd = new ServiceDispatcher(c, context, handler, flags);
    864                 if (map == null) {
    865                     map = new HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
    866                     mServices.put(context, map);
    867                 }
    868                 map.put(c, sd);
    869             } else {
    870                 sd.validate(context, handler);
    871             }
    872             return sd.getIServiceConnection();
    873         }
    874     }
    875 
    876     public final IServiceConnection forgetServiceDispatcher(Context context,
    877             ServiceConnection c) {
    878         synchronized (mServices) {
    879             HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> map
    880                     = mServices.get(context);
    881             LoadedApk.ServiceDispatcher sd = null;
    882             if (map != null) {
    883                 sd = map.get(c);
    884                 if (sd != null) {
    885                     map.remove(c);
    886                     sd.doForget();
    887                     if (map.size() == 0) {
    888                         mServices.remove(context);
    889                     }
    890                     if ((sd.getFlags()&Context.BIND_DEBUG_UNBIND) != 0) {
    891                         HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder
    892                                 = mUnboundServices.get(context);
    893                         if (holder == null) {
    894                             holder = new HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
    895                             mUnboundServices.put(context, holder);
    896                         }
    897                         RuntimeException ex = new IllegalArgumentException(
    898                                 "Originally unbound here:");
    899                         ex.fillInStackTrace();
    900                         sd.setUnbindLocation(ex);
    901                         holder.put(c, sd);
    902                     }
    903                     return sd.getIServiceConnection();
    904                 }
    905             }
    906             HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder
    907                     = mUnboundServices.get(context);
    908             if (holder != null) {
    909                 sd = holder.get(c);
    910                 if (sd != null) {
    911                     RuntimeException ex = sd.getUnbindLocation();
    912                     throw new IllegalArgumentException(
    913                             "Unbinding Service " + c
    914                             + " that was already unbound", ex);
    915                 }
    916             }
    917             if (context == null) {
    918                 throw new IllegalStateException("Unbinding Service " + c
    919                         + " from Context that is no longer in use: " + context);
    920             } else {
    921                 throw new IllegalArgumentException("Service not registered: " + c);
    922             }
    923         }
    924     }
    925 
    926     static final class ServiceDispatcher {
    927         private final ServiceDispatcher.InnerConnection mIServiceConnection;
    928         private final ServiceConnection mConnection;
    929         private final Context mContext;
    930         private final Handler mActivityThread;
    931         private final ServiceConnectionLeaked mLocation;
    932         private final int mFlags;
    933 
    934         private RuntimeException mUnbindLocation;
    935 
    936         private boolean mDied;
    937         private boolean mForgotten;
    938 
    939         private static class ConnectionInfo {
    940             IBinder binder;
    941             IBinder.DeathRecipient deathMonitor;
    942         }
    943 
    944         private static class InnerConnection extends IServiceConnection.Stub {
    945             final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
    946 
    947             InnerConnection(LoadedApk.ServiceDispatcher sd) {
    948                 mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
    949             }
    950 
    951             public void connected(ComponentName name, IBinder service) throws RemoteException {
    952                 LoadedApk.ServiceDispatcher sd = mDispatcher.get();
    953                 if (sd != null) {
    954                     sd.connected(name, service);
    955                 }
    956             }
    957         }
    958 
    959         private final HashMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections
    960             = new HashMap<ComponentName, ServiceDispatcher.ConnectionInfo>();
    961 
    962         ServiceDispatcher(ServiceConnection conn,
    963                 Context context, Handler activityThread, int flags) {
    964             mIServiceConnection = new InnerConnection(this);
    965             mConnection = conn;
    966             mContext = context;
    967             mActivityThread = activityThread;
    968             mLocation = new ServiceConnectionLeaked(null);
    969             mLocation.fillInStackTrace();
    970             mFlags = flags;
    971         }
    972 
    973         void validate(Context context, Handler activityThread) {
    974             if (mContext != context) {
    975                 throw new RuntimeException(
    976                     "ServiceConnection " + mConnection +
    977                     " registered with differing Context (was " +
    978                     mContext + " now " + context + ")");
    979             }
    980             if (mActivityThread != activityThread) {
    981                 throw new RuntimeException(
    982                     "ServiceConnection " + mConnection +
    983                     " registered with differing handler (was " +
    984                     mActivityThread + " now " + activityThread + ")");
    985             }
    986         }
    987 
    988         void doForget() {
    989             synchronized(this) {
    990                 Iterator<ServiceDispatcher.ConnectionInfo> it = mActiveConnections.values().iterator();
    991                 while (it.hasNext()) {
    992                     ServiceDispatcher.ConnectionInfo ci = it.next();
    993                     ci.binder.unlinkToDeath(ci.deathMonitor, 0);
    994                 }
    995                 mActiveConnections.clear();
    996                 mForgotten = true;
    997             }
    998         }
    999 
   1000         ServiceConnectionLeaked getLocation() {
   1001             return mLocation;
   1002         }
   1003 
   1004         ServiceConnection getServiceConnection() {
   1005             return mConnection;
   1006         }
   1007 
   1008         IServiceConnection getIServiceConnection() {
   1009             return mIServiceConnection;
   1010         }
   1011 
   1012         int getFlags() {
   1013             return mFlags;
   1014         }
   1015 
   1016         void setUnbindLocation(RuntimeException ex) {
   1017             mUnbindLocation = ex;
   1018         }
   1019 
   1020         RuntimeException getUnbindLocation() {
   1021             return mUnbindLocation;
   1022         }
   1023 
   1024         public void connected(ComponentName name, IBinder service) {
   1025             if (mActivityThread != null) {
   1026                 mActivityThread.post(new RunConnection(name, service, 0));
   1027             } else {
   1028                 doConnected(name, service);
   1029             }
   1030         }
   1031 
   1032         public void death(ComponentName name, IBinder service) {
   1033             ServiceDispatcher.ConnectionInfo old;
   1034 
   1035             synchronized (this) {
   1036                 mDied = true;
   1037                 old = mActiveConnections.remove(name);
   1038                 if (old == null || old.binder != service) {
   1039                     // Death for someone different than who we last
   1040                     // reported...  just ignore it.
   1041                     return;
   1042                 }
   1043                 old.binder.unlinkToDeath(old.deathMonitor, 0);
   1044             }
   1045 
   1046             if (mActivityThread != null) {
   1047                 mActivityThread.post(new RunConnection(name, service, 1));
   1048             } else {
   1049                 doDeath(name, service);
   1050             }
   1051         }
   1052 
   1053         public void doConnected(ComponentName name, IBinder service) {
   1054             ServiceDispatcher.ConnectionInfo old;
   1055             ServiceDispatcher.ConnectionInfo info;
   1056 
   1057             synchronized (this) {
   1058                 if (mForgotten) {
   1059                     // We unbound before receiving the connection; ignore
   1060                     // any connection received.
   1061                     return;
   1062                 }
   1063                 old = mActiveConnections.get(name);
   1064                 if (old != null && old.binder == service) {
   1065                     // Huh, already have this one.  Oh well!
   1066                     return;
   1067                 }
   1068 
   1069                 if (service != null) {
   1070                     // A new service is being connected... set it all up.
   1071                     mDied = false;
   1072                     info = new ConnectionInfo();
   1073                     info.binder = service;
   1074                     info.deathMonitor = new DeathMonitor(name, service);
   1075                     try {
   1076                         service.linkToDeath(info.deathMonitor, 0);
   1077                         mActiveConnections.put(name, info);
   1078                     } catch (RemoteException e) {
   1079                         // This service was dead before we got it...  just
   1080                         // don't do anything with it.
   1081                         mActiveConnections.remove(name);
   1082                         return;
   1083                     }
   1084 
   1085                 } else {
   1086                     // The named service is being disconnected... clean up.
   1087                     mActiveConnections.remove(name);
   1088                 }
   1089 
   1090                 if (old != null) {
   1091                     old.binder.unlinkToDeath(old.deathMonitor, 0);
   1092                 }
   1093             }
   1094 
   1095             // If there was an old service, it is not disconnected.
   1096             if (old != null) {
   1097                 mConnection.onServiceDisconnected(name);
   1098             }
   1099             // If there is a new service, it is now connected.
   1100             if (service != null) {
   1101                 mConnection.onServiceConnected(name, service);
   1102             }
   1103         }
   1104 
   1105         public void doDeath(ComponentName name, IBinder service) {
   1106             mConnection.onServiceDisconnected(name);
   1107         }
   1108 
   1109         private final class RunConnection implements Runnable {
   1110             RunConnection(ComponentName name, IBinder service, int command) {
   1111                 mName = name;
   1112                 mService = service;
   1113                 mCommand = command;
   1114             }
   1115 
   1116             public void run() {
   1117                 if (mCommand == 0) {
   1118                     doConnected(mName, mService);
   1119                 } else if (mCommand == 1) {
   1120                     doDeath(mName, mService);
   1121                 }
   1122             }
   1123 
   1124             final ComponentName mName;
   1125             final IBinder mService;
   1126             final int mCommand;
   1127         }
   1128 
   1129         private final class DeathMonitor implements IBinder.DeathRecipient
   1130         {
   1131             DeathMonitor(ComponentName name, IBinder service) {
   1132                 mName = name;
   1133                 mService = service;
   1134             }
   1135 
   1136             public void binderDied() {
   1137                 death(mName, mService);
   1138             }
   1139 
   1140             final ComponentName mName;
   1141             final IBinder mService;
   1142         }
   1143     }
   1144 }
   1145