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