package android.app;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.dex.ArtManager;
import android.content.pm.split.SplitDependencyLoader;
import android.content.res.AssetManager;
import android.content.res.CompatibilityInfo;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.os.StrictMode;
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.AndroidRuntimeException;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayAdjustments;
import com.android.internal.util.ArrayUtils;
import dalvik.system.VMRuntime;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Objects;
final class IntentReceiverLeaked extends AndroidRuntimeException {
public IntentReceiverLeaked(String msg) {
super(msg);
}
}
final class ServiceConnectionLeaked extends AndroidRuntimeException {
public ServiceConnectionLeaked(String msg) {
super(msg);
}
}
public final class LoadedApk {
static final String TAG = "LoadedApk";
static final boolean DEBUG = false;
private static final String PROPERTY_NAME_APPEND_NATIVE = "pi.append_native_lib_paths";
private final ActivityThread mActivityThread;
final String mPackageName;
private ApplicationInfo mApplicationInfo;
private String mAppDir;
private String mResDir;
private String[] mOverlayDirs;
private String mDataDir;
private String mLibDir;
private File mDataDirFile;
private File mDeviceProtectedDataDirFile;
private File mCredentialProtectedDataDirFile;
private final ClassLoader mBaseClassLoader;
private final boolean mSecurityViolation;
private final boolean mIncludeCode;
private final boolean mRegisterPackage;
private final DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments();
Resources mResources;
private ClassLoader mClassLoader;
private Application mApplication;
private String[] mSplitNames;
private String[] mSplitAppDirs;
private String[] mSplitResDirs;
private String[] mSplitClassLoaderNames;
private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers
= new ArrayMap<>();
private final ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mUnregisteredReceivers
= new ArrayMap<>();
private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
= new ArrayMap<>();
private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mUnboundServices
= new ArrayMap<>();
private AppComponentFactory mAppComponentFactory;
Application getApplication() {
return mApplication;
}
public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo,
CompatibilityInfo compatInfo, ClassLoader baseLoader,
boolean securityViolation, boolean includeCode, boolean registerPackage) {
mActivityThread = activityThread;
setApplicationInfo(aInfo);
mPackageName = aInfo.packageName;
mBaseClassLoader = baseLoader;
mSecurityViolation = securityViolation;
mIncludeCode = includeCode;
mRegisterPackage = registerPackage;
mDisplayAdjustments.setCompatibilityInfo(compatInfo);
mAppComponentFactory = createAppFactory(mApplicationInfo, mBaseClassLoader);
}
private static ApplicationInfo adjustNativeLibraryPaths(ApplicationInfo info) {
if (info.primaryCpuAbi != null && info.secondaryCpuAbi != null) {
final String runtimeIsa = VMRuntime.getRuntime().vmInstructionSet();
String secondaryIsa = VMRuntime.getInstructionSet(info.secondaryCpuAbi);
final String secondaryDexCodeIsa = SystemProperties.get("ro.dalvik.vm.isa." + secondaryIsa);
secondaryIsa = secondaryDexCodeIsa.isEmpty() ? secondaryIsa : secondaryDexCodeIsa;
if (runtimeIsa.equals(secondaryIsa)) {
final ApplicationInfo modified = new ApplicationInfo(info);
modified.nativeLibraryDir = modified.secondaryNativeLibraryDir;
modified.primaryCpuAbi = modified.secondaryCpuAbi;
return modified;
}
}
return info;
}
LoadedApk(ActivityThread activityThread) {
mActivityThread = activityThread;
mApplicationInfo = new ApplicationInfo();
mApplicationInfo.packageName = "android";
mPackageName = "android";
mAppDir = null;
mResDir = null;
mSplitAppDirs = null;
mSplitResDirs = null;
mSplitClassLoaderNames = null;
mOverlayDirs = null;
mDataDir = null;
mDataDirFile = null;
mDeviceProtectedDataDirFile = null;
mCredentialProtectedDataDirFile = null;
mLibDir = null;
mBaseClassLoader = null;
mSecurityViolation = false;
mIncludeCode = true;
mRegisterPackage = false;
mClassLoader = ClassLoader.getSystemClassLoader();
mResources = Resources.getSystem();
mAppComponentFactory = createAppFactory(mApplicationInfo, mClassLoader);
}
void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
assert info.packageName.equals("android");
mApplicationInfo = info;
mClassLoader = classLoader;
mAppComponentFactory = createAppFactory(info, classLoader);
}
private AppComponentFactory createAppFactory(ApplicationInfo appInfo, ClassLoader cl) {
if (appInfo.appComponentFactory != null && cl != null) {
try {
return (AppComponentFactory) cl.loadClass(appInfo.appComponentFactory)
.newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
Slog.e(TAG, "Unable to instantiate appComponentFactory", e);
}
}
return AppComponentFactory.DEFAULT;
}
public AppComponentFactory getAppFactory() {
return mAppComponentFactory;
}
public String getPackageName() {
return mPackageName;
}
public ApplicationInfo getApplicationInfo() {
return mApplicationInfo;
}
public int getTargetSdkVersion() {
return mApplicationInfo.targetSdkVersion;
}
public boolean isSecurityViolation() {
return mSecurityViolation;
}
public CompatibilityInfo getCompatibilityInfo() {
return mDisplayAdjustments.getCompatibilityInfo();
}
public void setCompatibilityInfo(CompatibilityInfo compatInfo) {
mDisplayAdjustments.setCompatibilityInfo(compatInfo);
}
private static String[] getLibrariesFor(String packageName) {
ApplicationInfo ai = null;
try {
ai = ActivityThread.getPackageManager().getApplicationInfo(packageName,
PackageManager.GET_SHARED_LIBRARY_FILES, UserHandle.myUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
if (ai == null) {
return null;
}
return ai.sharedLibraryFiles;
}
public void updateApplicationInfo(@NonNull ApplicationInfo aInfo,
@Nullable List<String> oldPaths) {
setApplicationInfo(aInfo);
final List<String> newPaths = new ArrayList<>();
makePaths(mActivityThread, aInfo, newPaths);
final List<String> addedPaths = new ArrayList<>(newPaths.size());
if (oldPaths != null) {
for (String path : newPaths) {
final String apkName = path.substring(path.lastIndexOf(File.separator));
boolean match = false;
for (String oldPath : oldPaths) {
final String oldApkName = oldPath.substring(oldPath.lastIndexOf(File.separator));
if (apkName.equals(oldApkName)) {
match = true;
break;
}
}
if (!match) {
addedPaths.add(path);
}
}
} else {
addedPaths.addAll(newPaths);
}
synchronized (this) {
createOrUpdateClassLoaderLocked(addedPaths);
if (mResources != null) {
final String[] splitPaths;
try {
splitPaths = getSplitPaths(null);
} catch (NameNotFoundException e) {
throw new AssertionError("null split not found");
}
mResources = ResourcesManager.getInstance().getResources(null, mResDir,
splitPaths, mOverlayDirs, mApplicationInfo.sharedLibraryFiles,
Display.DEFAULT_DISPLAY, null, getCompatibilityInfo(),
getClassLoader());
}
}
mAppComponentFactory = createAppFactory(aInfo, mClassLoader);
}
private void setApplicationInfo(ApplicationInfo aInfo) {
final int myUid = Process.myUid();
aInfo = adjustNativeLibraryPaths(aInfo);
mApplicationInfo = aInfo;
mAppDir = aInfo.sourceDir;
mResDir = aInfo.uid == myUid ? aInfo.sourceDir : aInfo.publicSourceDir;
mOverlayDirs = aInfo.resourceDirs;
mDataDir = aInfo.dataDir;
mLibDir = aInfo.nativeLibraryDir;
mDataDirFile = FileUtils.newFileOrNull(aInfo.dataDir);
mDeviceProtectedDataDirFile = FileUtils.newFileOrNull(aInfo.deviceProtectedDataDir);
mCredentialProtectedDataDirFile = FileUtils.newFileOrNull(aInfo.credentialProtectedDataDir);
mSplitNames = aInfo.splitNames;
mSplitAppDirs = aInfo.splitSourceDirs;
mSplitResDirs = aInfo.uid == myUid ? aInfo.splitSourceDirs : aInfo.splitPublicSourceDirs;
mSplitClassLoaderNames = aInfo.splitClassLoaderNames;
if (aInfo.requestsIsolatedSplitLoading() && !ArrayUtils.isEmpty(mSplitNames)) {
mSplitLoader = new SplitDependencyLoaderImpl(aInfo.splitDependencies);
}
}
public static void makePaths(ActivityThread activityThread,
ApplicationInfo aInfo,
List<String> outZipPaths) {
makePaths(activityThread, false, aInfo, outZipPaths, null);
}
public static void makePaths(ActivityThread activityThread,
boolean isBundledApp,
ApplicationInfo aInfo,
List<String> outZipPaths,
List<String> outLibPaths) {
final String appDir = aInfo.sourceDir;
final String libDir = aInfo.nativeLibraryDir;
final String[] sharedLibraries = aInfo.sharedLibraryFiles;
outZipPaths.clear();
outZipPaths.add(appDir);
if (aInfo.splitSourceDirs != null && !aInfo.requestsIsolatedSplitLoading()) {
Collections.addAll(outZipPaths, aInfo.splitSourceDirs);
}
if (outLibPaths != null) {
outLibPaths.clear();
}
String[] instrumentationLibs = null;
if (activityThread != null) {
String instrumentationPackageName = activityThread.mInstrumentationPackageName;
String instrumentationAppDir = activityThread.mInstrumentationAppDir;
String[] instrumentationSplitAppDirs = activityThread.mInstrumentationSplitAppDirs;
String instrumentationLibDir = activityThread.mInstrumentationLibDir;
String instrumentedAppDir = activityThread.mInstrumentedAppDir;
String[] instrumentedSplitAppDirs = activityThread.mInstrumentedSplitAppDirs;
String instrumentedLibDir = activityThread.mInstrumentedLibDir;
if (appDir.equals(instrumentationAppDir)
|| appDir.equals(instrumentedAppDir)) {
outZipPaths.clear();
outZipPaths.add(instrumentationAppDir);
if (!aInfo.requestsIsolatedSplitLoading()) {
if (instrumentationSplitAppDirs != null) {
Collections.addAll(outZipPaths, instrumentationSplitAppDirs);
}
if (!instrumentationAppDir.equals(instrumentedAppDir)) {
outZipPaths.add(instrumentedAppDir);
if (instrumentedSplitAppDirs != null) {
Collections.addAll(outZipPaths, instrumentedSplitAppDirs);
}
}
}
if (outLibPaths != null) {
outLibPaths.add(instrumentationLibDir);
if (!instrumentationLibDir.equals(instrumentedLibDir)) {
outLibPaths.add(instrumentedLibDir);
}
}
if (!instrumentedAppDir.equals(instrumentationAppDir)) {
instrumentationLibs = getLibrariesFor(instrumentationPackageName);
}
}
}
if (outLibPaths != null) {
if (outLibPaths.isEmpty()) {
outLibPaths.add(libDir);
}
if (aInfo.primaryCpuAbi != null) {
if (aInfo.targetSdkVersion < Build.VERSION_CODES.N) {
outLibPaths.add("/system/fake-libs" +
(VMRuntime.is64BitAbi(aInfo.primaryCpuAbi) ? "64" : ""));
}
for (String apk : outZipPaths) {
outLibPaths.add(apk + "!/lib/" + aInfo.primaryCpuAbi);
}
}
if (isBundledApp) {
outLibPaths.add(System.getProperty("java.library.path"));
}
}
if (sharedLibraries != null) {
int index = 0;
for (String lib : sharedLibraries) {
if (!outZipPaths.contains(lib)) {
outZipPaths.add(index, lib);
index++;
appendApkLibPathIfNeeded(lib, aInfo, outLibPaths);
}
}
}
if (instrumentationLibs != null) {
for (String lib : instrumentationLibs) {
if (!outZipPaths.contains(lib)) {
outZipPaths.add(0, lib);
appendApkLibPathIfNeeded(lib, aInfo, outLibPaths);
}
}
}
}
private static void appendApkLibPathIfNeeded(@NonNull String path,
@NonNull ApplicationInfo applicationInfo, @Nullable List<String> outLibPaths) {
if (outLibPaths != null && applicationInfo.primaryCpuAbi != null && path.endsWith(".apk")) {
if (applicationInfo.targetSdkVersion >= Build.VERSION_CODES.O) {
outLibPaths.add(path + "!/lib/" + applicationInfo.primaryCpuAbi);
}
}
}
private class SplitDependencyLoaderImpl extends SplitDependencyLoader<NameNotFoundException> {
private final String[][] mCachedResourcePaths;
private final ClassLoader[] mCachedClassLoaders;
SplitDependencyLoaderImpl(@NonNull SparseArray<int[]> dependencies) {
super(dependencies);
mCachedResourcePaths = new String[mSplitNames.length + 1][];
mCachedClassLoaders = new ClassLoader[mSplitNames.length + 1];
}
@Override
protected boolean isSplitCached(int splitIdx) {
return mCachedClassLoaders[splitIdx] != null;
}
@Override
protected void constructSplit(int splitIdx, @NonNull int[] configSplitIndices,
int parentSplitIdx) throws NameNotFoundException {
final ArrayList<String> splitPaths = new ArrayList<>();
if (splitIdx == 0) {
createOrUpdateClassLoaderLocked(null);
mCachedClassLoaders[0] = mClassLoader;
for (int configSplitIdx : configSplitIndices) {
splitPaths.add(mSplitResDirs[configSplitIdx - 1]);
}
mCachedResourcePaths[0] = splitPaths.toArray(new String[splitPaths.size()]);
return;
}
final ClassLoader parent = mCachedClassLoaders[parentSplitIdx];
mCachedClassLoaders[splitIdx] = ApplicationLoaders.getDefault().getClassLoader(
mSplitAppDirs[splitIdx - 1], getTargetSdkVersion(), false, null, null, parent,
mSplitClassLoaderNames[splitIdx - 1]);
Collections.addAll(splitPaths, mCachedResourcePaths[parentSplitIdx]);
splitPaths.add(mSplitResDirs[splitIdx - 1]);
for (int configSplitIdx : configSplitIndices) {
splitPaths.add(mSplitResDirs[configSplitIdx - 1]);
}
mCachedResourcePaths[splitIdx] = splitPaths.toArray(new String[splitPaths.size()]);
}
private int ensureSplitLoaded(String splitName) throws NameNotFoundException {
int idx = 0;
if (splitName != null) {
idx = Arrays.binarySearch(mSplitNames, splitName);
if (idx < 0) {
throw new PackageManager.NameNotFoundException(
"Split name '" + splitName + "' is not installed");
}
idx += 1;
}
loadDependenciesForSplit(idx);
return idx;
}
ClassLoader getClassLoaderForSplit(String splitName) throws NameNotFoundException {
return mCachedClassLoaders[ensureSplitLoaded(splitName)];
}
String[] getSplitPathsForSplit(String splitName) throws NameNotFoundException {
return mCachedResourcePaths[ensureSplitLoaded(splitName)];
}
}
private SplitDependencyLoaderImpl mSplitLoader;
ClassLoader getSplitClassLoader(String splitName) throws NameNotFoundException {
if (mSplitLoader == null) {
return mClassLoader;
}
return mSplitLoader.getClassLoaderForSplit(splitName);
}
String[] getSplitPaths(String splitName) throws NameNotFoundException {
if (mSplitLoader == null) {
return mSplitResDirs;
}
return mSplitLoader.getSplitPathsForSplit(splitName);
}
private void createOrUpdateClassLoaderLocked(List<String> addedPaths) {
if (mPackageName.equals("android")) {
if (mClassLoader != null) {
return;
}
if (mBaseClassLoader != null) {
mClassLoader = mBaseClassLoader;
} else {
mClassLoader = ClassLoader.getSystemClassLoader();
}
mAppComponentFactory = createAppFactory(mApplicationInfo, mClassLoader);
return;
}
if (!Objects.equals(mPackageName, ActivityThread.currentPackageName()) && mIncludeCode) {
try {
ActivityThread.getPackageManager().notifyPackageUse(mPackageName,
PackageManager.NOTIFY_PACKAGE_USE_CROSS_PACKAGE);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
}
if (mRegisterPackage) {
try {
ActivityManager.getService().addPackageDependency(mPackageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
final List<String> zipPaths = new ArrayList<>(10);
final List<String> libPaths = new ArrayList<>(10);
boolean isBundledApp = mApplicationInfo.isSystemApp()
&& !mApplicationInfo.isUpdatedSystemApp();
final String defaultSearchPaths = System.getProperty("java.library.path");
final boolean treatVendorApkAsUnbundled = !defaultSearchPaths.contains("/vendor/lib");
if (mApplicationInfo.getCodePath() != null
&& mApplicationInfo.isVendor() && treatVendorApkAsUnbundled) {
isBundledApp = false;
}
makePaths(mActivityThread, isBundledApp, mApplicationInfo, zipPaths, libPaths);
String libraryPermittedPath = mDataDir;
if (isBundledApp) {
libraryPermittedPath += File.pathSeparator
+ Paths.get(getAppDir()).getParent().toString();
libraryPermittedPath += File.pathSeparator + defaultSearchPaths;
}
final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);
if (!mIncludeCode) {
if (mClassLoader == null) {
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
mClassLoader = ApplicationLoaders.getDefault().getClassLoader(
"" , mApplicationInfo.targetSdkVersion, isBundledApp,
librarySearchPath, libraryPermittedPath, mBaseClassLoader,
null );
StrictMode.setThreadPolicy(oldPolicy);
mAppComponentFactory = AppComponentFactory.DEFAULT;
}
return;
}
final String zip = (zipPaths.size() == 1) ? zipPaths.get(0) :
TextUtils.join(File.pathSeparator, zipPaths);
if (DEBUG) Slog.v(ActivityThread.TAG, "Class path: " + zip +
", JNI path: " + librarySearchPath);
boolean needToSetupJitProfiles = false;
if (mClassLoader == null) {
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip,
mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
libraryPermittedPath, mBaseClassLoader,
mApplicationInfo.classLoaderName);
mAppComponentFactory = createAppFactory(mApplicationInfo, mClassLoader);
StrictMode.setThreadPolicy(oldPolicy);
needToSetupJitProfiles = true;
}
if (!libPaths.isEmpty() && SystemProperties.getBoolean(PROPERTY_NAME_APPEND_NATIVE, true)) {
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
try {
ApplicationLoaders.getDefault().addNative(mClassLoader, libPaths);
} finally {
StrictMode.setThreadPolicy(oldPolicy);
}
}
List<String> extraLibPaths = new ArrayList<>(3);
String abiSuffix = VMRuntime.getRuntime().is64Bit() ? "64" : "";
if (!defaultSearchPaths.contains("/vendor/lib")) {
extraLibPaths.add("/vendor/lib" + abiSuffix);
}
if (!defaultSearchPaths.contains("/odm/lib")) {
extraLibPaths.add("/odm/lib" + abiSuffix);
}
if (!defaultSearchPaths.contains("/product/lib")) {
extraLibPaths.add("/product/lib" + abiSuffix);
}
if (!extraLibPaths.isEmpty()) {
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
try {
ApplicationLoaders.getDefault().addNative(mClassLoader, extraLibPaths);
} finally {
StrictMode.setThreadPolicy(oldPolicy);
}
}
if (addedPaths != null && addedPaths.size() > 0) {
final String add = TextUtils.join(File.pathSeparator, addedPaths);
ApplicationLoaders.getDefault().addPath(mClassLoader, add);
needToSetupJitProfiles = true;
}
if (needToSetupJitProfiles && !ActivityThread.isSystem()) {
setupJitProfileSupport();
}
}
public ClassLoader getClassLoader() {
synchronized (this) {
if (mClassLoader == null) {
createOrUpdateClassLoaderLocked(null );
}
return mClassLoader;
}
}
private void setupJitProfileSupport() {
if (!SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false)) {
return;
}
if (mApplicationInfo.uid != Process.myUid()) {
return;
}
final List<String> codePaths = new ArrayList<>();
if ((mApplicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) {
codePaths.add(mApplicationInfo.sourceDir);
}
if (mApplicationInfo.splitSourceDirs != null) {
Collections.addAll(codePaths, mApplicationInfo.splitSourceDirs);
}
if (codePaths.isEmpty()) {
return;
}
for (int i = codePaths.size() - 1; i >= 0; i--) {
String splitName = i == 0 ? null : mApplicationInfo.splitNames[i - 1];
String profileFile = ArtManager.getCurrentProfilePath(
mPackageName, UserHandle.myUserId(), splitName);
VMRuntime.registerAppInfo(profileFile, new String[] {codePaths.get(i)});
}
DexLoadReporter.getInstance().registerAppDataDir(mPackageName, mDataDir);
}
private void initializeJavaContextClassLoader() {
IPackageManager pm = ActivityThread.getPackageManager();
android.content.pm.PackageInfo pi;
try {
pi = pm.getPackageInfo(mPackageName, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
UserHandle.myUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
if (pi == null) {
throw new IllegalStateException("Unable to get package info for "
+ mPackageName + "; is package not installed?");
}
boolean sharedUserIdSet = (pi.sharedUserId != null);
boolean processNameNotDefault =
(pi.applicationInfo != null &&
!mPackageName.equals(pi.applicationInfo.processName));
boolean sharable = (sharedUserIdSet || processNameNotDefault);
ClassLoader contextClassLoader =
(sharable)
? new WarningContextClassLoader()
: mClassLoader;
Thread.currentThread().setContextClassLoader(contextClassLoader);
}
private static class WarningContextClassLoader extends ClassLoader {
private static boolean warned = false;
private void warn(String methodName) {
if (warned) {
return;
}
warned = true;
Thread.currentThread().setContextClassLoader(getParent());
Slog.w(ActivityThread.TAG, "ClassLoader." + methodName + ": " +
"The class loader returned by " +
"Thread.getContextClassLoader() may fail for processes " +
"that host multiple applications. You should explicitly " +
"specify a context class loader. For example: " +
"Thread.setContextClassLoader(getClass().getClassLoader());");
}
@Override public URL getResource(String resName) {
warn("getResource");
return getParent().getResource(resName);
}
@Override public Enumeration<URL> getResources(String resName) throws IOException {
warn("getResources");
return getParent().getResources(resName);
}
@Override public InputStream getResourceAsStream(String resName) {
warn("getResourceAsStream");
return getParent().getResourceAsStream(resName);
}
@Override public Class<?> loadClass(String className) throws ClassNotFoundException {
warn("loadClass");
return getParent().loadClass(className);
}
@Override public void setClassAssertionStatus(String cname, boolean enable) {
warn("setClassAssertionStatus");
getParent().setClassAssertionStatus(cname, enable);
}
@Override public void setPackageAssertionStatus(String pname, boolean enable) {
warn("setPackageAssertionStatus");
getParent().setPackageAssertionStatus(pname, enable);
}
@Override public void setDefaultAssertionStatus(boolean enable) {
warn("setDefaultAssertionStatus");
getParent().setDefaultAssertionStatus(enable);
}
@Override public void clearAssertionStatus() {
warn("clearAssertionStatus");
getParent().clearAssertionStatus();
}
}
public String getAppDir() {
return mAppDir;
}
public String getLibDir() {
return mLibDir;
}
public String getResDir() {
return mResDir;
}
public String[] getSplitAppDirs() {
return mSplitAppDirs;
}
public String[] getSplitResDirs() {
return mSplitResDirs;
}
public String[] getOverlayDirs() {
return mOverlayDirs;
}
public String getDataDir() {
return mDataDir;
}
public File getDataDirFile() {
return mDataDirFile;
}
public File getDeviceProtectedDataDirFile() {
return mDeviceProtectedDataDirFile;
}
public File getCredentialProtectedDataDirFile() {
return mCredentialProtectedDataDirFile;
}
public AssetManager getAssets() {
return getResources().getAssets();
}
public Resources getResources() {
if (mResources == null) {
final String[] splitPaths;
try {
splitPaths = getSplitPaths(null);
} catch (NameNotFoundException e) {
throw new AssertionError("null split not found");
}
mResources = ResourcesManager.getInstance().getResources(null, mResDir,
splitPaths, mOverlayDirs, mApplicationInfo.sharedLibraryFiles,
Display.DEFAULT_DISPLAY, null, getCompatibilityInfo(),
getClassLoader());
}
return mResources;
}
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
if (mApplication != null) {
return mApplication;
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");
Application app = null;
String appClass = mApplicationInfo.className;
if (forceDefaultAppClass || (appClass == null)) {
appClass = "android.app.Application";
}
try {
java.lang.ClassLoader cl = getClassLoader();
if (!mPackageName.equals("android")) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
"initializeJavaContextClassLoader");
initializeJavaContextClassLoader();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
} catch (Exception e) {
if (!mActivityThread.mInstrumentation.onException(app, e)) {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
throw new RuntimeException(
"Unable to instantiate application " + appClass
+ ": " + e.toString(), e);
}
}
mActivityThread.mAllApplications.add(app);
mApplication = app;
if (instrumentation != null) {
try {
instrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
if (!instrumentation.onException(app, e)) {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
throw new RuntimeException(
"Unable to create application " + app.getClass().getName()
+ ": " + e.toString(), e);
}
}
}
SparseArray<String> packageIdentifiers = getAssets().getAssignedPackageIdentifiers();
final int N = packageIdentifiers.size();
for (int i = 0; i < N; i++) {
final int id = packageIdentifiers.keyAt(i);
if (id == 0x01 || id == 0x7f) {
continue;
}
rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id);
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
return app;
}
private void rewriteRValues(ClassLoader cl, String packageName, int id) {
final Class<?> rClazz;
try {
rClazz = cl.loadClass(packageName + ".R");
} catch (ClassNotFoundException e) {
Log.i(TAG, "No resource references to update in package " + packageName);
return;
}
final Method callback;
try {
callback = rClazz.getMethod("onResourcesLoaded", int.class);
} catch (NoSuchMethodException e) {
return;
}
Throwable cause;
try {
callback.invoke(null, id);
return;
} catch (IllegalAccessException e) {
cause = e;
} catch (InvocationTargetException e) {
cause = e.getCause();
}
throw new RuntimeException("Failed to rewrite resource references for " + packageName,
cause);
}
public void removeContextRegistrations(Context context,
String who, String what) {
final boolean reportRegistrationLeaks = StrictMode.vmRegistrationLeaksEnabled();
synchronized (mReceivers) {
ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> rmap =
mReceivers.remove(context);
if (rmap != null) {
for (int i = 0; i < rmap.size(); i++) {
LoadedApk.ReceiverDispatcher rd = rmap.valueAt(i);
IntentReceiverLeaked leak = new IntentReceiverLeaked(
what + " " + who + " has leaked IntentReceiver "
+ rd.getIntentReceiver() + " that was " +
"originally registered here. Are you missing a " +
"call to unregisterReceiver()?");
leak.setStackTrace(rd.getLocation().getStackTrace());
Slog.e(ActivityThread.TAG, leak.getMessage(), leak);
if (reportRegistrationLeaks) {
StrictMode.onIntentReceiverLeaked(leak);
}
try {
ActivityManager.getService().unregisterReceiver(
rd.getIIntentReceiver());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
mUnregisteredReceivers.remove(context);
}
synchronized (mServices) {
ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> smap =
mServices.remove(context);
if (smap != null) {
for (int i = 0; i < smap.size(); i++) {
LoadedApk.ServiceDispatcher sd = smap.valueAt(i);
ServiceConnectionLeaked leak = new ServiceConnectionLeaked(
what + " " + who + " has leaked ServiceConnection "
+ sd.getServiceConnection() + " that was originally bound here");
leak.setStackTrace(sd.getLocation().getStackTrace());
Slog.e(ActivityThread.TAG, leak.getMessage(), leak);
if (reportRegistrationLeaks) {
StrictMode.onServiceConnectionLeaked(leak);
}
try {
ActivityManager.getService().unbindService(
sd.getIServiceConnection());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
sd.doForget();
}
}
mUnboundServices.remove(context);
}
}
public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
Context context, Handler handler,
Instrumentation instrumentation, boolean registered) {
synchronized (mReceivers) {
LoadedApk.ReceiverDispatcher rd = null;
ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
if (registered) {
map = mReceivers.get(context);
if (map != null) {
rd = map.get(r);
}
}
if (rd == null) {
rd = new ReceiverDispatcher(r, context, handler,
instrumentation, registered);
if (registered) {
if (map == null) {
map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
mReceivers.put(context, map);
}
map.put(r, rd);
}
} else {
rd.validate(context, handler);
}
rd.mForgotten = false;
return rd.getIIntentReceiver();
}
}
public IIntentReceiver forgetReceiverDispatcher(Context context,
BroadcastReceiver r) {
synchronized (mReceivers) {
ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = mReceivers.get(context);
LoadedApk.ReceiverDispatcher rd = null;
if (map != null) {
rd = map.get(r);
if (rd != null) {
map.remove(r);
if (map.size() == 0) {
mReceivers.remove(context);
}
if (r.getDebugUnregister()) {
ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder
= mUnregisteredReceivers.get(context);
if (holder == null) {
holder = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
mUnregisteredReceivers.put(context, holder);
}
RuntimeException ex = new IllegalArgumentException(
"Originally unregistered here:");
ex.fillInStackTrace();
rd.setUnregisterLocation(ex);
holder.put(r, rd);
}
rd.mForgotten = true;
return rd.getIIntentReceiver();
}
}
ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder
= mUnregisteredReceivers.get(context);
if (holder != null) {
rd = holder.get(r);
if (rd != null) {
RuntimeException ex = rd.getUnregisterLocation();
throw new IllegalArgumentException(
"Unregistering Receiver " + r
+ " that was already unregistered", ex);
}
}
if (context == null) {
throw new IllegalStateException("Unbinding Receiver " + r
+ " from Context that is no longer in use: " + context);
} else {
throw new IllegalArgumentException("Receiver not registered: " + r);
}
}
}
static final class ReceiverDispatcher {
final static class InnerReceiver extends IIntentReceiver.Stub {
final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
final LoadedApk.ReceiverDispatcher mStrongRef;
InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
mStrongRef = strong ? rd : null;
}
@Override
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
final LoadedApk.ReceiverDispatcher rd;
if (intent == null) {
Log.wtf(TAG, "Null intent received");
rd = null;
} else {
rd = mDispatcher.get();
}
if (ActivityThread.DEBUG_BROADCAST) {
int seq = intent.getIntExtra("seq", -1);
Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction()
+ " seq=" + seq + " to " + (rd != null ? rd.mReceiver : null));
}
if (rd != null) {
rd.performReceive(intent, resultCode, data, extras,
ordered, sticky, sendingUser);
} else {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast to unregistered receiver");
IActivityManager mgr = ActivityManager.getService();
try {
if (extras != null) {
extras.setAllowFds(false);
}
mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
}
final IIntentReceiver.Stub mIIntentReceiver;
final BroadcastReceiver mReceiver;
final Context mContext;
final Handler mActivityThread;
final Instrumentation mInstrumentation;
final boolean mRegistered;
final IntentReceiverLeaked mLocation;
RuntimeException mUnregisterLocation;
boolean mForgotten;
final class Args extends BroadcastReceiver.PendingResult {
private Intent mCurIntent;
private final boolean mOrdered;
private boolean mDispatched;
private Throwable mPreviousRunStacktrace;
public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
boolean ordered, boolean sticky, int sendingUser) {
super(resultCode, resultData, resultExtras,
mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered,
sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags());
mCurIntent = intent;
mOrdered = ordered;
}
public final Runnable getRunnable() {
return () -> {
final BroadcastReceiver receiver = mReceiver;
final boolean ordered = mOrdered;
if (ActivityThread.DEBUG_BROADCAST) {
int seq = mCurIntent.getIntExtra("seq", -1);
Slog.i(ActivityThread.TAG, "Dispatching broadcast " + mCurIntent.getAction()
+ " seq=" + seq + " to " + mReceiver);
Slog.i(ActivityThread.TAG, " mRegistered=" + mRegistered
+ " mOrderedHint=" + ordered);
}
final IActivityManager mgr = ActivityManager.getService();
final Intent intent = mCurIntent;
if (intent == null) {
Log.wtf(TAG, "Null intent being dispatched, mDispatched=" + mDispatched
+ ": run() previously called at "
+ Log.getStackTraceString(mPreviousRunStacktrace));
}
mCurIntent = null;
mDispatched = true;
mPreviousRunStacktrace = new Throwable("Previous stacktrace");
if (receiver == null || intent == null || mForgotten) {
if (mRegistered && ordered) {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing null broadcast to " + mReceiver);
sendFinished(mgr);
}
return;
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg");
try {
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
intent.prepareToEnterProcess();
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);
} catch (Exception e) {
if (mRegistered && ordered) {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing failed broadcast to " + mReceiver);
sendFinished(mgr);
}
if (mInstrumentation == null ||
!mInstrumentation.onException(mReceiver, e)) {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
throw new RuntimeException(
"Error receiving broadcast " + intent
+ " in " + mReceiver, e);
}
}
if (receiver.getPendingResult() != null) {
finish();
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
};
}
}
ReceiverDispatcher(BroadcastReceiver receiver, Context context,
Handler activityThread, Instrumentation instrumentation,
boolean registered) {
if (activityThread == null) {
throw new NullPointerException("Handler must not be null");
}
mIIntentReceiver = new InnerReceiver(this, !registered);
mReceiver = receiver;
mContext = context;
mActivityThread = activityThread;
mInstrumentation = instrumentation;
mRegistered = registered;
mLocation = new IntentReceiverLeaked(null);
mLocation.fillInStackTrace();
}
void validate(Context context, Handler activityThread) {
if (mContext != context) {
throw new IllegalStateException(
"Receiver " + mReceiver +
" registered with differing Context (was " +
mContext + " now " + context + ")");
}
if (mActivityThread != activityThread) {
throw new IllegalStateException(
"Receiver " + mReceiver +
" registered with differing handler (was " +
mActivityThread + " now " + activityThread + ")");
}
}
IntentReceiverLeaked getLocation() {
return mLocation;
}
BroadcastReceiver getIntentReceiver() {
return mReceiver;
}
IIntentReceiver getIIntentReceiver() {
return mIIntentReceiver;
}
void setUnregisterLocation(RuntimeException ex) {
mUnregisterLocation = ex;
}
RuntimeException getUnregisterLocation() {
return mUnregisterLocation;
}
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
final Args args = new Args(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
if (intent == null) {
Log.wtf(TAG, "Null intent received");
} else {
if (ActivityThread.DEBUG_BROADCAST) {
int seq = intent.getIntExtra("seq", -1);
Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction()
+ " seq=" + seq + " to " + mReceiver);
}
}
if (intent == null || !mActivityThread.post(args.getRunnable())) {
if (mRegistered && ordered) {
IActivityManager mgr = ActivityManager.getService();
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing sync broadcast to " + mReceiver);
args.sendFinished(mgr);
}
}
}
}
public final IServiceConnection getServiceDispatcher(ServiceConnection c,
Context context, Handler handler, int flags) {
synchronized (mServices) {
LoadedApk.ServiceDispatcher sd = null;
ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
if (map != null) {
if (DEBUG) Slog.d(TAG, "Returning existing dispatcher " + sd + " for conn " + c);
sd = map.get(c);
}
if (sd == null) {
sd = new ServiceDispatcher(c, context, handler, flags);
if (DEBUG) Slog.d(TAG, "Creating new dispatcher " + sd + " for conn " + c);
if (map == null) {
map = new ArrayMap<>();
mServices.put(context, map);
}
map.put(c, sd);
} else {
sd.validate(context, handler);
}
return sd.getIServiceConnection();
}
}
public final IServiceConnection forgetServiceDispatcher(Context context,
ServiceConnection c) {
synchronized (mServices) {
ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map
= mServices.get(context);
LoadedApk.ServiceDispatcher sd = null;
if (map != null) {
sd = map.get(c);
if (sd != null) {
if (DEBUG) Slog.d(TAG, "Removing dispatcher " + sd + " for conn " + c);
map.remove(c);
sd.doForget();
if (map.size() == 0) {
mServices.remove(context);
}
if ((sd.getFlags()&Context.BIND_DEBUG_UNBIND) != 0) {
ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder
= mUnboundServices.get(context);
if (holder == null) {
holder = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
mUnboundServices.put(context, holder);
}
RuntimeException ex = new IllegalArgumentException(
"Originally unbound here:");
ex.fillInStackTrace();
sd.setUnbindLocation(ex);
holder.put(c, sd);
}
return sd.getIServiceConnection();
}
}
ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder
= mUnboundServices.get(context);
if (holder != null) {
sd = holder.get(c);
if (sd != null) {
RuntimeException ex = sd.getUnbindLocation();
throw new IllegalArgumentException(
"Unbinding Service " + c
+ " that was already unbound", ex);
}
}
if (context == null) {
throw new IllegalStateException("Unbinding Service " + c
+ " from Context that is no longer in use: " + context);
} else {
throw new IllegalArgumentException("Service not registered: " + c);
}
}
}
static final class ServiceDispatcher {
private final ServiceDispatcher.InnerConnection mIServiceConnection;
private final ServiceConnection mConnection;
private final Context mContext;
private final Handler mActivityThread;
private final ServiceConnectionLeaked mLocation;
private final int mFlags;
private RuntimeException mUnbindLocation;
private boolean mForgotten;
private static class ConnectionInfo {
IBinder binder;
IBinder.DeathRecipient deathMonitor;
}
private static class InnerConnection extends IServiceConnection.Stub {
final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
InnerConnection(LoadedApk.ServiceDispatcher sd) {
mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
}
public void connected(ComponentName name, IBinder service, boolean dead)
throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null) {
sd.connected(name, service, dead);
}
}
}
private final ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections
= new ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo>();
ServiceDispatcher(ServiceConnection conn,
Context context, Handler activityThread, int flags) {
mIServiceConnection = new InnerConnection(this);
mConnection = conn;
mContext = context;
mActivityThread = activityThread;
mLocation = new ServiceConnectionLeaked(null);
mLocation.fillInStackTrace();
mFlags = flags;
}
void validate(Context context, Handler activityThread) {
if (mContext != context) {
throw new RuntimeException(
"ServiceConnection " + mConnection +
" registered with differing Context (was " +
mContext + " now " + context + ")");
}
if (mActivityThread != activityThread) {
throw new RuntimeException(
"ServiceConnection " + mConnection +
" registered with differing handler (was " +
mActivityThread + " now " + activityThread + ")");
}
}
void doForget() {
synchronized(this) {
for (int i=0; i<mActiveConnections.size(); i++) {
ServiceDispatcher.ConnectionInfo ci = mActiveConnections.valueAt(i);
ci.binder.unlinkToDeath(ci.deathMonitor, 0);
}
mActiveConnections.clear();
mForgotten = true;
}
}
ServiceConnectionLeaked getLocation() {
return mLocation;
}
ServiceConnection getServiceConnection() {
return mConnection;
}
IServiceConnection getIServiceConnection() {
return mIServiceConnection;
}
int getFlags() {
return mFlags;
}
void setUnbindLocation(RuntimeException ex) {
mUnbindLocation = ex;
}
RuntimeException getUnbindLocation() {
return mUnbindLocation;
}
public void connected(ComponentName name, IBinder service, boolean dead) {
if (mActivityThread != null) {
mActivityThread.post(new RunConnection(name, service, 0, dead));
} else {
doConnected(name, service, dead);
}
}
public void death(ComponentName name, IBinder service) {
if (mActivityThread != null) {
mActivityThread.post(new RunConnection(name, service, 1, false));
} else {
doDeath(name, service);
}
}
public void doConnected(ComponentName name, IBinder service, boolean dead) {
ServiceDispatcher.ConnectionInfo old;
ServiceDispatcher.ConnectionInfo info;
synchronized (this) {
if (mForgotten) {
return;
}
old = mActiveConnections.get(name);
if (old != null && old.binder == service) {
return;
}
if (service != null) {
info = new ConnectionInfo();
info.binder = service;
info.deathMonitor = new DeathMonitor(name, service);
try {
service.linkToDeath(info.deathMonitor, 0);
mActiveConnections.put(name, info);
} catch (RemoteException e) {
mActiveConnections.remove(name);
return;
}
} else {
mActiveConnections.remove(name);
}
if (old != null) {
old.binder.unlinkToDeath(old.deathMonitor, 0);
}
}
if (old != null) {
mConnection.onServiceDisconnected(name);
}
if (dead) {
mConnection.onBindingDied(name);
}
if (service != null) {
mConnection.onServiceConnected(name, service);
} else {
mConnection.onNullBinding(name);
}
}
public void doDeath(ComponentName name, IBinder service) {
synchronized (this) {
ConnectionInfo old = mActiveConnections.get(name);
if (old == null || old.binder != service) {
return;
}
mActiveConnections.remove(name);
old.binder.unlinkToDeath(old.deathMonitor, 0);
}
mConnection.onServiceDisconnected(name);
}
private final class RunConnection implements Runnable {
RunConnection(ComponentName name, IBinder service, int command, boolean dead) {
mName = name;
mService = service;
mCommand = command;
mDead = dead;
}
public void run() {
if (mCommand == 0) {
doConnected(mName, mService, mDead);
} else if (mCommand == 1) {
doDeath(mName, mService);
}
}
final ComponentName mName;
final IBinder mService;
final int mCommand;
final boolean mDead;
}
private final class DeathMonitor implements IBinder.DeathRecipient
{
DeathMonitor(ComponentName name, IBinder service) {
mName = name;
mService = service;
}
public void binderDied() {
death(mName, mService);
}
final ComponentName mName;
final IBinder mService;
}
}
}