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