2 * Copyright (C) 2010 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 import android.text.TextUtils;
20 import android.util.ArrayMap;
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.FileUtils;
35 import android.os.Handler;
36 import android.os.IBinder;
37 import android.os.Process;
38 import android.os.RemoteException;
39 import android.os.StrictMode;
40 import android.os.Trace;
41 import android.os.UserHandle;
42 import android.util.AndroidRuntimeException;
43 import android.util.Log;
44 import android.util.Slog;
45 import android.util.SparseArray;
46 import android.view.DisplayAdjustments;
47 import android.view.Display;
48 import android.os.SystemProperties;
50 import dalvik.system.VMRuntime;
53 import java.io.IOException;
54 import java.io.InputStream;
55 import java.lang.ref.WeakReference;
56 import java.lang.reflect.InvocationTargetException;
57 import java.lang.reflect.Method;
59 import java.util.List;
60 import java.util.ArrayList;
61 import java.util.Arrays;
62 import java.util.Collections;
63 import java.util.Enumeration;
64 import java.util.Objects;
66 final class IntentReceiverLeaked extends AndroidRuntimeException {
67 public IntentReceiverLeaked(String msg) {
72 final class ServiceConnectionLeaked extends AndroidRuntimeException {
73 public ServiceConnectionLeaked(String msg) {
79 * Local state maintained about a currently loaded .apk.
82 public final class LoadedApk {
84 private static final String TAG = "LoadedApk";
86 private final ActivityThread mActivityThread;
87 final String mPackageName;
88 private ApplicationInfo mApplicationInfo;
89 private String mAppDir;
90 private String mResDir;
91 private String[] mSplitAppDirs;
92 private String[] mSplitResDirs;
93 private String[] mOverlayDirs;
94 private String[] mSharedLibraries;
95 private String mDataDir;
96 private String mLibDir;
97 private File mDataDirFile;
98 private File mDeviceEncryptedDataDirFile;
99 private File mCredentialEncryptedDataDirFile;
100 private final ClassLoader mBaseClassLoader;
101 private final boolean mSecurityViolation;
102 private final boolean mIncludeCode;
103 private final boolean mRegisterPackage;
104 private final DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments();
105 /** WARNING: This may change. Don't hold external references to it. */
106 Resources mResources;
107 private ClassLoader mClassLoader;
108 private Application mApplication;
110 private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers
111 = new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
112 private final ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mUnregisteredReceivers
113 = new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
114 private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
115 = new ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>>();
116 private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mUnboundServices
117 = new ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>>();
119 int mClientCount = 0;
121 Application getApplication() {
126 * Create information about a new .apk
128 * NOTE: This constructor is called with ActivityThread's lock held,
129 * so MUST NOT call back out to the activity manager.
131 public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo,
132 CompatibilityInfo compatInfo, ClassLoader baseLoader,
133 boolean securityViolation, boolean includeCode, boolean registerPackage) {
135 mActivityThread = activityThread;
136 setApplicationInfo(aInfo);
137 mPackageName = aInfo.packageName;
138 mBaseClassLoader = baseLoader;
139 mSecurityViolation = securityViolation;
140 mIncludeCode = includeCode;
141 mRegisterPackage = registerPackage;
142 mDisplayAdjustments.setCompatibilityInfo(compatInfo);
145 private static ApplicationInfo adjustNativeLibraryPaths(ApplicationInfo info) {
146 // If we're dealing with a multi-arch application that has both
147 // 32 and 64 bit shared libraries, we might need to choose the secondary
148 // depending on what the current runtime's instruction set is.
149 if (info.primaryCpuAbi != null && info.secondaryCpuAbi != null) {
150 final String runtimeIsa = VMRuntime.getRuntime().vmInstructionSet();
152 // Get the instruction set that the libraries of secondary Abi is supported.
153 // In presence of a native bridge this might be different than the one secondary Abi used.
154 String secondaryIsa = VMRuntime.getInstructionSet(info.secondaryCpuAbi);
155 final String secondaryDexCodeIsa = SystemProperties.get("ro.dalvik.vm.isa." + secondaryIsa);
156 secondaryIsa = secondaryDexCodeIsa.isEmpty() ? secondaryIsa : secondaryDexCodeIsa;
158 // If the runtimeIsa is the same as the primary isa, then we do nothing.
159 // Everything will be set up correctly because info.nativeLibraryDir will
160 // correspond to the right ISA.
161 if (runtimeIsa.equals(secondaryIsa)) {
162 final ApplicationInfo modified = new ApplicationInfo(info);
163 modified.nativeLibraryDir = modified.secondaryNativeLibraryDir;
164 modified.primaryCpuAbi = modified.secondaryCpuAbi;
173 * Create information about the system package.
174 * Must call {@link #installSystemApplicationInfo} later.
176 LoadedApk(ActivityThread activityThread) {
177 mActivityThread = activityThread;
178 mApplicationInfo = new ApplicationInfo();
179 mApplicationInfo.packageName = "android";
180 mPackageName = "android";
183 mSplitAppDirs = null;
184 mSplitResDirs = null;
186 mSharedLibraries = null;
189 mDeviceEncryptedDataDirFile = null;
190 mCredentialEncryptedDataDirFile = null;
192 mBaseClassLoader = null;
193 mSecurityViolation = false;
195 mRegisterPackage = false;
196 mClassLoader = ClassLoader.getSystemClassLoader();
197 mResources = Resources.getSystem();
201 * Sets application info about the system package.
203 void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
204 assert info.packageName.equals("android");
205 mApplicationInfo = info;
206 mClassLoader = classLoader;
209 public String getPackageName() {
213 public ApplicationInfo getApplicationInfo() {
214 return mApplicationInfo;
217 public int getTargetSdkVersion() {
218 return mApplicationInfo.targetSdkVersion;
221 public boolean isSecurityViolation() {
222 return mSecurityViolation;
225 public CompatibilityInfo getCompatibilityInfo() {
226 return mDisplayAdjustments.getCompatibilityInfo();
229 public void setCompatibilityInfo(CompatibilityInfo compatInfo) {
230 mDisplayAdjustments.setCompatibilityInfo(compatInfo);
234 * Gets the array of shared libraries that are listed as
235 * used by the given package.
237 * @param packageName the name of the package (note: not its
239 * @return null-ok; the array of shared libraries, each one
240 * a fully-qualified path
242 private static String[] getLibrariesFor(String packageName) {
243 ApplicationInfo ai = null;
245 ai = ActivityThread.getPackageManager().getApplicationInfo(packageName,
246 PackageManager.GET_SHARED_LIBRARY_FILES, UserHandle.myUserId());
247 } catch (RemoteException e) {
248 throw e.rethrowFromSystemServer();
255 return ai.sharedLibraryFiles;
258 public void updateApplicationInfo(ApplicationInfo aInfo, List<String> oldPaths) {
259 setApplicationInfo(aInfo);
261 final List<String> newPaths = new ArrayList<>();
262 makePaths(mActivityThread, aInfo, newPaths, null /*libPaths*/);
263 final List<String> addedPaths = new ArrayList<>(newPaths.size());
265 if (oldPaths != null) {
266 for (String path : newPaths) {
267 final String apkName = path.substring(path.lastIndexOf(File.separator));
268 boolean match = false;
269 for (String oldPath : oldPaths) {
270 final String oldApkName = oldPath.substring(path.lastIndexOf(File.separator));
271 if (apkName.equals(oldApkName)) {
277 addedPaths.add(path);
281 addedPaths.addAll(newPaths);
283 synchronized (this) {
284 createOrUpdateClassLoaderLocked(addedPaths);
285 if (mResources != null) {
286 mResources = mActivityThread.getTopLevelResources(mResDir, mSplitResDirs,
287 mOverlayDirs, mApplicationInfo.sharedLibraryFiles, Display.DEFAULT_DISPLAY,
293 private void setApplicationInfo(ApplicationInfo aInfo) {
294 final int myUid = Process.myUid();
295 aInfo = adjustNativeLibraryPaths(aInfo);
296 mApplicationInfo = aInfo;
297 mAppDir = aInfo.sourceDir;
298 mResDir = aInfo.uid == myUid ? aInfo.sourceDir : aInfo.publicSourceDir;
299 mSplitAppDirs = aInfo.splitSourceDirs;
300 mSplitResDirs = aInfo.uid == myUid ? aInfo.splitSourceDirs : aInfo.splitPublicSourceDirs;
301 mOverlayDirs = aInfo.resourceDirs;
302 mSharedLibraries = aInfo.sharedLibraryFiles;
303 mDataDir = aInfo.dataDir;
304 mLibDir = aInfo.nativeLibraryDir;
305 mDataDirFile = FileUtils.newFileOrNull(aInfo.dataDir);
306 mDeviceEncryptedDataDirFile = FileUtils.newFileOrNull(aInfo.deviceEncryptedDataDir);
307 mCredentialEncryptedDataDirFile = FileUtils.newFileOrNull(aInfo.credentialEncryptedDataDir);
310 public static void makePaths(ActivityThread activityThread, ApplicationInfo aInfo,
311 List<String> outZipPaths, List<String> outLibPaths) {
312 final String appDir = aInfo.sourceDir;
313 final String[] splitAppDirs = aInfo.splitSourceDirs;
314 final String libDir = aInfo.nativeLibraryDir;
315 final String[] sharedLibraries = aInfo.sharedLibraryFiles;
318 outZipPaths.add(appDir);
319 if (splitAppDirs != null) {
320 Collections.addAll(outZipPaths, splitAppDirs);
323 if (outLibPaths != null) {
328 * The following is a bit of a hack to inject
329 * instrumentation into the system: If the app
330 * being started matches one of the instrumentation names,
331 * then we combine both the "instrumentation" and
332 * "instrumented" app into the path, along with the
333 * concatenation of both apps' shared library lists.
336 String instrumentationPackageName = activityThread.mInstrumentationPackageName;
337 String instrumentationAppDir = activityThread.mInstrumentationAppDir;
338 String[] instrumentationSplitAppDirs = activityThread.mInstrumentationSplitAppDirs;
339 String instrumentationLibDir = activityThread.mInstrumentationLibDir;
341 String instrumentedAppDir = activityThread.mInstrumentedAppDir;
342 String[] instrumentedSplitAppDirs = activityThread.mInstrumentedSplitAppDirs;
343 String instrumentedLibDir = activityThread.mInstrumentedLibDir;
344 String[] instrumentationLibs = null;
346 if (appDir.equals(instrumentationAppDir)
347 || appDir.equals(instrumentedAppDir)) {
349 outZipPaths.add(instrumentationAppDir);
350 if (instrumentationSplitAppDirs != null) {
351 Collections.addAll(outZipPaths, instrumentationSplitAppDirs);
353 outZipPaths.add(instrumentedAppDir);
354 if (instrumentedSplitAppDirs != null) {
355 Collections.addAll(outZipPaths, instrumentedSplitAppDirs);
358 if (outLibPaths != null) {
359 outLibPaths.add(instrumentationLibDir);
360 outLibPaths.add(instrumentedLibDir);
363 if (!instrumentedAppDir.equals(instrumentationAppDir)) {
364 instrumentationLibs = getLibrariesFor(instrumentationPackageName);
368 if (outLibPaths != null) {
369 if (outLibPaths.isEmpty()) {
370 outLibPaths.add(libDir);
373 // Add path to libraries in apk for current abi. Do this now because more entries
374 // will be added to zipPaths that shouldn't be part of the library path.
375 if (aInfo.primaryCpuAbi != null) {
376 for (String apk : outZipPaths) {
377 outLibPaths.add(apk + "!/lib/" + aInfo.primaryCpuAbi);
381 if (aInfo.isSystemApp() && !aInfo.isUpdatedSystemApp()) {
382 // Add path to system libraries to libPaths;
383 // Access to system libs should be limited
384 // to bundled applications; this is why updated
385 // system apps are not included.
386 outLibPaths.add(System.getProperty("java.library.path"));
390 if (sharedLibraries != null) {
391 for (String lib : sharedLibraries) {
392 if (!outZipPaths.contains(lib)) {
393 outZipPaths.add(0, lib);
398 if (instrumentationLibs != null) {
399 for (String lib : instrumentationLibs) {
400 if (!outZipPaths.contains(lib)) {
401 outZipPaths.add(0, lib);
407 private void createOrUpdateClassLoaderLocked(List<String> addedPaths) {
408 if (mPackageName.equals("android")) {
409 if (mClassLoader != null) {
414 if (mBaseClassLoader != null) {
415 mClassLoader = mBaseClassLoader;
417 mClassLoader = ClassLoader.getSystemClassLoader();
423 // Avoid the binder call when the package is the current application package.
424 // The activity manager will perform ensure that dexopt is performed before
425 // spinning up the process.
426 if (!Objects.equals(mPackageName, ActivityThread.currentPackageName())) {
427 VMRuntime.getRuntime().vmInstructionSet();
429 ActivityThread.getPackageManager().notifyPackageUse(mPackageName);
430 } catch (RemoteException re) {
431 throw re.rethrowFromSystemServer();
435 final List<String> zipPaths = new ArrayList<>();
436 final List<String> libPaths = new ArrayList<>();
438 if (mRegisterPackage) {
440 ActivityManagerNative.getDefault().addPackageDependency(mPackageName);
441 } catch (RemoteException e) {
442 throw e.rethrowFromSystemServer();
446 makePaths(mActivityThread, mApplicationInfo, zipPaths, libPaths);
447 final String zip = mIncludeCode ? TextUtils.join(File.pathSeparator, zipPaths) : "";
448 final boolean isBundledApp = mApplicationInfo.isSystemApp()
449 && !mApplicationInfo.isUpdatedSystemApp();
450 String libraryPermittedPath = mDataDir;
452 // This is necessary to grant bundled apps access to
453 // libraries located in subdirectories of /system/lib
454 libraryPermittedPath += File.pathSeparator +
455 System.getProperty("java.library.path");
457 // DO NOT SHIP: this is a workaround for apps loading native libraries
458 // provided by 3rd party apps using absolute path instead of corresponding
459 // classloader; see http://b/26954419 for example.
460 if (mApplicationInfo.targetSdkVersion <= 23) {
461 libraryPermittedPath += File.pathSeparator + "/data/app";
463 // -----------------------------------------------------------------------------
465 final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);
468 * With all the combination done (if necessary, actually
469 * create the class loader.
472 if (ActivityThread.localLOGV)
473 Slog.v(ActivityThread.TAG, "Class path: " + zip +
474 ", JNI path: " + librarySearchPath);
476 if (mClassLoader == null) {
477 // Temporarily disable logging of disk reads on the Looper thread
478 // as this is early and necessary.
479 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
481 mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip,
482 mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
483 libraryPermittedPath, mBaseClassLoader);
485 StrictMode.setThreadPolicy(oldPolicy);
488 if (addedPaths != null && addedPaths.size() > 0) {
489 final String add = TextUtils.join(File.pathSeparator, addedPaths);
490 ApplicationLoaders.getDefault().addPath(mClassLoader, add);
494 public ClassLoader getClassLoader() {
495 synchronized (this) {
496 if (mClassLoader == null) {
497 createOrUpdateClassLoaderLocked(null /*addedPaths*/);
504 * Setup value for Thread.getContextClassLoader(). If the
505 * package will not run in in a VM with other packages, we set
506 * the Java context ClassLoader to the
507 * PackageInfo.getClassLoader value. However, if this VM can
508 * contain multiple packages, we intead set the Java context
509 * ClassLoader to a proxy that will warn about the use of Java
510 * context ClassLoaders and then fall through to use the
511 * system ClassLoader.
513 * <p> Note that this is similar to but not the same as the
514 * android.content.Context.getClassLoader(). While both
515 * context class loaders are typically set to the
516 * PathClassLoader used to load the package archive in the
517 * single application per VM case, a single Android process
518 * may contain several Contexts executing on one thread with
519 * their own logical ClassLoaders while the Java context
520 * ClassLoader is a thread local. This is why in the case when
521 * we have multiple packages per VM we do not set the Java
522 * context ClassLoader to an arbitrary but instead warn the
523 * user to set their own if we detect that they are using a
524 * Java library that expects it to be set.
526 private void initializeJavaContextClassLoader() {
527 IPackageManager pm = ActivityThread.getPackageManager();
528 android.content.pm.PackageInfo pi;
530 pi = pm.getPackageInfo(mPackageName, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
531 UserHandle.myUserId());
532 } catch (RemoteException e) {
533 throw e.rethrowFromSystemServer();
536 throw new IllegalStateException("Unable to get package info for "
537 + mPackageName + "; is package not installed?");
540 * Two possible indications that this package could be
541 * sharing its virtual machine with other packages:
543 * 1.) the sharedUserId attribute is set in the manifest,
544 * indicating a request to share a VM with other
545 * packages with the same sharedUserId.
547 * 2.) the application element of the manifest has an
548 * attribute specifying a non-default process name,
549 * indicating the desire to run in another packages VM.
551 boolean sharedUserIdSet = (pi.sharedUserId != null);
552 boolean processNameNotDefault =
553 (pi.applicationInfo != null &&
554 !mPackageName.equals(pi.applicationInfo.processName));
555 boolean sharable = (sharedUserIdSet || processNameNotDefault);
556 ClassLoader contextClassLoader =
558 ? new WarningContextClassLoader()
560 Thread.currentThread().setContextClassLoader(contextClassLoader);
563 private static class WarningContextClassLoader extends ClassLoader {
565 private static boolean warned = false;
567 private void warn(String methodName) {
572 Thread.currentThread().setContextClassLoader(getParent());
573 Slog.w(ActivityThread.TAG, "ClassLoader." + methodName + ": " +
574 "The class loader returned by " +
575 "Thread.getContextClassLoader() may fail for processes " +
576 "that host multiple applications. You should explicitly " +
577 "specify a context class loader. For example: " +
578 "Thread.setContextClassLoader(getClass().getClassLoader());");
581 @Override public URL getResource(String resName) {
583 return getParent().getResource(resName);
586 @Override public Enumeration<URL> getResources(String resName) throws IOException {
587 warn("getResources");
588 return getParent().getResources(resName);
591 @Override public InputStream getResourceAsStream(String resName) {
592 warn("getResourceAsStream");
593 return getParent().getResourceAsStream(resName);
596 @Override public Class<?> loadClass(String className) throws ClassNotFoundException {
598 return getParent().loadClass(className);
601 @Override public void setClassAssertionStatus(String cname, boolean enable) {
602 warn("setClassAssertionStatus");
603 getParent().setClassAssertionStatus(cname, enable);
606 @Override public void setPackageAssertionStatus(String pname, boolean enable) {
607 warn("setPackageAssertionStatus");
608 getParent().setPackageAssertionStatus(pname, enable);
611 @Override public void setDefaultAssertionStatus(boolean enable) {
612 warn("setDefaultAssertionStatus");
613 getParent().setDefaultAssertionStatus(enable);
616 @Override public void clearAssertionStatus() {
617 warn("clearAssertionStatus");
618 getParent().clearAssertionStatus();
622 public String getAppDir() {
626 public String getLibDir() {
630 public String getResDir() {
634 public String[] getSplitAppDirs() {
635 return mSplitAppDirs;
638 public String[] getSplitResDirs() {
639 return mSplitResDirs;
642 public String[] getOverlayDirs() {
646 public String getDataDir() {
650 public File getDataDirFile() {
654 public File getDeviceEncryptedDataDirFile() {
655 return mDeviceEncryptedDataDirFile;
658 public File getCredentialEncryptedDataDirFile() {
659 return mCredentialEncryptedDataDirFile;
662 public AssetManager getAssets(ActivityThread mainThread) {
663 return getResources(mainThread).getAssets();
666 public Resources getResources(ActivityThread mainThread) {
667 if (mResources == null) {
668 mResources = mainThread.getTopLevelResources(mResDir, mSplitResDirs, mOverlayDirs,
669 mApplicationInfo.sharedLibraryFiles, Display.DEFAULT_DISPLAY, this);
674 public Application makeApplication(boolean forceDefaultAppClass,
675 Instrumentation instrumentation) {
676 if (mApplication != null) {
680 Application app = null;
682 String appClass = mApplicationInfo.className;
683 if (forceDefaultAppClass || (appClass == null)) {
684 appClass = "android.app.Application";
688 java.lang.ClassLoader cl = getClassLoader();
689 if (!mPackageName.equals("android")) {
690 initializeJavaContextClassLoader();
692 ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
693 app = mActivityThread.mInstrumentation.newApplication(
694 cl, appClass, appContext);
695 appContext.setOuterContext(app);
696 } catch (Exception e) {
697 if (!mActivityThread.mInstrumentation.onException(app, e)) {
698 throw new RuntimeException(
699 "Unable to instantiate application " + appClass
700 + ": " + e.toString(), e);
703 mActivityThread.mAllApplications.add(app);
706 if (instrumentation != null) {
708 instrumentation.callApplicationOnCreate(app);
709 } catch (Exception e) {
710 if (!instrumentation.onException(app, e)) {
711 throw new RuntimeException(
712 "Unable to create application " + app.getClass().getName()
713 + ": " + e.toString(), e);
718 // Rewrite the R 'constants' for all library apks.
719 SparseArray<String> packageIdentifiers = getAssets(mActivityThread)
720 .getAssignedPackageIdentifiers();
721 final int N = packageIdentifiers.size();
722 for (int i = 0; i < N; i++) {
723 final int id = packageIdentifiers.keyAt(i);
724 if (id == 0x01 || id == 0x7f) {
728 rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id);
734 private void rewriteRValues(ClassLoader cl, String packageName, int id) {
735 final Class<?> rClazz;
737 rClazz = cl.loadClass(packageName + ".R");
738 } catch (ClassNotFoundException e) {
739 // This is not necessarily an error, as some packages do not ship with resources
740 // (or they do not need rewriting).
741 Log.i(TAG, "No resource references to update in package " + packageName);
745 final Method callback;
747 callback = rClazz.getMethod("onResourcesLoaded", int.class);
748 } catch (NoSuchMethodException e) {
749 // No rewriting to be done.
755 callback.invoke(null, id);
757 } catch (IllegalAccessException e) {
759 } catch (InvocationTargetException e) {
760 cause = e.getCause();
763 throw new RuntimeException("Failed to rewrite resource references for " + packageName,
767 public void removeContextRegistrations(Context context,
768 String who, String what) {
769 final boolean reportRegistrationLeaks = StrictMode.vmRegistrationLeaksEnabled();
770 synchronized (mReceivers) {
771 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> rmap =
772 mReceivers.remove(context);
774 for (int i = 0; i < rmap.size(); i++) {
775 LoadedApk.ReceiverDispatcher rd = rmap.valueAt(i);
776 IntentReceiverLeaked leak = new IntentReceiverLeaked(
777 what + " " + who + " has leaked IntentReceiver "
778 + rd.getIntentReceiver() + " that was " +
779 "originally registered here. Are you missing a " +
780 "call to unregisterReceiver()?");
781 leak.setStackTrace(rd.getLocation().getStackTrace());
782 Slog.e(ActivityThread.TAG, leak.getMessage(), leak);
783 if (reportRegistrationLeaks) {
784 StrictMode.onIntentReceiverLeaked(leak);
787 ActivityManagerNative.getDefault().unregisterReceiver(
788 rd.getIIntentReceiver());
789 } catch (RemoteException e) {
790 throw e.rethrowFromSystemServer();
794 mUnregisteredReceivers.remove(context);
797 synchronized (mServices) {
798 //Slog.i(TAG, "Receiver registrations: " + mReceivers);
799 ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> smap =
800 mServices.remove(context);
802 for (int i = 0; i < smap.size(); i++) {
803 LoadedApk.ServiceDispatcher sd = smap.valueAt(i);
804 ServiceConnectionLeaked leak = new ServiceConnectionLeaked(
805 what + " " + who + " has leaked ServiceConnection "
806 + sd.getServiceConnection() + " that was originally bound here");
807 leak.setStackTrace(sd.getLocation().getStackTrace());
808 Slog.e(ActivityThread.TAG, leak.getMessage(), leak);
809 if (reportRegistrationLeaks) {
810 StrictMode.onServiceConnectionLeaked(leak);
813 ActivityManagerNative.getDefault().unbindService(
814 sd.getIServiceConnection());
815 } catch (RemoteException e) {
816 throw e.rethrowFromSystemServer();
821 mUnboundServices.remove(context);
822 //Slog.i(TAG, "Service registrations: " + mServices);
826 public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
827 Context context, Handler handler,
828 Instrumentation instrumentation, boolean registered) {
829 synchronized (mReceivers) {
830 LoadedApk.ReceiverDispatcher rd = null;
831 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
833 map = mReceivers.get(context);
839 rd = new ReceiverDispatcher(r, context, handler,
840 instrumentation, registered);
843 map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
844 mReceivers.put(context, map);
849 rd.validate(context, handler);
851 rd.mForgotten = false;
852 return rd.getIIntentReceiver();
856 public IIntentReceiver forgetReceiverDispatcher(Context context,
857 BroadcastReceiver r) {
858 synchronized (mReceivers) {
859 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = mReceivers.get(context);
860 LoadedApk.ReceiverDispatcher rd = null;
865 if (map.size() == 0) {
866 mReceivers.remove(context);
868 if (r.getDebugUnregister()) {
869 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder
870 = mUnregisteredReceivers.get(context);
871 if (holder == null) {
872 holder = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
873 mUnregisteredReceivers.put(context, holder);
875 RuntimeException ex = new IllegalArgumentException(
876 "Originally unregistered here:");
877 ex.fillInStackTrace();
878 rd.setUnregisterLocation(ex);
881 rd.mForgotten = true;
882 return rd.getIIntentReceiver();
885 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder
886 = mUnregisteredReceivers.get(context);
887 if (holder != null) {
890 RuntimeException ex = rd.getUnregisterLocation();
891 throw new IllegalArgumentException(
892 "Unregistering Receiver " + r
893 + " that was already unregistered", ex);
896 if (context == null) {
897 throw new IllegalStateException("Unbinding Receiver " + r
898 + " from Context that is no longer in use: " + context);
900 throw new IllegalArgumentException("Receiver not registered: " + r);
906 static final class ReceiverDispatcher {
908 final static class InnerReceiver extends IIntentReceiver.Stub {
909 final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
910 final LoadedApk.ReceiverDispatcher mStrongRef;
912 InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
913 mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
914 mStrongRef = strong ? rd : null;
918 public void performReceive(Intent intent, int resultCode, String data,
919 Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
920 LoadedApk.ReceiverDispatcher rd = mDispatcher.get();
921 if (ActivityThread.DEBUG_BROADCAST) {
922 int seq = intent.getIntExtra("seq", -1);
923 Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction() + " seq=" + seq
924 + " to " + (rd != null ? rd.mReceiver : null));
927 rd.performReceive(intent, resultCode, data, extras,
928 ordered, sticky, sendingUser);
930 // The activity manager dispatched a broadcast to a registered
931 // receiver in this process, but before it could be delivered the
932 // receiver was unregistered. Acknowledge the broadcast on its
933 // behalf so that the system's broadcast sequence can continue.
934 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
935 "Finishing broadcast to unregistered receiver");
936 IActivityManager mgr = ActivityManagerNative.getDefault();
938 if (extras != null) {
939 extras.setAllowFds(false);
941 mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
942 } catch (RemoteException e) {
943 throw e.rethrowFromSystemServer();
949 final IIntentReceiver.Stub mIIntentReceiver;
950 final BroadcastReceiver mReceiver;
951 final Context mContext;
952 final Handler mActivityThread;
953 final Instrumentation mInstrumentation;
954 final boolean mRegistered;
955 final IntentReceiverLeaked mLocation;
956 RuntimeException mUnregisterLocation;
959 final class Args extends BroadcastReceiver.PendingResult implements Runnable {
960 private Intent mCurIntent;
961 private final boolean mOrdered;
963 public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
964 boolean ordered, boolean sticky, int sendingUser) {
965 super(resultCode, resultData, resultExtras,
966 mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered,
967 sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags());
973 final BroadcastReceiver receiver = mReceiver;
974 final boolean ordered = mOrdered;
976 if (ActivityThread.DEBUG_BROADCAST) {
977 int seq = mCurIntent.getIntExtra("seq", -1);
978 Slog.i(ActivityThread.TAG, "Dispatching broadcast " + mCurIntent.getAction()
979 + " seq=" + seq + " to " + mReceiver);
980 Slog.i(ActivityThread.TAG, " mRegistered=" + mRegistered
981 + " mOrderedHint=" + ordered);
984 final IActivityManager mgr = ActivityManagerNative.getDefault();
985 final Intent intent = mCurIntent;
988 if (receiver == null || mForgotten) {
989 if (mRegistered && ordered) {
990 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
991 "Finishing null broadcast to " + mReceiver);
997 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg");
999 ClassLoader cl = mReceiver.getClass().getClassLoader();
1000 intent.setExtrasClassLoader(cl);
1001 intent.prepareToEnterProcess();
1002 setExtrasClassLoader(cl);
1003 receiver.setPendingResult(this);
1004 receiver.onReceive(mContext, intent);
1005 } catch (Exception e) {
1006 if (mRegistered && ordered) {
1007 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
1008 "Finishing failed broadcast to " + mReceiver);
1011 if (mInstrumentation == null ||
1012 !mInstrumentation.onException(mReceiver, e)) {
1013 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
1014 throw new RuntimeException(
1015 "Error receiving broadcast " + intent
1016 + " in " + mReceiver, e);
1020 if (receiver.getPendingResult() != null) {
1023 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
1027 ReceiverDispatcher(BroadcastReceiver receiver, Context context,
1028 Handler activityThread, Instrumentation instrumentation,
1029 boolean registered) {
1030 if (activityThread == null) {
1031 throw new NullPointerException("Handler must not be null");
1034 mIIntentReceiver = new InnerReceiver(this, !registered);
1035 mReceiver = receiver;
1037 mActivityThread = activityThread;
1038 mInstrumentation = instrumentation;
1039 mRegistered = registered;
1040 mLocation = new IntentReceiverLeaked(null);
1041 mLocation.fillInStackTrace();
1044 void validate(Context context, Handler activityThread) {
1045 if (mContext != context) {
1046 throw new IllegalStateException(
1047 "Receiver " + mReceiver +
1048 " registered with differing Context (was " +
1049 mContext + " now " + context + ")");
1051 if (mActivityThread != activityThread) {
1052 throw new IllegalStateException(
1053 "Receiver " + mReceiver +
1054 " registered with differing handler (was " +
1055 mActivityThread + " now " + activityThread + ")");
1059 IntentReceiverLeaked getLocation() {
1063 BroadcastReceiver getIntentReceiver() {
1067 IIntentReceiver getIIntentReceiver() {
1068 return mIIntentReceiver;
1071 void setUnregisterLocation(RuntimeException ex) {
1072 mUnregisterLocation = ex;
1075 RuntimeException getUnregisterLocation() {
1076 return mUnregisterLocation;
1079 public void performReceive(Intent intent, int resultCode, String data,
1080 Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
1081 if (ActivityThread.DEBUG_BROADCAST) {
1082 int seq = intent.getIntExtra("seq", -1);
1083 Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq
1084 + " to " + mReceiver);
1086 Args args = new Args(intent, resultCode, data, extras, ordered,
1087 sticky, sendingUser);
1088 if (!mActivityThread.post(args)) {
1089 if (mRegistered && ordered) {
1090 IActivityManager mgr = ActivityManagerNative.getDefault();
1091 if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
1092 "Finishing sync broadcast to " + mReceiver);
1093 args.sendFinished(mgr);
1100 public final IServiceConnection getServiceDispatcher(ServiceConnection c,
1101 Context context, Handler handler, int flags) {
1102 synchronized (mServices) {
1103 LoadedApk.ServiceDispatcher sd = null;
1104 ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
1109 sd = new ServiceDispatcher(c, context, handler, flags);
1111 map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
1112 mServices.put(context, map);
1116 sd.validate(context, handler);
1118 return sd.getIServiceConnection();
1122 public final IServiceConnection forgetServiceDispatcher(Context context,
1123 ServiceConnection c) {
1124 synchronized (mServices) {
1125 ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map
1126 = mServices.get(context);
1127 LoadedApk.ServiceDispatcher sd = null;
1133 if (map.size() == 0) {
1134 mServices.remove(context);
1136 if ((sd.getFlags()&Context.BIND_DEBUG_UNBIND) != 0) {
1137 ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder
1138 = mUnboundServices.get(context);
1139 if (holder == null) {
1140 holder = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
1141 mUnboundServices.put(context, holder);
1143 RuntimeException ex = new IllegalArgumentException(
1144 "Originally unbound here:");
1145 ex.fillInStackTrace();
1146 sd.setUnbindLocation(ex);
1149 return sd.getIServiceConnection();
1152 ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder
1153 = mUnboundServices.get(context);
1154 if (holder != null) {
1157 RuntimeException ex = sd.getUnbindLocation();
1158 throw new IllegalArgumentException(
1159 "Unbinding Service " + c
1160 + " that was already unbound", ex);
1163 if (context == null) {
1164 throw new IllegalStateException("Unbinding Service " + c
1165 + " from Context that is no longer in use: " + context);
1167 throw new IllegalArgumentException("Service not registered: " + c);
1172 static final class ServiceDispatcher {
1173 private final ServiceDispatcher.InnerConnection mIServiceConnection;
1174 private final ServiceConnection mConnection;
1175 private final Context mContext;
1176 private final Handler mActivityThread;
1177 private final ServiceConnectionLeaked mLocation;
1178 private final int mFlags;
1180 private RuntimeException mUnbindLocation;
1182 private boolean mForgotten;
1184 private static class ConnectionInfo {
1186 IBinder.DeathRecipient deathMonitor;
1189 private static class InnerConnection extends IServiceConnection.Stub {
1190 final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
1192 InnerConnection(LoadedApk.ServiceDispatcher sd) {
1193 mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
1196 public void connected(ComponentName name, IBinder service) throws RemoteException {
1197 LoadedApk.ServiceDispatcher sd = mDispatcher.get();
1199 sd.connected(name, service);
1204 private final ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections
1205 = new ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo>();
1207 ServiceDispatcher(ServiceConnection conn,
1208 Context context, Handler activityThread, int flags) {
1209 mIServiceConnection = new InnerConnection(this);
1212 mActivityThread = activityThread;
1213 mLocation = new ServiceConnectionLeaked(null);
1214 mLocation.fillInStackTrace();
1218 void validate(Context context, Handler activityThread) {
1219 if (mContext != context) {
1220 throw new RuntimeException(
1221 "ServiceConnection " + mConnection +
1222 " registered with differing Context (was " +
1223 mContext + " now " + context + ")");
1225 if (mActivityThread != activityThread) {
1226 throw new RuntimeException(
1227 "ServiceConnection " + mConnection +
1228 " registered with differing handler (was " +
1229 mActivityThread + " now " + activityThread + ")");
1234 synchronized(this) {
1235 for (int i=0; i<mActiveConnections.size(); i++) {
1236 ServiceDispatcher.ConnectionInfo ci = mActiveConnections.valueAt(i);
1237 ci.binder.unlinkToDeath(ci.deathMonitor, 0);
1239 mActiveConnections.clear();
1244 ServiceConnectionLeaked getLocation() {
1248 ServiceConnection getServiceConnection() {
1252 IServiceConnection getIServiceConnection() {
1253 return mIServiceConnection;
1260 void setUnbindLocation(RuntimeException ex) {
1261 mUnbindLocation = ex;
1264 RuntimeException getUnbindLocation() {
1265 return mUnbindLocation;
1268 public void connected(ComponentName name, IBinder service) {
1269 if (mActivityThread != null) {
1270 mActivityThread.post(new RunConnection(name, service, 0));
1272 doConnected(name, service);
1276 public void death(ComponentName name, IBinder service) {
1277 ServiceDispatcher.ConnectionInfo old;
1279 synchronized (this) {
1280 old = mActiveConnections.remove(name);
1281 if (old == null || old.binder != service) {
1282 // Death for someone different than who we last
1283 // reported... just ignore it.
1286 old.binder.unlinkToDeath(old.deathMonitor, 0);
1289 if (mActivityThread != null) {
1290 mActivityThread.post(new RunConnection(name, service, 1));
1292 doDeath(name, service);
1296 public void doConnected(ComponentName name, IBinder service) {
1297 ServiceDispatcher.ConnectionInfo old;
1298 ServiceDispatcher.ConnectionInfo info;
1300 synchronized (this) {
1302 // We unbound before receiving the connection; ignore
1303 // any connection received.
1306 old = mActiveConnections.get(name);
1307 if (old != null && old.binder == service) {
1308 // Huh, already have this one. Oh well!
1312 if (service != null) {
1313 // A new service is being connected... set it all up.
1314 info = new ConnectionInfo();
1315 info.binder = service;
1316 info.deathMonitor = new DeathMonitor(name, service);
1318 service.linkToDeath(info.deathMonitor, 0);
1319 mActiveConnections.put(name, info);
1320 } catch (RemoteException e) {
1321 // This service was dead before we got it... just
1322 // don't do anything with it.
1323 mActiveConnections.remove(name);
1328 // The named service is being disconnected... clean up.
1329 mActiveConnections.remove(name);
1333 old.binder.unlinkToDeath(old.deathMonitor, 0);
1337 // If there was an old service, it is not disconnected.
1339 mConnection.onServiceDisconnected(name);
1341 // If there is a new service, it is now connected.
1342 if (service != null) {
1343 mConnection.onServiceConnected(name, service);
1347 public void doDeath(ComponentName name, IBinder service) {
1348 mConnection.onServiceDisconnected(name);
1351 private final class RunConnection implements Runnable {
1352 RunConnection(ComponentName name, IBinder service, int command) {
1359 if (mCommand == 0) {
1360 doConnected(mName, mService);
1361 } else if (mCommand == 1) {
1362 doDeath(mName, mService);
1366 final ComponentName mName;
1367 final IBinder mService;
1371 private final class DeathMonitor implements IBinder.DeathRecipient
1373 DeathMonitor(ComponentName name, IBinder service) {
1378 public void binderDied() {
1379 death(mName, mService);
1382 final ComponentName mName;
1383 final IBinder mService;