From 1378aba7aeeb7f6dd6cc2503968ba7b0e58d9333 Mon Sep 17 00:00:00 2001 From: Ramin Zaghi Date: Fri, 28 Feb 2014 15:03:19 +0000 Subject: [PATCH] Re-implement native library search and copies. We now use a two step approach : - First we look through the list of shared libraries in an APK, and choose an ABI based on the (priority) list of ABIs a given device supports. - Then we look through the list of shared libraries and copy all shared libraries that match the ABI we've selected. This fixes a long-standing bug where we would sometimes copy a mixture of different ABIs to the device, and also allows us to clearly pick an ABI to run an app with. The code in NativeLibraryHelper has been refactored so that all file name validation & matching logic is done in a single place (NativeLibrariesIterator). This allows us to avoid a lot of redundant logic and straightens out a few corner cases (for eg. where the abi determination & copying logic do not agree on what files to skip). bug: https://code.google.com/p/android/issues/detail?id=65053 bug: 13647418 Change-Id: I34d08353f24115b0f6b800a7eda3ac427fa25fef Co-Authored-By: Zhenghua Wang Co-Authored-By: Ramin Zaghi Co-Authored-By: Narayan Kamath --- .../android/content/pm/PackageManager.java | 19 ++ core/java/android/os/Build.java | 9 +- .../internal/content/NativeLibraryHelper.java | 74 +++-- ...d_internal_content_NativeLibraryHelper.cpp | 293 +++++++++++++----- .../defcontainer/DefaultContainerService.java | 35 ++- .../server/pm/PackageManagerService.java | 42 ++- 6 files changed, 356 insertions(+), 116 deletions(-) diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index c97c2b89304de..8ce7e972e4cb7 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -674,6 +674,25 @@ public abstract class PackageManager { */ public static final int INSTALL_FAILED_USER_RESTRICTED = -111; + /** + * Installation failed return code: this is passed to the {@link IPackageInstallObserver} by + * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} + * if the system failed to install the package because its packaged native code did not + * match any of the ABIs supported by the system. + * + * @hide + */ + public static final int INSTALL_FAILED_NO_MATCHING_ABIS = -112; + + /** + * Internal return code for NativeLibraryHelper methods to indicate that the package + * being processed did not contain any native code. This is placed here only so that + * it can belong to the same value space as the other install failure codes. + * + * @hide + */ + public static final int NO_NATIVE_LIBRARIES = -113; + /** * Flag parameter for {@link #deletePackage} to indicate that you don't want to delete the * package's data directory. diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index bc51a60992805..c3313c53a5ee5 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -74,7 +74,14 @@ public class Build { /** A hardware serial number, if available. Alphanumeric only, case-insensitive. */ public static final String SERIAL = getString("ro.serialno"); - + + /** + * A list of ABIs (in priority) order supported by this device. + * + * @hide + */ + public static final String[] SUPPORTED_ABIS = getString("ro.product.cpu.abilist").split(","); + /** Various version strings. */ public static class VERSION { /** diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java index 6d657829c8fad..ba419f9bf1ab0 100644 --- a/core/java/com/android/internal/content/NativeLibraryHelper.java +++ b/core/java/com/android/internal/content/NativeLibraryHelper.java @@ -16,7 +16,7 @@ package com.android.internal.content; -import android.os.Build; +import android.content.pm.PackageManager; import android.util.Slog; import java.io.File; @@ -31,38 +31,76 @@ public class NativeLibraryHelper { private static final boolean DEBUG_NATIVE = false; - private static native long nativeSumNativeBinaries(String file, String cpuAbi, String cpuAbi2); - /** - * Sums the size of native binaries in an APK. + * A handle to an opened APK. Used as input to the various NativeLibraryHelper + * methods. Allows us to scan and parse the APK exactly once instead of doing + * it multiple times. * - * @param apkFile APK file to scan for native libraries - * @return size of all native binary files in bytes + * @hide */ - public static long sumNativeBinariesLI(File apkFile) { - final String cpuAbi = Build.CPU_ABI; - final String cpuAbi2 = Build.CPU_ABI2; - return nativeSumNativeBinaries(apkFile.getPath(), cpuAbi, cpuAbi2); + public static class ApkHandle { + final String apkPath; + final long apkHandle; + + public ApkHandle(String path) { + apkPath = path; + apkHandle = nativeOpenApk(apkPath); + } + + public ApkHandle(File apkFile) { + apkPath = apkFile.getPath(); + apkHandle = nativeOpenApk(apkPath); + } + + public void close() { + nativeClose(apkHandle); + } } - private native static int nativeCopyNativeBinaries(String filePath, String sharedLibraryPath, - String cpuAbi, String cpuAbi2); + + private static native long nativeOpenApk(String path); + private static native void nativeClose(long handle); + + private static native long nativeSumNativeBinaries(long handle, String cpuAbi); + + /** + * Sums the size of native binaries in an APK for a given ABI. + * + * @return size of all native binary files in bytes + */ + public static long sumNativeBinariesLI(ApkHandle handle, String abi) { + return nativeSumNativeBinaries(handle.apkHandle, abi); + } + + private native static int nativeCopyNativeBinaries(long handle, + String sharedLibraryPath, String abiToCopy); /** * Copies native binaries to a shared library directory. * - * @param apkFile APK file to scan for native libraries + * @param handle APK file to scan for native libraries * @param sharedLibraryDir directory for libraries to be copied to * @return {@link PackageManager#INSTALL_SUCCEEDED} if successful or another * error code from that class if not */ - public static int copyNativeBinariesIfNeededLI(File apkFile, File sharedLibraryDir) { - final String cpuAbi = Build.CPU_ABI; - final String cpuAbi2 = Build.CPU_ABI2; - return nativeCopyNativeBinaries(apkFile.getPath(), sharedLibraryDir.getPath(), cpuAbi, - cpuAbi2); + public static int copyNativeBinariesIfNeededLI(ApkHandle handle, File sharedLibraryDir, + String abi) { + return nativeCopyNativeBinaries(handle.apkHandle, sharedLibraryDir.getPath(), abi); } + /** + * Checks if a given APK contains native code for any of the provided + * {@code supportedAbis}. Returns an index into {@code supportedAbis} if a matching + * ABI is found, {@link PackageManager#NO_NATIVE_LIBRARIES} if the + * APK doesn't contain any native code, and + * {@link PackageManager#INSTALL_FAILED_NO_MATCHING_ABIS} if none of the ABIs match. + */ + public static int findSupportedAbi(ApkHandle handle, String[] supportedAbis) { + return nativeFindSupportedAbi(handle.apkHandle, supportedAbis); + } + + private native static int nativeFindSupportedAbi(long handle, String[] supportedAbis); + // Convenience method to call removeNativeBinariesFromDirLI(File) public static boolean removeNativeBinariesLI(String nativeLibraryPath) { return removeNativeBinariesFromDirLI(new File(nativeLibraryPath)); diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp index a86091851aba9..200457696d729 100644 --- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp +++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp @@ -19,11 +19,12 @@ #include -#include -#include -#include #include #include +#include +#include +#include +#include #include @@ -54,17 +55,19 @@ namespace android { // These match PackageManager.java install codes -typedef enum { +enum install_status_t { INSTALL_SUCCEEDED = 1, INSTALL_FAILED_INVALID_APK = -2, INSTALL_FAILED_INSUFFICIENT_STORAGE = -4, INSTALL_FAILED_CONTAINER_ERROR = -18, INSTALL_FAILED_INTERNAL_ERROR = -110, -} install_status_t; + INSTALL_FAILED_NO_MATCHING_ABIS = -112, + NO_NATIVE_LIBRARIES = -113 +}; typedef install_status_t (*iterFunc)(JNIEnv*, void*, ZipFileRO*, ZipEntryRO, const char*); -// Equivalent to isFilenameSafe +// Equivalent to android.os.FileUtils.isFilenameSafe static bool isFilenameSafe(const char* filename) { @@ -268,126 +271,252 @@ copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntr return INSTALL_SUCCEEDED; } -static install_status_t -iterateOverNativeFiles(JNIEnv *env, jstring javaFilePath, jstring javaCpuAbi, jstring javaCpuAbi2, - iterFunc callFunc, void* callArg) { - ScopedUtfChars filePath(env, javaFilePath); - ScopedUtfChars cpuAbi(env, javaCpuAbi); - ScopedUtfChars cpuAbi2(env, javaCpuAbi2); - - UniquePtr zipFile(ZipFileRO::open(filePath.c_str())); - if (zipFile.get() == NULL) { - ALOGI("Couldn't open APK %s\n", filePath.c_str()); - return INSTALL_FAILED_INVALID_APK; +/* + * An iterator over all shared libraries in a zip file. An entry is + * considered to be a shared library if all of the conditions below are + * satisfied : + * + * - The entry is under the lib/ directory. + * - The entry name ends with ".so" and the entry name starts with "lib", + * an exception is made for entries whose name is "gdbserver". + * - The entry filename is "safe" (as determined by isFilenameSafe). + * + */ +class NativeLibrariesIterator { +private: + NativeLibrariesIterator(ZipFileRO* zipFile, void* cookie) + : mZipFile(zipFile), mCookie(cookie), mLastSlash(NULL) { + fileName[0] = '\0'; } +public: + static NativeLibrariesIterator* create(ZipFileRO* zipFile) { + void* cookie = NULL; + if (!zipFile->startIteration(&cookie)) { + return NULL; + } + + return new NativeLibrariesIterator(zipFile, cookie); + } + + ZipEntryRO next() { + ZipEntryRO next = NULL; + while ((next = mZipFile->nextEntry(mCookie)) != NULL) { + // Make sure this entry has a filename. + if (mZipFile->getEntryFileName(next, fileName, sizeof(fileName))) { + continue; + } + + // Make sure we're in the lib directory of the ZIP. + if (strncmp(fileName, APK_LIB, APK_LIB_LEN)) { + continue; + } + + // Make sure the filename is at least to the minimum library name size. + const size_t fileNameLen = strlen(fileName); + static const size_t minLength = APK_LIB_LEN + 2 + LIB_PREFIX_LEN + 1 + LIB_SUFFIX_LEN; + if (fileNameLen < minLength) { + continue; + } + + const char* lastSlash = strrchr(fileName, '/'); + ALOG_ASSERT(lastSlash != NULL, "last slash was null somehow for %s\n", fileName); + + // Exception: If we find the gdbserver binary, return it. + if (!strncmp(lastSlash + 1, GDBSERVER, GDBSERVER_LEN)) { + break; + } + + // Make sure the filename starts with lib and ends with ".so". + if (strncmp(fileName + fileNameLen - LIB_SUFFIX_LEN, LIB_SUFFIX, LIB_SUFFIX_LEN) + || strncmp(lastSlash, LIB_PREFIX, LIB_PREFIX_LEN)) { + continue; + } + + // Make sure the filename is safe. + if (!isFilenameSafe(lastSlash + 1)) { + continue; + } + + mLastSlash = lastSlash; + break; + } + + return next; + } + + inline const char* currentEntry() const { + return fileName; + } + + inline const char* lastSlash() const { + return mLastSlash; + } + + virtual ~NativeLibrariesIterator() { + mZipFile->endIteration(mCookie); + } +private: + char fileName[PATH_MAX]; - bool hasPrimaryAbi = false; + ZipFileRO* const mZipFile; + void* mCookie; + const char* mLastSlash; +}; - void* cookie = NULL; - if (!zipFile->startIteration(&cookie)) { - ALOGI("Couldn't iterate over APK%s\n", filePath.c_str()); +static install_status_t +iterateOverNativeFiles(JNIEnv *env, jlong apkHandle, jstring javaCpuAbi, + iterFunc callFunc, void* callArg) { + ZipFileRO* zipFile = reinterpret_cast(apkHandle); + if (zipFile == NULL) { return INSTALL_FAILED_INVALID_APK; } + UniquePtr it(NativeLibrariesIterator::create(zipFile)); + if (it.get() == NULL) { + return INSTALL_FAILED_INVALID_APK; + } + + const ScopedUtfChars cpuAbi(env, javaCpuAbi); + if (cpuAbi.c_str() == NULL) { + // This would've thrown, so this return code isn't observable by + // Java. + return INSTALL_FAILED_INVALID_APK; + } ZipEntryRO entry = NULL; - while ((entry = zipFile->nextEntry(cookie)) != NULL) { - // Make sure this entry has a filename. - if (zipFile->getEntryFileName(entry, fileName, sizeof(fileName))) { - continue; - } - - // Make sure we're in the lib directory of the ZIP. - if (strncmp(fileName, APK_LIB, APK_LIB_LEN)) { - continue; - } - - // Make sure the filename is at least to the minimum library name size. - const size_t fileNameLen = strlen(fileName); - static const size_t minLength = APK_LIB_LEN + 2 + LIB_PREFIX_LEN + 1 + LIB_SUFFIX_LEN; - if (fileNameLen < minLength) { - continue; - } - - const char* lastSlash = strrchr(fileName, '/'); - ALOG_ASSERT(lastSlash != NULL, "last slash was null somehow for %s\n", fileName); + while ((entry = it->next()) != NULL) { + const char* fileName = it->currentEntry(); + const char* lastSlash = it->lastSlash(); // Check to make sure the CPU ABI of this file is one we support. const char* cpuAbiOffset = fileName + APK_LIB_LEN; const size_t cpuAbiRegionSize = lastSlash - cpuAbiOffset; - ALOGV("Comparing ABIs %s and %s versus %s\n", cpuAbi.c_str(), cpuAbi2.c_str(), cpuAbiOffset); - if (cpuAbi.size() == cpuAbiRegionSize - && *(cpuAbiOffset + cpuAbi.size()) == '/' - && !strncmp(cpuAbiOffset, cpuAbi.c_str(), cpuAbiRegionSize)) { - ALOGV("Using primary ABI %s\n", cpuAbi.c_str()); - hasPrimaryAbi = true; - } else if (cpuAbi2.size() == cpuAbiRegionSize - && *(cpuAbiOffset + cpuAbi2.size()) == '/' - && !strncmp(cpuAbiOffset, cpuAbi2.c_str(), cpuAbiRegionSize)) { - - /* - * If this library matches both the primary and secondary ABIs, - * only use the primary ABI. - */ - if (hasPrimaryAbi) { - ALOGV("Already saw primary ABI, skipping secondary ABI %s\n", cpuAbi2.c_str()); - continue; - } else { - ALOGV("Using secondary ABI %s\n", cpuAbi2.c_str()); - } - } else { - ALOGV("abi didn't match anything: %s (end at %zd)\n", cpuAbiOffset, cpuAbiRegionSize); - continue; - } - - // If this is a .so file, check to see if we need to copy it. - if ((!strncmp(fileName + fileNameLen - LIB_SUFFIX_LEN, LIB_SUFFIX, LIB_SUFFIX_LEN) - && !strncmp(lastSlash, LIB_PREFIX, LIB_PREFIX_LEN) - && isFilenameSafe(lastSlash + 1)) - || !strncmp(lastSlash + 1, GDBSERVER, GDBSERVER_LEN)) { - - install_status_t ret = callFunc(env, callArg, zipFile.get(), entry, lastSlash + 1); + if (cpuAbi.size() == cpuAbiRegionSize && !strncmp(cpuAbiOffset, cpuAbi.c_str(), cpuAbiRegionSize)) { + install_status_t ret = callFunc(env, callArg, zipFile, entry, lastSlash + 1); if (ret != INSTALL_SUCCEEDED) { ALOGV("Failure for entry %s", lastSlash + 1); - zipFile->endIteration(cookie); return ret; } } } - zipFile->endIteration(cookie); - return INSTALL_SUCCEEDED; } + +static int findSupportedAbi(JNIEnv *env, jlong apkHandle, jobjectArray supportedAbisArray) { + const int numAbis = env->GetArrayLength(supportedAbisArray); + Vector supportedAbis; + + for (int i = 0; i < numAbis; ++i) { + supportedAbis.add(new ScopedUtfChars(env, + (jstring) env->GetObjectArrayElement(supportedAbisArray, i))); + } + + ZipFileRO* zipFile = reinterpret_cast(apkHandle); + if (zipFile == NULL) { + return INSTALL_FAILED_INVALID_APK; + } + + UniquePtr it(NativeLibrariesIterator::create(zipFile)); + if (it.get() == NULL) { + return INSTALL_FAILED_INVALID_APK; + } + + ZipEntryRO entry = NULL; + char fileName[PATH_MAX]; + int status = NO_NATIVE_LIBRARIES; + while ((entry = it->next()) != NULL) { + // We're currently in the lib/ directory of the APK, so it does have some native + // code. We should return INSTALL_FAILED_NO_MATCHING_ABIS if none of the + // libraries match. + if (status == NO_NATIVE_LIBRARIES) { + status = INSTALL_FAILED_NO_MATCHING_ABIS; + } + + const char* fileName = it->currentEntry(); + const char* lastSlash = it->lastSlash(); + + // Check to see if this CPU ABI matches what we are looking for. + const char* abiOffset = fileName + APK_LIB_LEN; + const size_t abiSize = lastSlash - abiOffset; + for (int i = 0; i < numAbis; i++) { + const ScopedUtfChars* abi = supportedAbis[i]; + if (abi->size() == abiSize && !strncmp(abiOffset, abi->c_str(), abiSize)) { + // The entry that comes in first (i.e. with a lower index) has the higher priority. + if (((i < status) && (status >= 0)) || (status < 0) ) { + status = i; + } + } + } + } + + for (int i = 0; i < numAbis; ++i) { + delete supportedAbis[i]; + } + + return status; +} + static jint com_android_internal_content_NativeLibraryHelper_copyNativeBinaries(JNIEnv *env, jclass clazz, - jstring javaFilePath, jstring javaNativeLibPath, jstring javaCpuAbi, jstring javaCpuAbi2) + jlong apkHandle, jstring javaNativeLibPath, jstring javaCpuAbi) { - return (jint) iterateOverNativeFiles(env, javaFilePath, javaCpuAbi, javaCpuAbi2, + return (jint) iterateOverNativeFiles(env, apkHandle, javaCpuAbi, copyFileIfChanged, &javaNativeLibPath); } static jlong com_android_internal_content_NativeLibraryHelper_sumNativeBinaries(JNIEnv *env, jclass clazz, - jstring javaFilePath, jstring javaCpuAbi, jstring javaCpuAbi2) + jlong apkHandle, jstring javaCpuAbi) { size_t totalSize = 0; - iterateOverNativeFiles(env, javaFilePath, javaCpuAbi, javaCpuAbi2, sumFiles, &totalSize); + iterateOverNativeFiles(env, apkHandle, javaCpuAbi, sumFiles, &totalSize); return totalSize; } +static jint +com_android_internal_content_NativeLibraryHelper_findSupportedAbi(JNIEnv *env, jclass clazz, + jlong apkHandle, jobjectArray javaCpuAbisToSearch) +{ + return (jint) findSupportedAbi(env, apkHandle, javaCpuAbisToSearch); +} + +static jlong +com_android_internal_content_NativeLibraryHelper_openApk(JNIEnv *env, jclass, jstring apkPath) +{ + ScopedUtfChars filePath(env, apkPath); + ZipFileRO* zipFile = ZipFileRO::open(filePath.c_str()); + + return reinterpret_cast(zipFile); +} + +static void +com_android_internal_content_NativeLibraryHelper_close(JNIEnv *env, jclass, jlong apkHandle) +{ + delete reinterpret_cast(apkHandle); +} + static JNINativeMethod gMethods[] = { + {"nativeOpenApk", + "(Ljava/lang/String;)J", + (void *)com_android_internal_content_NativeLibraryHelper_openApk}, + {"nativeClose", + "(J)V", + (void *)com_android_internal_content_NativeLibraryHelper_close}, {"nativeCopyNativeBinaries", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I", + "(JLjava/lang/String;Ljava/lang/String;)I", (void *)com_android_internal_content_NativeLibraryHelper_copyNativeBinaries}, {"nativeSumNativeBinaries", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)J", + "(JLjava/lang/String;)J", (void *)com_android_internal_content_NativeLibraryHelper_sumNativeBinaries}, + {"nativeFindSupportedAbi", + "(J[Ljava/lang/String;)I", + (void *)com_android_internal_content_NativeLibraryHelper_findSupportedAbi}, }; diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java index 6e34bbb08a394..48ef9dbe61e5e 100644 --- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java +++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java @@ -30,6 +30,7 @@ import android.content.pm.PackageParser; import android.content.res.ObbInfo; import android.content.res.ObbScanner; import android.net.Uri; +import android.os.Build; import android.os.Environment; import android.os.Environment.UserEnvironment; import android.os.FileUtils; @@ -39,10 +40,8 @@ import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.StatFs; -import android.os.SystemClock; import android.provider.Settings; import android.util.DisplayMetrics; -import android.util.Log; import android.util.Slog; import com.android.internal.app.IMediaContainerService; @@ -343,11 +342,13 @@ public class DefaultContainerService extends IntentService { // The .apk file String codePath = packageURI.getPath(); File codeFile = new File(codePath); + NativeLibraryHelper.ApkHandle handle = new NativeLibraryHelper.ApkHandle(codePath); + final int abi = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_ABIS); // Calculate size of container needed to hold base APK. final int sizeMb; try { - sizeMb = calculateContainerSize(codeFile, isForwardLocked); + sizeMb = calculateContainerSize(handle, codeFile, abi, isForwardLocked); } catch (IOException e) { Slog.w(TAG, "Problem when trying to copy " + codeFile.getPath()); return null; @@ -410,7 +411,14 @@ public class DefaultContainerService extends IntentService { final File sharedLibraryDir = new File(newCachePath, LIB_DIR_NAME); if (sharedLibraryDir.mkdir()) { - int ret = NativeLibraryHelper.copyNativeBinariesIfNeededLI(codeFile, sharedLibraryDir); + int ret = PackageManager.INSTALL_SUCCEEDED; + if (abi >= 0) { + ret = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle, + sharedLibraryDir, Build.SUPPORTED_ABIS[abi]); + } else if (abi != PackageManager.NO_NATIVE_LIBRARIES) { + ret = abi; + } + if (ret != PackageManager.INSTALL_SUCCEEDED) { Slog.e(TAG, "Could not copy native libraries to " + sharedLibraryDir.getPath()); PackageHelper.destroySdDir(newCid); @@ -824,6 +832,17 @@ public class DefaultContainerService extends IntentService { return availSdMb > sizeMb; } + private int calculateContainerSize(File apkFile, boolean forwardLocked) throws IOException { + NativeLibraryHelper.ApkHandle handle = new NativeLibraryHelper.ApkHandle(apkFile); + final int abi = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_ABIS); + + try { + return calculateContainerSize(handle, apkFile, abi, forwardLocked); + } finally { + handle.close(); + } + } + /** * Calculate the container size for an APK. Takes into account the * @@ -831,7 +850,8 @@ public class DefaultContainerService extends IntentService { * @return size in megabytes (2^20 bytes) * @throws IOException when there is a problem reading the file */ - private int calculateContainerSize(File apkFile, boolean forwardLocked) throws IOException { + private int calculateContainerSize(NativeLibraryHelper.ApkHandle apkHandle, + File apkFile, int abiIndex, boolean forwardLocked) throws IOException { // Calculate size of container needed to hold base APK. long sizeBytes = apkFile.length(); if (sizeBytes == 0 && !apkFile.exists()) { @@ -840,7 +860,10 @@ public class DefaultContainerService extends IntentService { // Check all the native files that need to be copied and add that to the // container size. - sizeBytes += NativeLibraryHelper.sumNativeBinariesLI(apkFile); + if (abiIndex >= 0) { + sizeBytes += NativeLibraryHelper.sumNativeBinariesLI(apkHandle, + Build.SUPPORTED_ABIS[abiIndex]); + } if (forwardLocked) { sizeBytes += PackageHelper.extractPublicFiles(apkFile.getPath(), null); diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index f33f739411f35..7d13caa0072f8 100755 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -59,8 +59,8 @@ import android.content.IIntentReceiver; import android.content.Intent; import android.content.IntentFilter; import android.content.IntentSender; -import android.content.ServiceConnection; import android.content.IntentSender.SendIntentException; +import android.content.ServiceConnection; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.ContainerEncryptionParams; @@ -72,14 +72,15 @@ import android.content.pm.IPackageManager; import android.content.pm.IPackageMoveObserver; import android.content.pm.IPackageStatsObserver; import android.content.pm.InstrumentationInfo; +import android.content.pm.ManifestDigest; import android.content.pm.PackageCleanItem; import android.content.pm.PackageInfo; import android.content.pm.PackageInfoLite; import android.content.pm.PackageManager; import android.content.pm.PackageParser; -import android.content.pm.PackageUserState; import android.content.pm.PackageParser.ActivityIntentInfo; import android.content.pm.PackageStats; +import android.content.pm.PackageUserState; import android.content.pm.ParceledListSlice; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; @@ -87,7 +88,6 @@ import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.Signature; -import android.content.pm.ManifestDigest; import android.content.pm.VerificationParams; import android.content.pm.VerifierDeviceIdentity; import android.content.pm.VerifierInfo; @@ -97,6 +97,7 @@ import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Environment; +import android.os.Environment.UserEnvironment; import android.os.FileObserver; import android.os.FileUtils; import android.os.Handler; @@ -113,7 +114,6 @@ import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; -import android.os.Environment.UserEnvironment; import android.os.UserManager; import android.security.KeyStore; import android.security.SystemKeyStore; @@ -4700,7 +4700,8 @@ public class PackageManagerService extends IPackageManager.Stub { } try { - if (copyNativeLibrariesForInternalApp(scanFile, nativeLibraryDir) != PackageManager.INSTALL_SUCCEEDED) { + int copyRet = copyNativeLibrariesForInternalApp(scanFile, nativeLibraryDir); + if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) { Slog.e(TAG, "Unable to copy native libraries"); mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR; return null; @@ -5251,7 +5252,21 @@ public class PackageManagerService extends IPackageManager.Stub { * If this is an internal application or our nativeLibraryPath points to * the app-lib directory, unpack the libraries if necessary. */ - return NativeLibraryHelper.copyNativeBinariesIfNeededLI(scanFile, nativeLibraryDir); + final NativeLibraryHelper.ApkHandle handle = new NativeLibraryHelper.ApkHandle(scanFile); + try { + int abi = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_ABIS); + if (abi >= 0) { + int copyRet = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle, + nativeLibraryDir, Build.SUPPORTED_ABIS[abi]); + if (copyRet != PackageManager.INSTALL_SUCCEEDED) { + return copyRet; + } + } + + return abi; + } finally { + handle.close(); + } } private void killApplication(String pkgName, int appId, String reason) { @@ -8137,7 +8152,7 @@ public class PackageManagerService extends IPackageManager.Stub { } try { int copyRet = copyNativeLibrariesForInternalApp(codeFile, nativeLibraryFile); - if (copyRet != PackageManager.INSTALL_SUCCEEDED) { + if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) { return copyRet; } } catch (IOException e) { @@ -11512,8 +11527,17 @@ public class PackageManagerService extends IPackageManager.Stub { final File newNativeDir = new File(newNativePath); if (!isForwardLocked(pkg) && !isExternal(pkg)) { - NativeLibraryHelper.copyNativeBinariesIfNeededLI( - new File(newCodePath), newNativeDir); + // NOTE: We do not report any errors from the APK scan and library + // copy at this point. + NativeLibraryHelper.ApkHandle handle = + new NativeLibraryHelper.ApkHandle(newCodePath); + final int abi = NativeLibraryHelper.findSupportedAbi( + handle, Build.SUPPORTED_ABIS); + if (abi >= 0) { + NativeLibraryHelper.copyNativeBinariesIfNeededLI( + handle, newNativeDir, Build.SUPPORTED_ABIS[abi]); + } + handle.close(); } final int[] users = sUserManager.getUserIds(); for (int user : users) {