From f8579581c1d6bf993f26d21aefca410ac9b6706b Mon Sep 17 00:00:00 2001 From: Svet Ganov Date: Fri, 16 Jun 2017 15:04:01 -0700 Subject: [DO NOT MERGE] Support native shared libs Add the shared libs that are APKs to the native library path when creating application class loaders. Also don't allow shared libraries hosting native libs to request extraction of the native libs out of the APK. Lastly, shared libraries hosting native libs must be declared as multi-architecture. Test: CTS tests in this topic bug:62720360 Change-Id: I0a398593ebe41b2976cb706ca8a388005f5aec83 --- core/java/android/app/LoadedApk.java | 23 +++++++++++++++++++ core/java/android/content/pm/PackageParser.java | 4 ++++ .../android/server/pm/PackageManagerService.java | 26 ++++++++++++++++++---- 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index 0708b0bd3821..393909bbeefb 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -452,6 +452,7 @@ public final class LoadedApk { for (String lib : sharedLibraries) { if (!outZipPaths.contains(lib)) { outZipPaths.add(0, lib); + appendApkLibPathIfNeeded(lib, aInfo, outLibPaths); } } } @@ -460,11 +461,33 @@ public final class LoadedApk { for (String lib : instrumentationLibs) { if (!outZipPaths.contains(lib)) { outZipPaths.add(0, lib); + appendApkLibPathIfNeeded(lib, aInfo, outLibPaths); } } } } + /** + * This method appends a path to the appropriate native library folder of a + * library if this library is hosted in an APK. This allows support for native + * shared libraries. The library API is determined based on the application + * ABI. + * + * @param path Path to the library. + * @param applicationInfo The application depending on the library. + * @param outLibPaths List to which to add the native lib path if needed. + */ + private static void appendApkLibPathIfNeeded(@NonNull String path, + @NonNull ApplicationInfo applicationInfo, @Nullable List outLibPaths) { + // Looking at the suffix is a little hacky but a safe and simple solution. + // We will be revisiting code in the next release and clean this up. + if (outLibPaths != null && applicationInfo.primaryCpuAbi != null && path.endsWith(".apk")) { + if (applicationInfo.targetSdkVersion >= Build.VERSION_CODES.O) { + outLibPaths.add(path + "!/lib/" + applicationInfo.primaryCpuAbi); + } + } + } + /* * All indices received by the super class should be shifted by 1 when accessing mSplitNames, * etc. The super class assumes the base APK is index 0, while the PackageManager APIs don't diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index fdb0f2bae64b..c67376c25885 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -5989,6 +5989,10 @@ public class PackageParser { } } + public boolean isLibrary() { + return staticSharedLibName != null || !ArrayUtils.isEmpty(libraryNames); + } + public List getAllCodePaths() { ArrayList paths = new ArrayList<>(); paths.add(baseCodePath); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 5f96b9177281..54f2ffd63167 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -57,6 +57,7 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE import static android.content.pm.PackageManager.INSTALL_FORWARD_LOCK; import static android.content.pm.PackageManager.INSTALL_INTERNAL; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; @@ -10432,8 +10433,9 @@ public class PackageManagerService extends IPackageManager.Stub if ((scanFlags & SCAN_NEW_INSTALL) == 0) { if ((scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi"); - derivePackageAbi( - pkg, scanFile, cpuAbiOverride, true /*extractLibs*/, mAppLib32InstallDir); + final boolean extractNativeLibs = !pkg.isLibrary(); + derivePackageAbi(pkg, scanFile, cpuAbiOverride, extractNativeLibs, + mAppLib32InstallDir); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); // Some system apps still use directory structure for native libraries @@ -11461,6 +11463,12 @@ public class PackageManagerService extends IPackageManager.Stub Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } + // Shared library native code should be in the APK zip aligned + if (abi32 >= 0 && pkg.isLibrary() && extractLibs) { + throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, + "Shared library native lib extraction not supported"); + } + maybeThrowExceptionForMultiArchCopy( "Error unpackaging 32 bit native libs for multiarch app.", abi32); @@ -11481,6 +11489,11 @@ public class PackageManagerService extends IPackageManager.Stub "Error unpackaging 64 bit native libs for multiarch app.", abi64); if (abi64 >= 0) { + // Shared library native libs should be in the APK zip aligned + if (extractLibs && pkg.isLibrary()) { + throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, + "Shared library native lib extraction not supported"); + } pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[abi64]; } @@ -11497,7 +11510,6 @@ public class PackageManagerService extends IPackageManager.Stub pkg.applicationInfo.primaryCpuAbi = abi; } } - } else { String[] abiList = (cpuAbiOverride != null) ? new String[] { cpuAbiOverride } : Build.SUPPORTED_ABIS; @@ -11530,6 +11542,11 @@ public class PackageManagerService extends IPackageManager.Stub } if (copyRet >= 0) { + // Shared libraries that have native libs must be multi-architecture + if (pkg.isLibrary()) { + throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, + "Shared library with native libs must be multiarch"); + } pkg.applicationInfo.primaryCpuAbi = abiList[copyRet]; } else if (copyRet == PackageManager.NO_NATIVE_LIBRARIES && cpuAbiOverride != null) { pkg.applicationInfo.primaryCpuAbi = cpuAbiOverride; @@ -18084,8 +18101,9 @@ public class PackageManagerService extends IPackageManager.Stub try { String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ? args.abiOverride : pkg.cpuAbiOverride); + final boolean extractNativeLibs = !pkg.isLibrary(); derivePackageAbi(pkg, new File(pkg.codePath), abiOverride, - true /*extractLibs*/, mAppLib32InstallDir); + extractNativeLibs, mAppLib32InstallDir); } catch (PackageManagerException pme) { Slog.e(TAG, "Error deriving application ABI", pme); res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI"); -- cgit v1.2.3-59-g8ed1b