summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jiyong Park <jiyong@google.com> 2020-07-23 08:56:41 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2020-07-23 08:56:41 +0000
commit5a63c659983b78766ed8cefd31c19013287d5eec (patch)
treefbe1ad63b75c51d15d3c3134d59308b8ddd3d886
parent3e9bfcf84fa5a42a50d1ba1d707eb7c4c3d4fcae (diff)
parent6a5b8b1f6db172b5aaadcec0c3868e54e214b675 (diff)
Merge "Introduce uses-native-library tag"
-rw-r--r--core/java/android/app/ApplicationLoaders.java28
-rw-r--r--core/java/android/app/LoadedApk.java23
-rw-r--r--core/java/android/content/pm/SharedLibraryInfo.java25
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackage.java6
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageImpl.java44
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageRead.java13
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageUtils.java35
-rw-r--r--core/java/com/android/internal/os/ClassLoaderFactory.java15
-rw-r--r--core/java/com/android/server/SystemConfig.java40
-rw-r--r--core/jni/com_android_internal_os_ClassLoaderFactory.cpp9
-rw-r--r--core/res/res/values/attrs_manifest.xml23
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java52
-rw-r--r--services/core/java/com/android/server/pm/Settings.java17
-rw-r--r--services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java13
-rw-r--r--tools/aapt2/dump/DumpManifest.cpp25
-rw-r--r--tools/aapt2/link/ManifestFixer.cpp1
16 files changed, 343 insertions, 26 deletions
diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java
index bac432e42318..15237beee805 100644
--- a/core/java/android/app/ApplicationLoaders.java
+++ b/core/java/android/app/ApplicationLoaders.java
@@ -48,17 +48,18 @@ public class ApplicationLoaders {
ClassLoader parent, String classLoaderName) {
return getClassLoaderWithSharedLibraries(zip, targetSdkVersion, isBundled,
librarySearchPath, libraryPermittedPath, parent, classLoaderName,
- null);
+ null, null);
}
ClassLoader getClassLoaderWithSharedLibraries(
String zip, int targetSdkVersion, boolean isBundled,
String librarySearchPath, String libraryPermittedPath,
ClassLoader parent, String classLoaderName,
- List<ClassLoader> sharedLibraries) {
+ List<ClassLoader> sharedLibraries, List<String> nativeSharedLibraries) {
// For normal usage the cache key used is the same as the zip path.
return getClassLoader(zip, targetSdkVersion, isBundled, librarySearchPath,
- libraryPermittedPath, parent, zip, classLoaderName, sharedLibraries);
+ libraryPermittedPath, parent, zip, classLoaderName, sharedLibraries,
+ nativeSharedLibraries);
}
/**
@@ -77,14 +78,22 @@ public class ApplicationLoaders {
return loader;
}
+ // TODO(b/142191088): allow (Java) shared libraries to have <uses-native-library>
+ // Until that is supported, assume that all native shared libraries are used.
+ // "ALL" is a magic string that libnativeloader uses to unconditionally add all available
+ // native shared libraries to the classloader.
+ List<String> nativeSharedLibraries = new ArrayList<>();
+ nativeSharedLibraries.add("ALL");
return getClassLoaderWithSharedLibraries(zip, targetSdkVersion, isBundled,
- librarySearchPath, libraryPermittedPath, parent, classLoaderName, sharedLibraries);
+ librarySearchPath, libraryPermittedPath, parent, classLoaderName, sharedLibraries,
+ nativeSharedLibraries);
}
private ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled,
String librarySearchPath, String libraryPermittedPath,
ClassLoader parent, String cacheKey,
- String classLoaderName, List<ClassLoader> sharedLibraries) {
+ String classLoaderName, List<ClassLoader> sharedLibraries,
+ List<String> nativeSharedLibraries) {
/*
* This is the parent we use if they pass "null" in. In theory
* this should be the "system" class loader; in practice we
@@ -113,7 +122,8 @@ public class ApplicationLoaders {
ClassLoader classloader = ClassLoaderFactory.createClassLoader(
zip, librarySearchPath, libraryPermittedPath, parent,
- targetSdkVersion, isBundled, classLoaderName, sharedLibraries);
+ targetSdkVersion, isBundled, classLoaderName, sharedLibraries,
+ nativeSharedLibraries);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
@@ -185,7 +195,8 @@ public class ApplicationLoaders {
// assume cached libraries work with current sdk since they are built-in
ClassLoader classLoader = getClassLoader(path, Build.VERSION.SDK_INT, true /*isBundled*/,
null /*librarySearchPath*/, null /*libraryPermittedPath*/, null /*parent*/,
- null /*cacheKey*/, null /*classLoaderName*/, sharedLibraries /*sharedLibraries*/);
+ null /*cacheKey*/, null /*classLoaderName*/, sharedLibraries /*sharedLibraries*/,
+ null /* nativeSharedLibraries */);
if (classLoader == null) {
// bad configuration or break in classloading code
@@ -255,7 +266,8 @@ 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, null /* classLoaderName */, null /* sharedLibraries */);
+ cacheKey, null /* classLoaderName */, null /* sharedLibraries */,
+ null /* nativeSharedLibraries */);
}
/**
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index f9b48e710148..1dc54ddbac4b 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -412,6 +412,12 @@ public final class LoadedApk {
return;
}
for (SharedLibraryInfo lib : sharedLibraries) {
+ if (lib.isNative()) {
+ // Native shared lib doesn't contribute to the native lib search path. Its name is
+ // sent to libnativeloader and then the native shared lib is exported from the
+ // default linker namespace.
+ continue;
+ }
List<String> paths = lib.getAllCodePaths();
outSeenPaths.addAll(paths);
for (String path : paths) {
@@ -696,6 +702,12 @@ public final class LoadedApk {
}
List<ClassLoader> loaders = new ArrayList<>();
for (SharedLibraryInfo info : sharedLibraries) {
+ if (info.isNative()) {
+ // Native shared lib doesn't contribute to the native lib search path. Its name is
+ // sent to libnativeloader and then the native shared lib is exported from the
+ // default linker namespace.
+ continue;
+ }
loaders.add(createSharedLibraryLoader(
info, isBundledApp, librarySearchPath, libraryPermittedPath));
}
@@ -898,10 +910,19 @@ public final class LoadedApk {
mApplicationInfo.sharedLibraryInfos, isBundledApp, librarySearchPath,
libraryPermittedPath);
+ List<String> nativeSharedLibraries = new ArrayList<>();
+ if (mApplicationInfo.sharedLibraryInfos != null) {
+ for (SharedLibraryInfo info : mApplicationInfo.sharedLibraryInfos) {
+ if (info.isNative()) {
+ nativeSharedLibraries.add(info.getName());
+ }
+ }
+ }
+
mDefaultClassLoader = ApplicationLoaders.getDefault().getClassLoaderWithSharedLibraries(
zip, mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
libraryPermittedPath, mBaseClassLoader,
- mApplicationInfo.classLoaderName, sharedLibraries);
+ mApplicationInfo.classLoaderName, sharedLibraries, nativeSharedLibraries);
mAppComponentFactory = createAppFactory(mApplicationInfo, mDefaultClassLoader);
setThreadPolicy(oldPolicy);
diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java
index da2a3d885fc6..862563706da7 100644
--- a/core/java/android/content/pm/SharedLibraryInfo.java
+++ b/core/java/android/content/pm/SharedLibraryInfo.java
@@ -79,6 +79,7 @@ public final class SharedLibraryInfo implements Parcelable {
private final long mVersion;
private final @Type int mType;
+ private final boolean mIsNative;
private final VersionedPackage mDeclaringPackage;
private final List<VersionedPackage> mDependentPackages;
private List<SharedLibraryInfo> mDependencies;
@@ -93,13 +94,14 @@ public final class SharedLibraryInfo implements Parcelable {
* @param type The lib type.
* @param declaringPackage The package that declares the library.
* @param dependentPackages The packages that depend on the library.
+ * @param isNative indicate if this shared lib is a native lib or not (i.e. java)
*
* @hide
*/
public SharedLibraryInfo(String path, String packageName, List<String> codePaths,
String name, long version, int type,
VersionedPackage declaringPackage, List<VersionedPackage> dependentPackages,
- List<SharedLibraryInfo> dependencies) {
+ List<SharedLibraryInfo> dependencies, boolean isNative) {
mPath = path;
mPackageName = packageName;
mCodePaths = codePaths;
@@ -109,6 +111,16 @@ public final class SharedLibraryInfo implements Parcelable {
mDeclaringPackage = declaringPackage;
mDependentPackages = dependentPackages;
mDependencies = dependencies;
+ mIsNative = isNative;
+ }
+
+ /** @hide */
+ public SharedLibraryInfo(String path, String packageName, List<String> codePaths,
+ String name, long version, int type,
+ VersionedPackage declaringPackage, List<VersionedPackage> dependentPackages,
+ List<SharedLibraryInfo> dependencies) {
+ this(path, packageName, codePaths, name, version, type, declaringPackage, dependentPackages,
+ dependencies, false /* isNative */);
}
private SharedLibraryInfo(Parcel parcel) {
@@ -125,6 +137,7 @@ public final class SharedLibraryInfo implements Parcelable {
mDeclaringPackage = parcel.readParcelable(null);
mDependentPackages = parcel.readArrayList(null);
mDependencies = parcel.createTypedArrayList(SharedLibraryInfo.CREATOR);
+ mIsNative = parcel.readBoolean();
}
/**
@@ -137,6 +150,15 @@ public final class SharedLibraryInfo implements Parcelable {
}
/**
+ * Tells whether this library is a native shared library or not.
+ *
+ * @hide
+ */
+ public boolean isNative() {
+ return mIsNative;
+ }
+
+ /**
* Gets the library name an app defines in its manifest
* to depend on the library.
*
@@ -320,6 +342,7 @@ public final class SharedLibraryInfo implements Parcelable {
parcel.writeParcelable(mDeclaringPackage, flags);
parcel.writeList(mDependentPackages);
parcel.writeTypedList(mDependencies);
+ parcel.writeBoolean(mIsNative);
}
private static String typeToString(int type) {
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
index 2ee0ad67b108..872098c8689e 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -92,6 +92,10 @@ public interface ParsingPackage extends ParsingPackageRead {
ParsingPackage addUsesOptionalLibrary(String libraryName);
+ ParsingPackage addUsesNativeLibrary(String libraryName);
+
+ ParsingPackage addUsesOptionalNativeLibrary(String libraryName);
+
ParsingPackage addUsesStaticLibrary(String libraryName);
ParsingPackage addUsesStaticLibraryCertDigests(String[] certSha256Digests);
@@ -219,6 +223,8 @@ public interface ParsingPackage extends ParsingPackageRead {
ParsingPackage removeUsesOptionalLibrary(String libraryName);
+ ParsingPackage removeUsesOptionalNativeLibrary(String libraryName);
+
ParsingPackage setAnyDensity(int anyDensity);
ParsingPackage setAppComponentFactory(String appComponentFactory);
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
index f932bc250e28..0c0dc313087e 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -186,6 +186,13 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
@NonNull
@DataClass.ParcelWith(ForInternedStringList.class)
+ protected List<String> usesNativeLibraries = emptyList();
+ @NonNull
+ @DataClass.ParcelWith(ForInternedStringList.class)
+ protected List<String> usesOptionalNativeLibraries = emptyList();
+
+ @NonNull
+ @DataClass.ParcelWith(ForInternedStringList.class)
private List<String> usesStaticLibraries = emptyList();
@Nullable
private long[] usesStaticLibrariesVersions;
@@ -669,6 +676,27 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
}
@Override
+ public final ParsingPackageImpl addUsesOptionalNativeLibrary(String libraryName) {
+ this.usesOptionalNativeLibraries = CollectionUtils.add(this.usesOptionalNativeLibraries,
+ TextUtils.safeIntern(libraryName));
+ return this;
+ }
+
+ @Override
+ public final ParsingPackageImpl addUsesNativeLibrary(String libraryName) {
+ this.usesNativeLibraries = CollectionUtils.add(this.usesNativeLibraries,
+ TextUtils.safeIntern(libraryName));
+ return this;
+ }
+
+
+ @Override public ParsingPackageImpl removeUsesOptionalNativeLibrary(String libraryName) {
+ this.usesOptionalNativeLibraries = CollectionUtils.remove(this.usesOptionalNativeLibraries,
+ libraryName);
+ return this;
+ }
+
+ @Override
public ParsingPackageImpl addUsesStaticLibrary(String libraryName) {
this.usesStaticLibraries = CollectionUtils.add(this.usesStaticLibraries,
TextUtils.safeIntern(libraryName));
@@ -982,6 +1010,8 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
sForInternedStringList.parcel(this.libraryNames, dest, flags);
sForInternedStringList.parcel(this.usesLibraries, dest, flags);
sForInternedStringList.parcel(this.usesOptionalLibraries, dest, flags);
+ sForInternedStringList.parcel(this.usesNativeLibraries, dest, flags);
+ sForInternedStringList.parcel(this.usesOptionalNativeLibraries, dest, flags);
sForInternedStringList.parcel(this.usesStaticLibraries, dest, flags);
dest.writeLongArray(this.usesStaticLibrariesVersions);
@@ -1144,6 +1174,8 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
this.libraryNames = sForInternedStringList.unparcel(in);
this.usesLibraries = sForInternedStringList.unparcel(in);
this.usesOptionalLibraries = sForInternedStringList.unparcel(in);
+ this.usesNativeLibraries = sForInternedStringList.unparcel(in);
+ this.usesOptionalNativeLibraries = sForInternedStringList.unparcel(in);
this.usesStaticLibraries = sForInternedStringList.unparcel(in);
this.usesStaticLibrariesVersions = in.createLongArray();
@@ -1417,6 +1449,18 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
@NonNull
@Override
+ public List<String> getUsesNativeLibraries() {
+ return usesNativeLibraries;
+ }
+
+ @NonNull
+ @Override
+ public List<String> getUsesOptionalNativeLibraries() {
+ return usesOptionalNativeLibraries;
+ }
+
+ @NonNull
+ @Override
public List<String> getUsesStaticLibraries() {
return usesStaticLibraries;
}
diff --git a/core/java/android/content/pm/parsing/ParsingPackageRead.java b/core/java/android/content/pm/parsing/ParsingPackageRead.java
index 5b53c18b820c..7e0fe7dc41bf 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageRead.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageRead.java
@@ -230,6 +230,19 @@ public interface ParsingPackageRead extends Parcelable {
@NonNull
List<String> getUsesOptionalLibraries();
+ /** @see R.styleabele#AndroidManifestUsesNativeLibrary */
+ @NonNull
+ List<String> getUsesNativeLibraries();
+
+ /**
+ * Like {@link #getUsesNativeLibraries()}, but marked optional by setting
+ * {@link R.styleable#AndroidManifestUsesNativeLibrary_required} to false . Application is
+ * expected to handle absence manually.
+ * @see R.styleable#AndroidManifestUsesNativeLibrary
+ */
+ @NonNull
+ List<String> getUsesOptionalNativeLibraries();
+
/**
* TODO(b/135203078): Move static library stuff to an inner data class
* @see R.styleable#AndroidManifestUsesStaticLibrary
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index 3688f1bda979..e1f08f3e55a1 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -701,6 +701,8 @@ public class ParsingPackageUtils {
return parseUsesStaticLibrary(input, pkg, res, parser);
case "uses-library":
return parseUsesLibrary(input, pkg, res, parser);
+ case "uses-native-library":
+ return parseUsesNativeLibrary(input, pkg, res, parser);
case "uses-package":
// Dependencies for app installers; we don't currently try to
// enforce this.
@@ -2017,6 +2019,8 @@ public class ParsingPackageUtils {
return parseUsesStaticLibrary(input, pkg, res, parser);
case "uses-library":
return parseUsesLibrary(input, pkg, res, parser);
+ case "uses-native-library":
+ return parseUsesNativeLibrary(input, pkg, res, parser);
case "processes":
return parseProcesses(input, pkg, res, parser, mSeparateProcesses, flags);
case "uses-package":
@@ -2178,6 +2182,37 @@ public class ParsingPackageUtils {
}
@NonNull
+ private static ParseResult<ParsingPackage> parseUsesNativeLibrary(ParseInput input,
+ ParsingPackage pkg, Resources res, XmlResourceParser parser) {
+ TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesNativeLibrary);
+ try {
+ // Note: don't allow this value to be a reference to a resource
+ // that may change.
+ String lname = sa.getNonResourceString(
+ R.styleable.AndroidManifestUsesNativeLibrary_name);
+ boolean req = sa.getBoolean(R.styleable.AndroidManifestUsesNativeLibrary_required,
+ true);
+
+ if (lname != null) {
+ if (req) {
+ // Upgrade to treat as stronger constraint
+ pkg.addUsesNativeLibrary(lname)
+ .removeUsesOptionalNativeLibrary(lname);
+ } else {
+ // Ignore if someone already defined as required
+ if (!ArrayUtils.contains(pkg.getUsesNativeLibraries(), lname)) {
+ pkg.addUsesOptionalNativeLibrary(lname);
+ }
+ }
+ }
+
+ return input.success(pkg);
+ } finally {
+ sa.recycle();
+ }
+ }
+
+ @NonNull
private static ParseResult<ParsingPackage> parseProcesses(ParseInput input, ParsingPackage pkg,
Resources res, XmlResourceParser parser, String[] separateProcesses, int flags)
throws IOException, XmlPullParserException {
diff --git a/core/java/com/android/internal/os/ClassLoaderFactory.java b/core/java/com/android/internal/os/ClassLoaderFactory.java
index a18943c264f5..f83c5bdc4e28 100644
--- a/core/java/com/android/internal/os/ClassLoaderFactory.java
+++ b/core/java/com/android/internal/os/ClassLoaderFactory.java
@@ -101,7 +101,7 @@ public class ClassLoaderFactory {
String librarySearchPath, String libraryPermittedPath, ClassLoader parent,
int targetSdkVersion, boolean isNamespaceShared, String classLoaderName) {
return createClassLoader(dexPath, librarySearchPath, libraryPermittedPath,
- parent, targetSdkVersion, isNamespaceShared, classLoaderName, null);
+ parent, targetSdkVersion, isNamespaceShared, classLoaderName, null, null);
}
@@ -111,18 +111,24 @@ public class ClassLoaderFactory {
public static ClassLoader createClassLoader(String dexPath,
String librarySearchPath, String libraryPermittedPath, ClassLoader parent,
int targetSdkVersion, boolean isNamespaceShared, String classLoaderName,
- List<ClassLoader> sharedLibraries) {
+ List<ClassLoader> sharedLibraries, List<String> nativeSharedLibraries) {
final ClassLoader classLoader = createClassLoader(dexPath, librarySearchPath, parent,
classLoaderName, sharedLibraries);
+ String sonameList = "";
+ if (nativeSharedLibraries != null) {
+ sonameList = String.join(":", nativeSharedLibraries);
+ }
+
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "createClassloaderNamespace");
String errorMessage = createClassloaderNamespace(classLoader,
targetSdkVersion,
librarySearchPath,
libraryPermittedPath,
isNamespaceShared,
- dexPath);
+ dexPath,
+ sonameList);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
if (errorMessage != null) {
@@ -139,5 +145,6 @@ public class ClassLoaderFactory {
String librarySearchPath,
String libraryPermittedPath,
boolean isNamespaceShared,
- String dexPath);
+ String dexPath,
+ String sonameList);
}
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 0eb3981ed598..957cc76b3e54 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -49,10 +49,12 @@ import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
+import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -104,11 +106,17 @@ public class SystemConfig {
public final String name;
public final String filename;
public final String[] dependencies;
+ public final boolean isNative;
SharedLibraryEntry(String name, String filename, String[] dependencies) {
+ this(name, filename, dependencies, false /* isNative */);
+ }
+
+ SharedLibraryEntry(String name, String filename, String[] dependencies, boolean isNative) {
this.name = name;
this.filename = filename;
this.dependencies = dependencies;
+ this.isNative = isNative;
}
}
@@ -457,6 +465,7 @@ public class SystemConfig {
log.traceBegin("readAllPermissions");
try {
readAllPermissions();
+ readPublicNativeLibrariesList();
} finally {
log.traceEnd();
}
@@ -1513,6 +1522,37 @@ public class SystemConfig {
}
}
+ private void readPublicNativeLibrariesList() {
+ readPublicLibrariesListFile(new File("/vendor/etc/public.libraries.txt"));
+ String[] dirs = {"/system/etc", "/system_ext/etc", "/product/etc"};
+ for (String dir : dirs) {
+ for (File f : (new File(dir)).listFiles()) {
+ String name = f.getName();
+ if (name.startsWith("public.libraries-") && name.endsWith(".txt")) {
+ readPublicLibrariesListFile(f);
+ }
+ }
+ }
+ }
+
+ private void readPublicLibrariesListFile(File listFile) {
+ try (BufferedReader br = new BufferedReader(new FileReader(listFile))) {
+ String line;
+ while ((line = br.readLine()) != null) {
+ if (line.isEmpty() || line.startsWith("#")) {
+ continue;
+ }
+ // Line format is <soname> [abi]. We take the soname part.
+ String soname = line.trim().split(" ")[0];
+ SharedLibraryEntry entry = new SharedLibraryEntry(
+ soname, soname, new String[0], true);
+ mSharedLibraries.put(entry.name, entry);
+ }
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to read public libraries file " + listFile, e);
+ }
+ }
+
private static boolean isSystemProcess() {
return Process.myUid() == Process.SYSTEM_UID;
}
diff --git a/core/jni/com_android_internal_os_ClassLoaderFactory.cpp b/core/jni/com_android_internal_os_ClassLoaderFactory.cpp
index f8d41e4bef54..59c413ff58a6 100644
--- a/core/jni/com_android_internal_os_ClassLoaderFactory.cpp
+++ b/core/jni/com_android_internal_os_ClassLoaderFactory.cpp
@@ -28,16 +28,19 @@ static jstring createClassloaderNamespace_native(JNIEnv* env,
jstring librarySearchPath,
jstring libraryPermittedPath,
jboolean isShared,
- jstring dexPath) {
+ jstring dexPath,
+ jstring sonameList) {
return android::CreateClassLoaderNamespace(env, targetSdkVersion,
classLoader, isShared == JNI_TRUE,
dexPath,
- librarySearchPath, libraryPermittedPath);
+ librarySearchPath,
+ libraryPermittedPath,
+ sonameList);
}
static const JNINativeMethod g_methods[] = {
{ "createClassloaderNamespace",
- "(Ljava/lang/ClassLoader;ILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;)Ljava/lang/String;",
+ "(Ljava/lang/ClassLoader;ILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
reinterpret_cast<void*>(createClassloaderNamespace_native) },
};
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index eb30c9be4eba..ac08d96ab303 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2173,6 +2173,29 @@
<attr name="required" />
</declare-styleable>
+ <!-- The <code>uses-native-library</code> specifies a native shared library that this
+ package requires to be linked against. Specifying this flag tells the
+ system to make the native library to be available to your app.
+
+ <p>On devices running R or lower, this is ignored and the app has access to all
+ the public native shared libraries that are exported from the platform. This is
+ also ignored if the app is targeting R or lower.
+
+ <p>This appears as a child tag of the
+ {@link #AndroidManifestApplication application} tag. -->
+ <declare-styleable name="AndroidManifestUsesNativeLibrary" parent="AndroidManifestApplication">
+ <!-- Required name of the library you use. -->
+ <attr name="name" />
+ <!-- Specify whether this native library is required for the application.
+ The default is true, meaning the application requires the
+ library, and does not want to be installed on devices that
+ don't support it. If you set this to false, then this will
+ allow the application to be installed even if the library
+ doesn't exist, and you will need to check for its presence
+ dynamically at runtime. -->
+ <attr name="required" />
+ </declare-styleable>
+
<!-- The <code>uses-static-library</code> specifies a shared <strong>static</strong>
library that this package requires to be statically linked against. Specifying
this tag tells the system to include this library's code in your class loader.
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index bd12fd5f5d9a..2854b337fd29 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -651,6 +651,23 @@ public class PackageManagerService extends IPackageManager.Stub
private static final long THROW_EXCEPTION_ON_REQUIRE_INSTALL_PACKAGES_TO_ADD_INSTALLER_PACKAGE =
150857253;
+ /**
+ * Apps targeting Android S and above need to declare dependencies to the public native
+ * shared libraries that are defined by the device maker using {@code uses-native-library} tag
+ * in its {@code AndroidManifest.xml}.
+ *
+ * If any of the dependencies cannot be satisfied, i.e. one of the dependency doesn't exist,
+ * the package manager rejects to install the app. The dependency can be specified as optional
+ * using {@code android:required} attribute in the tag, in which case failing to satisfy the
+ * dependency doesn't stop the installation.
+ * <p>Once installed, an app is provided with only the native shared libraries that are
+ * specified in the app manifest. {@code dlopen}ing a native shared library that doesn't appear
+ * in the app manifest will fail even if it actually exists on the device.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
+ private static final long ENFORCE_NATIVE_SHARED_LIBRARY_DEPENDENCIES = 142191088;
+
public static final String PLATFORM_PACKAGE_NAME = "android";
private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
@@ -2952,9 +2969,8 @@ public class PackageManagerService extends IPackageManager.Stub
= systemConfig.getSharedLibraries();
final int builtInLibCount = libConfig.size();
for (int i = 0; i < builtInLibCount; i++) {
- String name = libConfig.keyAt(i);
SystemConfig.SharedLibraryEntry entry = libConfig.valueAt(i);
- addBuiltInSharedLibraryLocked(entry.filename, name);
+ addBuiltInSharedLibraryLocked(libConfig.valueAt(i));
}
// Now that we have added all the libraries, iterate again to add dependency
@@ -10486,6 +10502,19 @@ public class PackageManagerService extends IPackageManager.Stub
null, null, pkg.getPackageName(), false, pkg.getTargetSdkVersion(),
usesLibraryInfos, availablePackages, existingLibraries, newLibraries);
}
+ // TODO(b/160928779) gate this behavior using ENFORCE_NATIVE_SHARED_LIBRARY_DEPENDENCIES
+ if (pkg.getTargetSdkVersion() > 30) {
+ if (!pkg.getUsesNativeLibraries().isEmpty() && pkg.getTargetSdkVersion() > 30) {
+ usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesNativeLibraries(), null,
+ null, pkg.getPackageName(), true, pkg.getTargetSdkVersion(),
+ usesLibraryInfos, availablePackages, existingLibraries, newLibraries);
+ }
+ if (!pkg.getUsesOptionalNativeLibraries().isEmpty()) {
+ usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesOptionalNativeLibraries(),
+ null, null, pkg.getPackageName(), false, pkg.getTargetSdkVersion(),
+ usesLibraryInfos, availablePackages, existingLibraries, newLibraries);
+ }
+ }
return usesLibraryInfos;
}
@@ -12177,15 +12206,16 @@ public class PackageManagerService extends IPackageManager.Stub
}
@GuardedBy("mLock")
- private boolean addBuiltInSharedLibraryLocked(String path, String name) {
- if (nonStaticSharedLibExistsLocked(name)) {
+ private boolean addBuiltInSharedLibraryLocked(SystemConfig.SharedLibraryEntry entry) {
+ if (nonStaticSharedLibExistsLocked(entry.name)) {
return false;
}
- SharedLibraryInfo libraryInfo = new SharedLibraryInfo(path, null, null, name,
- (long) SharedLibraryInfo.VERSION_UNDEFINED, SharedLibraryInfo.TYPE_BUILTIN,
- new VersionedPackage(PLATFORM_PACKAGE_NAME, (long) 0),
- null, null);
+ SharedLibraryInfo libraryInfo = new SharedLibraryInfo(entry.filename, null, null,
+ entry.name, (long) SharedLibraryInfo.VERSION_UNDEFINED,
+ SharedLibraryInfo.TYPE_BUILTIN,
+ new VersionedPackage(PLATFORM_PACKAGE_NAME, (long)0), null, null,
+ entry.isNative);
commitSharedLibraryInfoLocked(libraryInfo);
return true;
@@ -21900,7 +21930,11 @@ public class PackageManagerService extends IPackageManager.Stub
pw.print(" -> ");
}
if (libraryInfo.getPath() != null) {
- pw.print(" (jar) ");
+ if (libraryInfo.isNative()) {
+ pw.print(" (so) ");
+ } else {
+ pw.print(" (jar) ");
+ }
pw.print(libraryInfo.getPath());
} else {
pw.print(" (apk) ");
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 13b927e7d9f4..7106499f9b56 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4784,6 +4784,23 @@ public final class Settings {
}
}
+ List<String> usesNativeLibraries = pkg.getUsesNativeLibraries();
+ if (usesNativeLibraries.size() > 0) {
+ pw.print(prefix); pw.println(" usesNativeLibraries:");
+ for (int i=0; i< usesNativeLibraries.size(); i++) {
+ pw.print(prefix); pw.print(" "); pw.println(usesNativeLibraries.get(i));
+ }
+ }
+
+ List<String> usesOptionalNativeLibraries = pkg.getUsesOptionalNativeLibraries();
+ if (usesOptionalNativeLibraries.size() > 0) {
+ pw.print(prefix); pw.println(" usesOptionalNativeLibraries:");
+ for (int i=0; i< usesOptionalNativeLibraries.size(); i++) {
+ pw.print(prefix); pw.print(" ");
+ pw.println(usesOptionalNativeLibraries.get(i));
+ }
+ }
+
List<String> usesLibraryFiles = ps.getPkgState().getUsesLibraryFiles();
if (usesLibraryFiles.size() > 0) {
pw.print(prefix); pw.println(" usesLibraryFiles:");
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
index c9e0bb467ce4..39784cf32cea 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
@@ -252,6 +252,19 @@ public interface AndroidPackage extends PkgAppInfo, PkgPackageInfo, ParsingPacka
@NonNull
List<String> getUsesOptionalLibraries();
+ /** @see R.styleabele#AndroidManifestUsesNativeLibrary */
+ @NonNull
+ List<String> getUsesNativeLibraries();
+
+ /**
+ * Like {@link #getUsesNativeLibraries()}, but marked optional by setting
+ * {@link R.styleable#AndroidManifestUsesNativeLibrary_required} to false . Application is
+ * expected to handle absence manually.
+ * @see R.styleable#AndroidManifestUsesNativeLibrary
+ */
+ @NonNull
+ List<String> getUsesOptionalNativeLibraries();
+
/**
* TODO(b/135203078): Move static library stuff to an inner data class
* @see R.styleable#AndroidManifestUsesStaticLibrary
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
index 4a6bfd031284..53d9ffe21949 100644
--- a/tools/aapt2/dump/DumpManifest.cpp
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -1405,6 +1405,29 @@ class UsesStaticLibrary : public ManifestExtractor::Element {
}
};
+/** Represents <uses-native-library> elements. **/
+class UsesNativeLibrary : public ManifestExtractor::Element {
+ public:
+ UsesNativeLibrary() = default;
+ std::string name;
+ int required;
+
+ void Extract(xml::Element* element) override {
+ auto parent_stack = extractor()->parent_stack();
+ if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
+ name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+ required = GetAttributeIntegerDefault(FindAttribute(element, REQUIRED_ATTR), 1);
+ }
+ }
+
+ void Print(text::Printer* printer) override {
+ if (!name.empty()) {
+ printer->Print(StringPrintf("uses-native-library%s:'%s'\n",
+ (required == 0) ? "-not-required" : "", name.data()));
+ }
+ }
+};
+
/**
* Represents <meta-data> elements. These tags are only printed when a flag is passed in to
* explicitly enable meta data printing.
@@ -2245,6 +2268,7 @@ T* ElementCast(ManifestExtractor::Element* element) {
{"uses-static-library", std::is_base_of<UsesStaticLibrary, T>::value},
{"additional-certificate", std::is_base_of<AdditionalCertificate, T>::value},
{"uses-sdk", std::is_base_of<UsesSdkBadging, T>::value},
+ {"uses-native-library", std::is_base_of<UsesNativeLibrary, T>::value},
};
auto check = kTagCheck.find(element->tag());
@@ -2295,6 +2319,7 @@ std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Element::Inflate(
{"uses-package", &CreateType<UsesPackage>},
{"additional-certificate", &CreateType<AdditionalCertificate>},
{"uses-sdk", &CreateType<UsesSdkBadging>},
+ {"uses-native-library", &CreateType<UsesNativeLibrary>},
};
// Attempt to map the xml tag to a element inflater
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 3d69093a936a..49f8e1bcd30b 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -422,6 +422,7 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
application_action.Action(OptionalNameIsJavaClassName);
application_action["uses-library"].Action(RequiredNameIsNotEmpty);
+ application_action["uses-native-library"].Action(RequiredNameIsNotEmpty);
application_action["library"].Action(RequiredNameIsNotEmpty);
application_action["profileable"];