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