diff options
18 files changed, 205 insertions, 132 deletions
diff --git a/api/current.txt b/api/current.txt index 38bb68be55a9..cfec8d27258c 100644 --- a/api/current.txt +++ b/api/current.txt @@ -388,6 +388,7 @@ package android { field public static final int childIndicatorRight = 16843024; // 0x1010110 field public static final int childIndicatorStart = 16843731; // 0x10103d3 field public static final int choiceMode = 16843051; // 0x101012b + field public static final int classLoader = 16844139; // 0x101056b field public static final int clearTaskOnLaunch = 16842773; // 0x1010015 field public static final int clickable = 16842981; // 0x10100e5 field public static final int clipChildren = 16842986; // 0x10100ea diff --git a/api/system-current.txt b/api/system-current.txt index d98319cc9c79..de632fda8b23 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -511,6 +511,7 @@ package android { field public static final int childIndicatorRight = 16843024; // 0x1010110 field public static final int childIndicatorStart = 16843731; // 0x10103d3 field public static final int choiceMode = 16843051; // 0x101012b + field public static final int classLoader = 16844139; // 0x101056b field public static final int clearTaskOnLaunch = 16842773; // 0x1010015 field public static final int clickable = 16842981; // 0x10100e5 field public static final int clipChildren = 16842986; // 0x10100ea diff --git a/api/test-current.txt b/api/test-current.txt index 94bfe84c88d0..4616c0bd859a 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -388,6 +388,7 @@ package android { field public static final int childIndicatorRight = 16843024; // 0x1010110 field public static final int childIndicatorStart = 16843731; // 0x10103d3 field public static final int choiceMode = 16843051; // 0x101012b + field public static final int classLoader = 16844139; // 0x101056b field public static final int clearTaskOnLaunch = 16842773; // 0x1010015 field public static final int clickable = 16842981; // 0x10100e5 field public static final int clipChildren = 16842986; // 0x10100ea diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index ad989dee7b55..f0189c240a85 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -414,7 +414,7 @@ public final class Pm { try { ApkLite baseApk = PackageParser.parseApkLite(file, 0); PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null, - null, null); + null, null, null); params.sessionParams.setSize( PackageHelper.calculateInstalledSize(pkgLite, false, params.sessionParams.abiOverride)); diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java index 2062930929a2..b7c1f4e082e2 100644 --- a/core/java/android/app/ApplicationLoaders.java +++ b/core/java/android/app/ApplicationLoaders.java @@ -18,9 +18,8 @@ package android.app; import android.os.Build; import android.os.Trace; -import android.text.TextUtils; import android.util.ArrayMap; -import com.android.internal.os.PathClassLoaderFactory; +import com.android.internal.os.ClassLoaderFactory; import dalvik.system.PathClassLoader; /** @hide */ @@ -31,15 +30,16 @@ public class ApplicationLoaders { ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, - ClassLoader parent) { + ClassLoader parent, String classLoaderName) { // For normal usage the cache key used is the same as the zip path. return getClassLoader(zip, targetSdkVersion, isBundled, librarySearchPath, - libraryPermittedPath, parent, zip); + libraryPermittedPath, parent, zip, classLoaderName); } private ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, - ClassLoader parent, String cacheKey) { + ClassLoader parent, String cacheKey, + String classLoaderName) { /* * This is the parent we use if they pass "null" in. In theory * this should be the "system" class loader; in practice we @@ -66,28 +66,25 @@ public class ApplicationLoaders { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip); - PathClassLoader pathClassloader = PathClassLoaderFactory.createClassLoader( - zip, - librarySearchPath, - libraryPermittedPath, - parent, - targetSdkVersion, - isBundled); + ClassLoader classloader = ClassLoaderFactory.createClassLoader( + zip, librarySearchPath, libraryPermittedPath, parent, + targetSdkVersion, isBundled, classLoaderName); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "setupVulkanLayerPath"); - setupVulkanLayerPath(pathClassloader, librarySearchPath); + setupVulkanLayerPath(classloader, librarySearchPath); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - mLoaders.put(cacheKey, pathClassloader); - return pathClassloader; + mLoaders.put(cacheKey, classloader); + return classloader; } Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip); - PathClassLoader pathClassloader = new PathClassLoader(zip, parent); + ClassLoader loader = ClassLoaderFactory.createClassLoader( + zip, null, parent, classLoaderName); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - return pathClassloader; + return loader; } } @@ -105,7 +102,7 @@ public class ApplicationLoaders { // The cache key is passed separately to enable the stub WebView to be cached under the // stub's APK path, when the actual package path is the donor APK. return getClassLoader(packagePath, Build.VERSION.SDK_INT, false, libsPath, null, null, - cacheKey); + cacheKey, null /* classLoaderName */); } private static native void setupVulkanLayerPath(ClassLoader classLoader, String librarySearchPath); @@ -122,7 +119,7 @@ public class ApplicationLoaders { baseDexClassLoader.addDexPath(dexPath); } - private final ArrayMap<String, ClassLoader> mLoaders = new ArrayMap<String, ClassLoader>(); + private final ArrayMap<String, ClassLoader> mLoaders = new ArrayMap<>(); private static final ApplicationLoaders gApplicationLoaders = new ApplicationLoaders(); } diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index 79e5407a17d3..b38be6626e50 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -97,7 +97,6 @@ public final class LoadedApk { private String mAppDir; private String mResDir; private String[] mOverlayDirs; - private String[] mSharedLibraries; private String mDataDir; private String mLibDir; private File mDataDirFile; @@ -116,6 +115,7 @@ public final class LoadedApk { private String[] mSplitNames; private String[] mSplitAppDirs; private String[] mSplitResDirs; + private String[] mSplitClassLoaderNames; private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers = new ArrayMap<>(); @@ -126,8 +126,6 @@ public final class LoadedApk { private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mUnboundServices = new ArrayMap<>(); - int mClientCount = 0; - Application getApplication() { return mApplication; } @@ -192,8 +190,8 @@ public final class LoadedApk { mResDir = null; mSplitAppDirs = null; mSplitResDirs = null; + mSplitClassLoaderNames = null; mOverlayDirs = null; - mSharedLibraries = null; mDataDir = null; mDataDirFile = null; mDeviceProtectedDataDirFile = null; @@ -324,7 +322,6 @@ public final class LoadedApk { mAppDir = aInfo.sourceDir; mResDir = aInfo.uid == myUid ? aInfo.sourceDir : aInfo.publicSourceDir; mOverlayDirs = aInfo.resourceDirs; - mSharedLibraries = aInfo.sharedLibraryFiles; mDataDir = aInfo.dataDir; mLibDir = aInfo.nativeLibraryDir; mDataDirFile = FileUtils.newFileOrNull(aInfo.dataDir); @@ -334,6 +331,7 @@ public final class LoadedApk { 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); @@ -530,7 +528,8 @@ public final class LoadedApk { // Since we handled the special base case above, parentSplitIdx is always valid. final ClassLoader parent = mCachedClassLoaders[parentSplitIdx]; mCachedClassLoaders[splitIdx] = ApplicationLoaders.getDefault().getClassLoader( - mSplitAppDirs[splitIdx - 1], getTargetSdkVersion(), false, null, null, parent); + mSplitAppDirs[splitIdx - 1], getTargetSdkVersion(), false, null, null, parent, + mSplitClassLoaderNames[splitIdx - 1]); Collections.addAll(splitPaths, mCachedResourcePaths[parentSplitIdx]); splitPaths.add(mSplitResDirs[splitIdx - 1]); @@ -650,8 +649,9 @@ public final class LoadedApk { if (mClassLoader == null) { StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); mClassLoader = ApplicationLoaders.getDefault().getClassLoader( - "" /* codePath */, mApplicationInfo.targetSdkVersion, isBundledApp, - librarySearchPath, libraryPermittedPath, mBaseClassLoader); + "" /* codePath */, mApplicationInfo.targetSdkVersion, isBundledApp, + librarySearchPath, libraryPermittedPath, mBaseClassLoader, + null /* classLoaderName */); StrictMode.setThreadPolicy(oldPolicy); } @@ -678,7 +678,8 @@ public final class LoadedApk { mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip, mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath, - libraryPermittedPath, mBaseClassLoader); + libraryPermittedPath, mBaseClassLoader, + mApplicationInfo.classLoaderName); StrictMode.setThreadPolicy(oldPolicy); // Setup the class loader paths for profiling. diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 06f7916be4b6..0bfe56797d22 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -1005,6 +1005,12 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { } } + /** @hide */ + public String classLoaderName; + + /** @hide */ + public String[] splitClassLoaderNames; + public void dump(Printer pw, String prefix) { dump(pw, prefix, DUMP_FLAG_ALL); } @@ -1056,6 +1062,13 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { pw.println(prefix + "sharedLibraryFiles=" + Arrays.toString(sharedLibraryFiles)); } } + if (classLoaderName != null) { + pw.println(prefix + "classLoaderName=" + classLoaderName); + } + if (!ArrayUtils.isEmpty(splitClassLoaderNames)) { + pw.println(prefix + "splitClassLoaderNames=" + Arrays.toString(splitClassLoaderNames)); + } + pw.println(prefix + "enabled=" + enabled + " minSdkVersion=" + minSdkVersion + " targetSdkVersion=" + targetSdkVersion @@ -1178,6 +1191,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { networkSecurityConfigRes = orig.networkSecurityConfigRes; category = orig.category; targetSandboxVersion = orig.targetSandboxVersion; + classLoaderName = orig.classLoaderName; + splitClassLoaderNames = orig.splitClassLoaderNames; } public String toString() { @@ -1246,6 +1261,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { dest.writeInt(networkSecurityConfigRes); dest.writeInt(category); dest.writeInt(targetSandboxVersion); + dest.writeString(classLoaderName); + dest.writeStringArray(splitClassLoaderNames); } public static final Parcelable.Creator<ApplicationInfo> CREATOR @@ -1311,6 +1328,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { networkSecurityConfigRes = source.readInt(); category = source.readInt(); targetSandboxVersion = source.readInt(); + classLoaderName = source.readString(); + splitClassLoaderNames = source.readStringArray(); } /** diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index e4f2fc1c5035..eb6e0d8bd4de 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -88,6 +88,7 @@ import android.view.Gravity; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.os.ClassLoaderFactory; import com.android.internal.util.ArrayUtils; import com.android.internal.util.XmlUtils; @@ -415,9 +416,12 @@ public class PackageParser { public final boolean extractNativeLibs; public final boolean isolatedSplits; + public final String classLoaderName; + public final String[] splitClassLoaderNames; + public PackageLite(String codePath, ApkLite baseApk, String[] splitNames, boolean[] isFeatureSplits, String[] usesSplitNames, String[] configForSplit, - String[] splitCodePaths, int[] splitRevisionCodes) { + String[] splitCodePaths, int[] splitRevisionCodes, String[] splitClassLoaderNames) { this.packageName = baseApk.packageName; this.versionCode = baseApk.versionCode; this.installLocation = baseApk.installLocation; @@ -437,6 +441,9 @@ public class PackageParser { this.use32bitAbi = baseApk.use32bitAbi; this.extractNativeLibs = baseApk.extractNativeLibs; this.isolatedSplits = baseApk.isolatedSplits; + + this.classLoaderName = baseApk.classLoaderName; + this.splitClassLoaderNames = splitClassLoaderNames; } public List<String> getAllCodePaths() { @@ -471,13 +478,14 @@ public class PackageParser { public final boolean use32bitAbi; public final boolean extractNativeLibs; public final boolean isolatedSplits; + public final String classLoaderName; public ApkLite(String codePath, String packageName, String splitName, boolean isFeatureSplit, String configForSplit, String usesSplitName, int versionCode, int revisionCode, int installLocation, List<VerifierInfo> verifiers, Signature[] signatures, Certificate[][] certificates, boolean coreApp, boolean debuggable, boolean multiArch, boolean use32bitAbi, boolean extractNativeLibs, - boolean isolatedSplits) { + boolean isolatedSplits, String classLoaderName) { this.codePath = codePath; this.packageName = packageName; this.splitName = splitName; @@ -496,6 +504,7 @@ public class PackageParser { this.use32bitAbi = use32bitAbi; this.extractNativeLibs = extractNativeLibs; this.isolatedSplits = isolatedSplits; + this.classLoaderName = classLoaderName; } } @@ -863,7 +872,7 @@ public class PackageParser { final ApkLite baseApk = parseApkLite(packageFile, flags); final String packagePath = packageFile.getAbsolutePath(); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); - return new PackageLite(packagePath, baseApk, null, null, null, null, null, null); + return new PackageLite(packagePath, baseApk, null, null, null, null, null, null, null); } static PackageLite parseClusterPackageLite(File packageDir, int flags) @@ -926,6 +935,7 @@ public class PackageParser { String[] configForSplits = null; String[] splitCodePaths = null; int[] splitRevisionCodes = null; + String[] splitClassLoaderNames = null; if (size > 0) { splitNames = new String[size]; isFeatureSplits = new boolean[size]; @@ -933,6 +943,7 @@ public class PackageParser { configForSplits = new String[size]; splitCodePaths = new String[size]; splitRevisionCodes = new int[size]; + splitClassLoaderNames = new String[size]; splitNames = apks.keySet().toArray(splitNames); Arrays.sort(splitNames, sSplitNameComparator); @@ -944,12 +955,13 @@ public class PackageParser { configForSplits[i] = apk.configForSplit; splitCodePaths[i] = apk.codePath; splitRevisionCodes[i] = apk.revisionCode; + splitClassLoaderNames[i] = apk.classLoaderName; } } final String codePath = packageDir.getAbsolutePath(); return new PackageLite(codePath, baseApk, splitNames, isFeatureSplits, usesSplitNames, - configForSplits, splitCodePaths, splitRevisionCodes); + configForSplits, splitCodePaths, splitRevisionCodes, splitClassLoaderNames); } /** @@ -1187,6 +1199,8 @@ public class PackageParser { pkg.splitPrivateFlags = new int[num]; pkg.applicationInfo.splitNames = pkg.splitNames; pkg.applicationInfo.splitDependencies = splitDependencies; + pkg.applicationInfo.classLoaderName = lite.classLoaderName; + pkg.applicationInfo.splitClassLoaderNames = lite.splitClassLoaderNames; for (int i = 0; i < num; i++) { final AssetManager splitAssets = assetLoader.getSplitAssetManager(i); @@ -1697,7 +1711,7 @@ public class PackageParser { } final AttributeSet attrs = parser; - return parseApkLite(apkPath, parser, attrs, flags, signatures, certificates); + return parseApkLite(apkPath, parser, attrs, signatures, certificates); } catch (XmlPullParserException | IOException | RuntimeException e) { Slog.w(TAG, "Failed to parse " + apkPath, e); @@ -1784,7 +1798,7 @@ public class PackageParser { } private static ApkLite parseApkLite(String codePath, XmlPullParser parser, AttributeSet attrs, - int flags, Signature[] signatures, Certificate[][] certificates) + Signature[] signatures, Certificate[][] certificates) throws IOException, XmlPullParserException, PackageParserException { final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs); @@ -1800,6 +1814,7 @@ public class PackageParser { boolean isFeatureSplit = false; String configForSplit = null; String usesSplitName = null; + String classLoaderName = null; for (int i = 0; i < attrs.getAttributeCount(); i++) { final String attr = attrs.getAttributeName(i); @@ -1856,6 +1871,14 @@ public class PackageParser { if ("extractNativeLibs".equals(attr)) { extractNativeLibs = attrs.getAttributeBooleanValue(i, true); } + if ("classLoader".equals(attr)) { + classLoaderName = attrs.getAttributeValue(i); + if (!ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) { + throw new PackageParserException( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Invalid class loader name: " + classLoaderName); + } + } } } else if (TAG_USES_SPLIT.equals(parser.getName())) { if (usesSplitName != null) { @@ -1875,19 +1898,7 @@ public class PackageParser { return new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit, configForSplit, usesSplitName, versionCode, revisionCode, installLocation, verifiers, signatures, certificates, coreApp, debuggable, multiArch, use32bitAbi, - extractNativeLibs, isolatedSplits); - } - - /** - * Temporary. - */ - static public Signature stringToSignature(String str) { - final int N = str.length(); - byte[] sig = new byte[N]; - for (int i=0; i<N; i++) { - sig[i] = (byte)str.charAt(i); - } - return new Signature(sig); + extractNativeLibs, isolatedSplits, classLoaderName); } /** diff --git a/core/java/com/android/internal/os/ClassLoaderFactory.java b/core/java/com/android/internal/os/ClassLoaderFactory.java new file mode 100644 index 000000000000..0c041f24b28d --- /dev/null +++ b/core/java/com/android/internal/os/ClassLoaderFactory.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.os; + +import android.os.Trace; + +import dalvik.system.DelegateLastClassLoader; +import dalvik.system.PathClassLoader; + +/** + * Creates class loaders. + * + * @hide + */ +public class ClassLoaderFactory { + // Unconstructable + private ClassLoaderFactory() {} + + private static final String PATH_CLASS_LOADER_NAME = PathClassLoader.class.getName(); + private static final String DELEGATE_LAST_CLASS_LOADER_NAME = + DelegateLastClassLoader.class.getName(); + + /** + * Returns true if {@code name} is a supported classloader. {@code name} must be a + * binary name of a class, as defined by {@code Class.getName}. + */ + public static boolean isValidClassLoaderName(String name) { + return PATH_CLASS_LOADER_NAME.equals(name) || + DELEGATE_LAST_CLASS_LOADER_NAME.equals(name); + } + + /** + * Same as {@code createClassLoader} below, except that no associated namespace + * is created. + */ + public static ClassLoader createClassLoader(String dexPath, + String librarySearchPath, ClassLoader parent, String classloaderName) { + if (classloaderName == null || PATH_CLASS_LOADER_NAME.equals(classloaderName)) { + return new PathClassLoader(dexPath, librarySearchPath, parent); + } else if (DELEGATE_LAST_CLASS_LOADER_NAME.equals(classloaderName)) { + return new DelegateLastClassLoader(dexPath, librarySearchPath, parent); + } + + throw new AssertionError("Invalid classLoaderName: " + classloaderName); + } + + /** + * Create a ClassLoader and initialize a linker-namespace for it. + */ + public static ClassLoader createClassLoader(String dexPath, + String librarySearchPath, String libraryPermittedPath, ClassLoader parent, + int targetSdkVersion, boolean isNamespaceShared, String classloaderName) { + + final ClassLoader classLoader = createClassLoader(dexPath, librarySearchPath, parent, + classloaderName); + + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "createClassloaderNamespace"); + String errorMessage = createClassloaderNamespace(classLoader, + targetSdkVersion, + librarySearchPath, + libraryPermittedPath, + isNamespaceShared); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); + + if (errorMessage != null) { + throw new UnsatisfiedLinkError("Unable to create namespace for the classloader " + + classLoader + ": " + errorMessage); + } + + return classLoader; + } + + private static native String createClassloaderNamespace(ClassLoader classLoader, + int targetSdkVersion, + String librarySearchPath, + String libraryPermittedPath, + boolean isNamespaceShared); +} diff --git a/core/java/com/android/internal/os/PathClassLoaderFactory.java b/core/java/com/android/internal/os/PathClassLoaderFactory.java deleted file mode 100644 index 06a93b254bf5..000000000000 --- a/core/java/com/android/internal/os/PathClassLoaderFactory.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.os; - -import android.os.Trace; - -import dalvik.system.PathClassLoader; - -/** - * Creates path class loaders. - * - * @hide - */ -public class PathClassLoaderFactory { - // Unconstructable - private PathClassLoaderFactory() {} - - /** - * Create a PathClassLoader and initialize a linker-namespace for it. - * - * @hide - */ - public static PathClassLoader createClassLoader(String dexPath, - String librarySearchPath, - String libraryPermittedPath, - ClassLoader parent, - int targetSdkVersion, - boolean isNamespaceShared) { - PathClassLoader pathClassloader = new PathClassLoader(dexPath, librarySearchPath, parent); - - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "createClassloaderNamespace"); - String errorMessage = createClassloaderNamespace(pathClassloader, - targetSdkVersion, - librarySearchPath, - libraryPermittedPath, - isNamespaceShared); - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - - if (errorMessage != null) { - throw new UnsatisfiedLinkError("Unable to create namespace for the classloader " + - pathClassloader + ": " + errorMessage); - } - - return pathClassloader; - } - - private static native String createClassloaderNamespace(ClassLoader classLoader, - int targetSdkVersion, - String librarySearchPath, - String libraryPermittedPath, - boolean isNamespaceShared); -} diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index 385976c187ed..77cd984bb4ef 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -24,7 +24,6 @@ import android.content.res.TypedArray; import android.icu.impl.CacheValue; import android.icu.text.DecimalFormatSymbols; import android.icu.util.ULocale; -import android.net.LocalServerSocket; import android.opengl.EGL14; import android.os.Build; import android.os.IInstalld; @@ -517,15 +516,12 @@ public class ZygoteInit { * namespace, i.e., this classloader can access platform-private native libraries. The * classloader will use java.library.path as the native library path. */ - static PathClassLoader createPathClassLoader(String classPath, int targetSdkVersion) { - String libraryPath = System.getProperty("java.library.path"); - - return PathClassLoaderFactory.createClassLoader(classPath, - libraryPath, - libraryPath, - ClassLoader.getSystemClassLoader(), - targetSdkVersion, - true /* isNamespaceShared */); + static ClassLoader createPathClassLoader(String classPath, int targetSdkVersion) { + String libraryPath = System.getProperty("java.library.path"); + + return ClassLoaderFactory.createClassLoader(classPath, libraryPath, libraryPath, + ClassLoader.getSystemClassLoader(), targetSdkVersion, true /* isNamespaceShared */, + null /* classLoaderName */); } /** diff --git a/core/jni/Android.bp b/core/jni/Android.bp index c4533c36d0f2..44dfb33effce 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -185,8 +185,8 @@ cc_library_shared { "android_content_res_Configuration.cpp", "android_animation_PropertyValuesHolder.cpp", "com_android_internal_net_NetworkStatsFactory.cpp", + "com_android_internal_os_ClassLoaderFactory.cpp", "com_android_internal_os_FuseAppLoop.cpp", - "com_android_internal_os_PathClassLoaderFactory.cpp", "com_android_internal_os_Zygote.cpp", "com_android_internal_util_VirtualRefBasePtr.cpp", "com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp", diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 89e137b7c399..30d4e0276bf0 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -203,8 +203,8 @@ extern int register_android_content_res_Configuration(JNIEnv* env); extern int register_android_animation_PropertyValuesHolder(JNIEnv *env); extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env); extern int register_com_android_internal_net_NetworkStatsFactory(JNIEnv *env); +extern int register_com_android_internal_os_ClassLoaderFactory(JNIEnv* env); extern int register_com_android_internal_os_FuseAppLoop(JNIEnv* env); -extern int register_com_android_internal_os_PathClassLoaderFactory(JNIEnv* env); extern int register_com_android_internal_os_Zygote(JNIEnv *env); extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env); @@ -1402,7 +1402,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_net_TrafficStats), REG_JNI(register_android_os_MemoryFile), REG_JNI(register_android_os_SharedMemory), - REG_JNI(register_com_android_internal_os_PathClassLoaderFactory), + REG_JNI(register_com_android_internal_os_ClassLoaderFactory), REG_JNI(register_com_android_internal_os_Zygote), REG_JNI(register_com_android_internal_util_VirtualRefBasePtr), REG_JNI(register_android_hardware_Camera), diff --git a/core/jni/com_android_internal_os_PathClassLoaderFactory.cpp b/core/jni/com_android_internal_os_ClassLoaderFactory.cpp index a7a912cd0e05..7052e5f3ce4b 100644 --- a/core/jni/com_android_internal_os_PathClassLoaderFactory.cpp +++ b/core/jni/com_android_internal_os_ClassLoaderFactory.cpp @@ -39,13 +39,13 @@ static const JNINativeMethod g_methods[] = { reinterpret_cast<void*>(createClassloaderNamespace_native) }, }; -static const char* const kPathClassLoaderFactoryPathName = "com/android/internal/os/PathClassLoaderFactory"; +static const char* const kClassLoaderFactoryPathName = "com/android/internal/os/ClassLoaderFactory"; namespace android { -int register_com_android_internal_os_PathClassLoaderFactory(JNIEnv* env) { - return RegisterMethodsOrDie(env, kPathClassLoaderFactoryPathName, g_methods, NELEM(g_methods)); +int register_com_android_internal_os_ClassLoaderFactory(JNIEnv* env) { + return RegisterMethodsOrDie(env, kClassLoaderFactoryPathName, g_methods, NELEM(g_methods)); } } // namespace android diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 01b8e1558fb3..33f69b47af36 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -1051,6 +1051,22 @@ <p>The default value of this attribute is <code>false</code>. --> <attr name="isolatedSplits" format="boolean" /> + <!-- The classname of the classloader used to load the application's classes + from its APK. The APK in question can either be the 'base' APK or any + of the application's 'split' APKs if it's using a feature split. + + <p> + The supported values for this attribute are + <code>dalvik.system.PathClassLoader</code> and + <code>dalvik.system.DelegateLastClassLoader</code>. If unspecified, + the default value of this attribute is <code>dalvik.system.PathClassLoader</code>. + + If an unknown classloader is provided, a PackageParserException with cause + <code>PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED</code> will be + thrown and the app will not be installed. + --> + <attr name="classLoader" format="string" /> + <!-- If set to <code>true</code>, indicates to the platform that this APK is a 'feature' split and that it implicitly depends on the base APK. This distinguishes this split APK from a 'configuration' split, which provides resource overrides @@ -1485,6 +1501,9 @@ <enum name="productivity" value="7" /> </attr> + <!-- Declares the kind of classloader this application's classes must be loaded with --> + <attr name="classLoader" /> + </declare-styleable> <!-- The <code>permission</code> tag declares a security permission that can be used to control access from other packages to specific components or diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 2a4881d6b167..634d79a92a4b 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2845,6 +2845,7 @@ <public-group type="attr" first-id="0x01010569"> <public name="showWhenLocked"/> <public name="turnScreenOn"/> + <public name="classLoader" /> </public-group> <public-group type="style" first-id="0x010302e0"> diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 5c54ba803a05..58237713d793 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -927,7 +927,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // This is kind of hacky; we're creating a half-parsed package that is // straddled between the inherited and staged APKs. final PackageLite pkg = new PackageLite(null, baseApk, null, null, null, null, - splitPaths.toArray(new String[splitPaths.size()]), null); + splitPaths.toArray(new String[splitPaths.size()]), null, null); final boolean isForwardLocked = (params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0; diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 20d7b28c55e1..9765113b7957 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -175,7 +175,7 @@ class PackageManagerShellCommand extends ShellCommand { try { ApkLite baseApk = PackageParser.parseApkLite(file, 0); PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null, - null, null); + null, null, null); params.sessionParams.setSize(PackageHelper.calculateInstalledSize( pkgLite, false, params.sessionParams.abiOverride)); } catch (PackageParserException | IOException e) { |