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