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