Loading api/current.txt +1 −1 Original line number Diff line number Diff line Loading @@ -8668,7 +8668,7 @@ package android.content.pm { method public void removeSessionCallback(android.content.pm.PackageInstaller.SessionCallback); method public void uninstall(java.lang.String, android.content.IntentSender); field public static final java.lang.String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS"; field public static final java.lang.String EXTRA_PACKAGE_NAMES = "android.content.pm.extra.PACKAGE_NAMES"; field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME"; field public static final java.lang.String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID"; field public static final java.lang.String EXTRA_STATUS = "android.content.pm.extra.STATUS"; field public static final java.lang.String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE"; core/java/android/content/pm/PackageInstaller.java +8 −4 Original line number Diff line number Diff line Loading @@ -105,10 +105,14 @@ public class PackageInstaller { public static final String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE"; /** * List of package names that are relevant to a status. * Package name relevant to a status. * * @see Intent#getStringArrayExtra(String) * @see Intent#getStringExtra(String) */ public static final String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME"; /** {@hide} */ @Deprecated public static final String EXTRA_PACKAGE_NAMES = "android.content.pm.extra.PACKAGE_NAMES"; /** {@hide} */ Loading Loading @@ -178,8 +182,8 @@ public class PackageInstaller { * permission, incompatible certificates, etc. The user may be able to * uninstall another app to fix the issue. * <p> * The result may also contain {@link #EXTRA_PACKAGE_NAMES} with the * specific packages identified as the cause of the conflict. * The result may also contain {@link #EXTRA_PACKAGE_NAME} with the * specific package identified as the cause of the conflict. * * @see #EXTRA_STATUS_MESSAGE */ Loading core/java/android/content/pm/PackageParser.java +8 −34 Original line number Diff line number Diff line Loading @@ -596,7 +596,7 @@ public class PackageParser { public final static int PARSE_ON_SDCARD = 1<<5; public final static int PARSE_IS_SYSTEM_DIR = 1<<6; public final static int PARSE_IS_PRIVILEGED = 1<<7; public final static int PARSE_GET_SIGNATURES = 1<<8; public final static int PARSE_COLLECT_CERTIFICATES = 1<<8; public final static int PARSE_TRUSTED_OVERLAY = 1<<9; private static final Comparator<String> sSplitNameComparator = new SplitNameComparator(); Loading Loading @@ -1087,34 +1087,6 @@ public class PackageParser { } } /** * Only collect certificates on the manifest; does not validate signatures * across remainder of package. */ private static Signature[] collectManifestCertificates(File apkFile) throws PackageParserException { final String apkPath = apkFile.getAbsolutePath(); try { final StrictJarFile jarFile = new StrictJarFile(apkPath); try { final ZipEntry jarEntry = jarFile.findEntry(ANDROID_MANIFEST_FILENAME); if (jarEntry == null) { throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, "Package " + apkPath + " has no manifest"); } final Certificate[][] certs = loadCertificates(jarFile, jarEntry); return convertToSignatures(certs); } finally { jarFile.close(); } } catch (GeneralSecurityException | IOException | RuntimeException e) { throw new PackageParserException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING, "Failed to collect certificates from " + apkPath, e); } } private static Signature[] convertToSignatures(Certificate[][] certs) throws CertificateEncodingException { final Signature[] res = new Signature[certs.length]; Loading @@ -1129,7 +1101,8 @@ public class PackageParser { * file, including package name, split name, and install location. * * @param apkFile path to a single APK * @param flags optional parse flags, such as {@link #PARSE_GET_SIGNATURES} * @param flags optional parse flags, such as * {@link #PARSE_COLLECT_CERTIFICATES} */ public static ApkLite parseApkLite(File apkFile, int flags) throws PackageParserException { Loading @@ -1154,11 +1127,12 @@ public class PackageParser { final Resources res = new Resources(assets, metrics, null); parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); // Only collect certificates on the manifest; does not validate // signatures across remainder of package. final Signature[] signatures; if ((flags & PARSE_GET_SIGNATURES) != 0) { signatures = collectManifestCertificates(apkFile); if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) { // TODO: factor signature related items out of Package object final Package tempPkg = new Package(null); collectCertificates(tempPkg, apkFile, 0); signatures = tempPkg.mSignatures; } else { signatures = null; } Loading core/java/com/android/internal/content/NativeLibraryHelper.java +181 −17 Original line number Diff line number Diff line Loading @@ -19,15 +19,25 @@ package com.android.internal.content; import static android.content.pm.PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS; import static android.content.pm.PackageManager.INSTALL_SUCCEEDED; import static android.content.pm.PackageManager.NO_NATIVE_LIBRARIES; import static android.system.OsConstants.S_IRGRP; import static android.system.OsConstants.S_IROTH; import static android.system.OsConstants.S_IRWXU; import static android.system.OsConstants.S_IXGRP; import static android.system.OsConstants.S_IXOTH; import android.content.pm.PackageManager; import android.content.pm.PackageParser; import android.content.pm.PackageParser.Package; import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; import android.os.Build; import android.os.SELinux; import android.system.ErrnoException; import android.system.Os; import android.util.Slog; import dalvik.system.CloseGuard; import dalvik.system.VMRuntime; import java.io.Closeable; import java.io.File; Loading @@ -44,6 +54,10 @@ public class NativeLibraryHelper { private static final boolean DEBUG_NATIVE = false; // Special value for {@code PackageParser.Package#cpuAbiOverride} to indicate // that the cpuAbiOverride must be clear. public static final String CLEAR_ABI_OVERRIDE = "-"; /** * A handle to an opened package, consisting of one or more APKs. Used as * input to the various NativeLibraryHelper methods. Allows us to scan and Loading Loading @@ -126,27 +140,17 @@ public class NativeLibraryHelper { 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(Handle handle, String[] abis) { private native static int nativeCopyNativeBinaries(long handle, String sharedLibraryPath, String abiToCopy); private static long sumNativeBinaries(Handle handle, String abi) { long sum = 0; for (long apkHandle : handle.apkHandles) { // NOTE: For a given APK handle, we parse the central directory precisely // once, but prefix matching of entries requires a CD traversal, which can // take a while (even if it needs no additional I/O). for (String abi : abis) { sum += nativeSumNativeBinaries(apkHandle, abi); } } return sum; } private native static int nativeCopyNativeBinaries(long handle, String sharedLibraryPath, String abiToCopy); /** * Copies native binaries to a shared library directory. * Loading Loading @@ -244,9 +248,171 @@ public class NativeLibraryHelper { } } private static void createNativeLibrarySubdir(File path) throws IOException { if (!path.isDirectory()) { path.delete(); if (!path.mkdir()) { throw new IOException("Cannot create " + path.getPath()); } try { Os.chmod(path.getPath(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); } catch (ErrnoException e) { throw new IOException("Cannot chmod native library directory " + path.getPath(), e); } } else if (!SELinux.restorecon(path)) { throw new IOException("Cannot set SELinux context for " + path.getPath()); } } private static long sumNativeBinaries(Handle handle, String[] abiList) { int abi = findSupportedAbi(handle, abiList); if (abi >= 0) { return sumNativeBinaries(handle, abiList[abi]); } else { return 0; } } public static int copyNativeBinariesIfNeededLI(Handle handle, File libraryRoot, String[] abiList, boolean useIsaSubdir) throws IOException { createNativeLibrarySubdir(libraryRoot); /* * If this is an internal application or our nativeLibraryPath points to * the app-lib directory, unpack the libraries if necessary. */ int abi = findSupportedAbi(handle, abiList); if (abi >= 0) { /* * If we have a matching instruction set, construct a subdir under the native * library root that corresponds to this instruction set. */ final String instructionSet = VMRuntime.getInstructionSet(abiList[abi]); final File subDir; if (useIsaSubdir) { final File isaSubdir = new File(libraryRoot, instructionSet); createNativeLibrarySubdir(isaSubdir); subDir = isaSubdir; } else { subDir = libraryRoot; } int copyRet = copyNativeBinariesIfNeededLI(handle, subDir, abiList[abi]); if (copyRet != PackageManager.INSTALL_SUCCEEDED) { return copyRet; } } return abi; } public static int copyNativeBinariesIfNeededLI(Handle handle, File libraryRoot, String abiOverride, boolean multiArch) { try { if (multiArch) { // Warn if we've set an abiOverride for multi-lib packages.. // By definition, we need to copy both 32 and 64 bit libraries for // such packages. if (abiOverride != null && !CLEAR_ABI_OVERRIDE.equals(abiOverride)) { Slog.w(TAG, "Ignoring abiOverride for multi arch application."); } int copyRet = PackageManager.NO_NATIVE_LIBRARIES; if (Build.SUPPORTED_32_BIT_ABIS.length > 0) { copyRet = copyNativeBinariesIfNeededLI(handle, libraryRoot, Build.SUPPORTED_32_BIT_ABIS, true /* use isa specific subdirs */); if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES && copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) { Slog.w(TAG, "Failure copying 32 bit native libraries; copyRet=" +copyRet); return copyRet; } } if (Build.SUPPORTED_64_BIT_ABIS.length > 0) { copyRet = copyNativeBinariesIfNeededLI(handle, libraryRoot, Build.SUPPORTED_64_BIT_ABIS, true /* use isa specific subdirs */); if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES && copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) { Slog.w(TAG, "Failure copying 64 bit native libraries; copyRet=" +copyRet); return copyRet; } } } else { String cpuAbiOverride = null; if (CLEAR_ABI_OVERRIDE.equals(abiOverride)) { cpuAbiOverride = null; } else if (abiOverride != null) { cpuAbiOverride = abiOverride; } String[] abiList = (cpuAbiOverride != null) ? new String[] { cpuAbiOverride } : Build.SUPPORTED_ABIS; if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null && hasRenderscriptBitcode(handle)) { abiList = Build.SUPPORTED_32_BIT_ABIS; } int copyRet = copyNativeBinariesIfNeededLI(handle, libraryRoot, abiList, true /* use isa specific subdirs */); if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) { Slog.w(TAG, "Failure copying native libraries [errorCode=" + copyRet + "]"); return copyRet; } } return PackageManager.INSTALL_SUCCEEDED; } catch (IOException e) { Slog.e(TAG, "Copying native libraries failed", e); return PackageManager.INSTALL_FAILED_INTERNAL_ERROR; } } public static long sumNativeBinaries(Handle handle, String abiOverride, boolean multiArch) throws IOException { long sum = 0; if (multiArch) { // Warn if we've set an abiOverride for multi-lib packages.. // By definition, we need to copy both 32 and 64 bit libraries for // such packages. if (abiOverride != null && !CLEAR_ABI_OVERRIDE.equals(abiOverride)) { Slog.w(TAG, "Ignoring abiOverride for multi arch application."); } if (Build.SUPPORTED_32_BIT_ABIS.length > 0) { sum += sumNativeBinaries(handle, Build.SUPPORTED_32_BIT_ABIS); } if (Build.SUPPORTED_64_BIT_ABIS.length > 0) { sum += sumNativeBinaries(handle, Build.SUPPORTED_64_BIT_ABIS); } } else { String cpuAbiOverride = null; if (CLEAR_ABI_OVERRIDE.equals(abiOverride)) { cpuAbiOverride = null; } else if (abiOverride != null) { cpuAbiOverride = abiOverride; } String[] abiList = (cpuAbiOverride != null) ? new String[] { cpuAbiOverride } : Build.SUPPORTED_ABIS; if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null && hasRenderscriptBitcode(handle)) { abiList = Build.SUPPORTED_32_BIT_ABIS; } sum += sumNativeBinaries(handle, abiList); } return sum; } // We don't care about the other return values for now. private static final int BITCODE_PRESENT = 1; private static native int hasRenderscriptBitcode(long apkHandle); public static boolean hasRenderscriptBitcode(Handle handle) throws IOException { for (long apkHandle : handle.apkHandles) { final int res = hasRenderscriptBitcode(apkHandle); Loading @@ -258,6 +424,4 @@ public class NativeLibraryHelper { } return false; } private static native int hasRenderscriptBitcode(long apkHandle); } core/java/com/android/internal/content/PackageHelper.java +40 −10 Original line number Diff line number Diff line Loading @@ -17,13 +17,17 @@ package com.android.internal.content; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Environment; import android.os.Environment.UserEnvironment; import android.os.FileUtils; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.os.storage.IMountService; import android.os.storage.StorageManager; import android.os.storage.StorageResultCode; Loading Loading @@ -215,7 +219,7 @@ public class PackageHelper { /** * Extract public files for the single given APK. */ public static int extractPublicFiles(String apkPath, File publicZipFile) public static long extractPublicFiles(File apkFile, File publicZipFile) throws IOException { final FileOutputStream fstr; final ZipOutputStream publicZipOutStream; Loading @@ -226,12 +230,13 @@ public class PackageHelper { } else { fstr = new FileOutputStream(publicZipFile); publicZipOutStream = new ZipOutputStream(fstr); Log.d(TAG, "Extracting " + apkFile + " to " + publicZipFile); } int size = 0; long size = 0L; try { final ZipFile privateZip = new ZipFile(apkPath); final ZipFile privateZip = new ZipFile(apkFile.getAbsolutePath()); try { // Copy manifest, resources.arsc and res directory to public zip for (final ZipEntry zipEntry : Collections.list(privateZip.entries())) { Loading Loading @@ -308,8 +313,15 @@ public class PackageHelper { * Given a requested {@link PackageInfo#installLocation} and calculated * install size, pick the actual location to install the app. */ public static int resolveInstallLocation(Context context, int installLocation, long sizeBytes, int installFlags) { public static int resolveInstallLocation(Context context, String packageName, int installLocation, long sizeBytes, int installFlags) { ApplicationInfo existingInfo = null; try { existingInfo = context.getPackageManager().getApplicationInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES); } catch (NameNotFoundException ignored) { } final int prefer; final boolean checkBoth; if ((installFlags & PackageManager.INSTALL_INTERNAL) != 0) { Loading @@ -325,7 +337,16 @@ public class PackageHelper { prefer = RECOMMEND_INSTALL_EXTERNAL; checkBoth = true; } else if (installLocation == PackageInfo.INSTALL_LOCATION_AUTO) { // When app is already installed, prefer same medium if (existingInfo != null) { if ((existingInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) { prefer = RECOMMEND_INSTALL_EXTERNAL; } else { prefer = RECOMMEND_INSTALL_INTERNAL; } } else { prefer = RECOMMEND_INSTALL_INTERNAL; } checkBoth = true; } else { prefer = RECOMMEND_INSTALL_INTERNAL; Loading @@ -337,14 +358,15 @@ public class PackageHelper { boolean fitsOnInternal = false; if (checkBoth || prefer == RECOMMEND_INSTALL_INTERNAL) { fitsOnInternal = (sizeBytes <= storage.getStorageBytesUntilLow(Environment.getDataDirectory())); final File target = Environment.getDataDirectory(); fitsOnInternal = (sizeBytes <= storage.getStorageBytesUntilLow(target)); } boolean fitsOnExternal = false; if (!emulated && (checkBoth || prefer == RECOMMEND_INSTALL_EXTERNAL)) { fitsOnExternal = (sizeBytes <= storage.getStorageBytesUntilLow(Environment.getExternalStorageDirectory())); final File target = new UserEnvironment(UserHandle.USER_OWNER) .getExternalStorageDirectory(); fitsOnExternal = (sizeBytes <= storage.getStorageBytesUntilLow(target)); } if (prefer == RECOMMEND_INSTALL_INTERNAL) { Loading Loading @@ -377,4 +399,12 @@ public class PackageHelper { return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE; } } public static String replaceEnd(String str, String before, String after) { if (!str.endsWith(before)) { throw new IllegalArgumentException( "Expected " + str + " to end with " + before); } return str.substring(0, str.length() - before.length()) + after; } } Loading
api/current.txt +1 −1 Original line number Diff line number Diff line Loading @@ -8668,7 +8668,7 @@ package android.content.pm { method public void removeSessionCallback(android.content.pm.PackageInstaller.SessionCallback); method public void uninstall(java.lang.String, android.content.IntentSender); field public static final java.lang.String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS"; field public static final java.lang.String EXTRA_PACKAGE_NAMES = "android.content.pm.extra.PACKAGE_NAMES"; field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME"; field public static final java.lang.String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID"; field public static final java.lang.String EXTRA_STATUS = "android.content.pm.extra.STATUS"; field public static final java.lang.String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE";
core/java/android/content/pm/PackageInstaller.java +8 −4 Original line number Diff line number Diff line Loading @@ -105,10 +105,14 @@ public class PackageInstaller { public static final String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE"; /** * List of package names that are relevant to a status. * Package name relevant to a status. * * @see Intent#getStringArrayExtra(String) * @see Intent#getStringExtra(String) */ public static final String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME"; /** {@hide} */ @Deprecated public static final String EXTRA_PACKAGE_NAMES = "android.content.pm.extra.PACKAGE_NAMES"; /** {@hide} */ Loading Loading @@ -178,8 +182,8 @@ public class PackageInstaller { * permission, incompatible certificates, etc. The user may be able to * uninstall another app to fix the issue. * <p> * The result may also contain {@link #EXTRA_PACKAGE_NAMES} with the * specific packages identified as the cause of the conflict. * The result may also contain {@link #EXTRA_PACKAGE_NAME} with the * specific package identified as the cause of the conflict. * * @see #EXTRA_STATUS_MESSAGE */ Loading
core/java/android/content/pm/PackageParser.java +8 −34 Original line number Diff line number Diff line Loading @@ -596,7 +596,7 @@ public class PackageParser { public final static int PARSE_ON_SDCARD = 1<<5; public final static int PARSE_IS_SYSTEM_DIR = 1<<6; public final static int PARSE_IS_PRIVILEGED = 1<<7; public final static int PARSE_GET_SIGNATURES = 1<<8; public final static int PARSE_COLLECT_CERTIFICATES = 1<<8; public final static int PARSE_TRUSTED_OVERLAY = 1<<9; private static final Comparator<String> sSplitNameComparator = new SplitNameComparator(); Loading Loading @@ -1087,34 +1087,6 @@ public class PackageParser { } } /** * Only collect certificates on the manifest; does not validate signatures * across remainder of package. */ private static Signature[] collectManifestCertificates(File apkFile) throws PackageParserException { final String apkPath = apkFile.getAbsolutePath(); try { final StrictJarFile jarFile = new StrictJarFile(apkPath); try { final ZipEntry jarEntry = jarFile.findEntry(ANDROID_MANIFEST_FILENAME); if (jarEntry == null) { throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, "Package " + apkPath + " has no manifest"); } final Certificate[][] certs = loadCertificates(jarFile, jarEntry); return convertToSignatures(certs); } finally { jarFile.close(); } } catch (GeneralSecurityException | IOException | RuntimeException e) { throw new PackageParserException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING, "Failed to collect certificates from " + apkPath, e); } } private static Signature[] convertToSignatures(Certificate[][] certs) throws CertificateEncodingException { final Signature[] res = new Signature[certs.length]; Loading @@ -1129,7 +1101,8 @@ public class PackageParser { * file, including package name, split name, and install location. * * @param apkFile path to a single APK * @param flags optional parse flags, such as {@link #PARSE_GET_SIGNATURES} * @param flags optional parse flags, such as * {@link #PARSE_COLLECT_CERTIFICATES} */ public static ApkLite parseApkLite(File apkFile, int flags) throws PackageParserException { Loading @@ -1154,11 +1127,12 @@ public class PackageParser { final Resources res = new Resources(assets, metrics, null); parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); // Only collect certificates on the manifest; does not validate // signatures across remainder of package. final Signature[] signatures; if ((flags & PARSE_GET_SIGNATURES) != 0) { signatures = collectManifestCertificates(apkFile); if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) { // TODO: factor signature related items out of Package object final Package tempPkg = new Package(null); collectCertificates(tempPkg, apkFile, 0); signatures = tempPkg.mSignatures; } else { signatures = null; } Loading
core/java/com/android/internal/content/NativeLibraryHelper.java +181 −17 Original line number Diff line number Diff line Loading @@ -19,15 +19,25 @@ package com.android.internal.content; import static android.content.pm.PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS; import static android.content.pm.PackageManager.INSTALL_SUCCEEDED; import static android.content.pm.PackageManager.NO_NATIVE_LIBRARIES; import static android.system.OsConstants.S_IRGRP; import static android.system.OsConstants.S_IROTH; import static android.system.OsConstants.S_IRWXU; import static android.system.OsConstants.S_IXGRP; import static android.system.OsConstants.S_IXOTH; import android.content.pm.PackageManager; import android.content.pm.PackageParser; import android.content.pm.PackageParser.Package; import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; import android.os.Build; import android.os.SELinux; import android.system.ErrnoException; import android.system.Os; import android.util.Slog; import dalvik.system.CloseGuard; import dalvik.system.VMRuntime; import java.io.Closeable; import java.io.File; Loading @@ -44,6 +54,10 @@ public class NativeLibraryHelper { private static final boolean DEBUG_NATIVE = false; // Special value for {@code PackageParser.Package#cpuAbiOverride} to indicate // that the cpuAbiOverride must be clear. public static final String CLEAR_ABI_OVERRIDE = "-"; /** * A handle to an opened package, consisting of one or more APKs. Used as * input to the various NativeLibraryHelper methods. Allows us to scan and Loading Loading @@ -126,27 +140,17 @@ public class NativeLibraryHelper { 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(Handle handle, String[] abis) { private native static int nativeCopyNativeBinaries(long handle, String sharedLibraryPath, String abiToCopy); private static long sumNativeBinaries(Handle handle, String abi) { long sum = 0; for (long apkHandle : handle.apkHandles) { // NOTE: For a given APK handle, we parse the central directory precisely // once, but prefix matching of entries requires a CD traversal, which can // take a while (even if it needs no additional I/O). for (String abi : abis) { sum += nativeSumNativeBinaries(apkHandle, abi); } } return sum; } private native static int nativeCopyNativeBinaries(long handle, String sharedLibraryPath, String abiToCopy); /** * Copies native binaries to a shared library directory. * Loading Loading @@ -244,9 +248,171 @@ public class NativeLibraryHelper { } } private static void createNativeLibrarySubdir(File path) throws IOException { if (!path.isDirectory()) { path.delete(); if (!path.mkdir()) { throw new IOException("Cannot create " + path.getPath()); } try { Os.chmod(path.getPath(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); } catch (ErrnoException e) { throw new IOException("Cannot chmod native library directory " + path.getPath(), e); } } else if (!SELinux.restorecon(path)) { throw new IOException("Cannot set SELinux context for " + path.getPath()); } } private static long sumNativeBinaries(Handle handle, String[] abiList) { int abi = findSupportedAbi(handle, abiList); if (abi >= 0) { return sumNativeBinaries(handle, abiList[abi]); } else { return 0; } } public static int copyNativeBinariesIfNeededLI(Handle handle, File libraryRoot, String[] abiList, boolean useIsaSubdir) throws IOException { createNativeLibrarySubdir(libraryRoot); /* * If this is an internal application or our nativeLibraryPath points to * the app-lib directory, unpack the libraries if necessary. */ int abi = findSupportedAbi(handle, abiList); if (abi >= 0) { /* * If we have a matching instruction set, construct a subdir under the native * library root that corresponds to this instruction set. */ final String instructionSet = VMRuntime.getInstructionSet(abiList[abi]); final File subDir; if (useIsaSubdir) { final File isaSubdir = new File(libraryRoot, instructionSet); createNativeLibrarySubdir(isaSubdir); subDir = isaSubdir; } else { subDir = libraryRoot; } int copyRet = copyNativeBinariesIfNeededLI(handle, subDir, abiList[abi]); if (copyRet != PackageManager.INSTALL_SUCCEEDED) { return copyRet; } } return abi; } public static int copyNativeBinariesIfNeededLI(Handle handle, File libraryRoot, String abiOverride, boolean multiArch) { try { if (multiArch) { // Warn if we've set an abiOverride for multi-lib packages.. // By definition, we need to copy both 32 and 64 bit libraries for // such packages. if (abiOverride != null && !CLEAR_ABI_OVERRIDE.equals(abiOverride)) { Slog.w(TAG, "Ignoring abiOverride for multi arch application."); } int copyRet = PackageManager.NO_NATIVE_LIBRARIES; if (Build.SUPPORTED_32_BIT_ABIS.length > 0) { copyRet = copyNativeBinariesIfNeededLI(handle, libraryRoot, Build.SUPPORTED_32_BIT_ABIS, true /* use isa specific subdirs */); if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES && copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) { Slog.w(TAG, "Failure copying 32 bit native libraries; copyRet=" +copyRet); return copyRet; } } if (Build.SUPPORTED_64_BIT_ABIS.length > 0) { copyRet = copyNativeBinariesIfNeededLI(handle, libraryRoot, Build.SUPPORTED_64_BIT_ABIS, true /* use isa specific subdirs */); if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES && copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) { Slog.w(TAG, "Failure copying 64 bit native libraries; copyRet=" +copyRet); return copyRet; } } } else { String cpuAbiOverride = null; if (CLEAR_ABI_OVERRIDE.equals(abiOverride)) { cpuAbiOverride = null; } else if (abiOverride != null) { cpuAbiOverride = abiOverride; } String[] abiList = (cpuAbiOverride != null) ? new String[] { cpuAbiOverride } : Build.SUPPORTED_ABIS; if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null && hasRenderscriptBitcode(handle)) { abiList = Build.SUPPORTED_32_BIT_ABIS; } int copyRet = copyNativeBinariesIfNeededLI(handle, libraryRoot, abiList, true /* use isa specific subdirs */); if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) { Slog.w(TAG, "Failure copying native libraries [errorCode=" + copyRet + "]"); return copyRet; } } return PackageManager.INSTALL_SUCCEEDED; } catch (IOException e) { Slog.e(TAG, "Copying native libraries failed", e); return PackageManager.INSTALL_FAILED_INTERNAL_ERROR; } } public static long sumNativeBinaries(Handle handle, String abiOverride, boolean multiArch) throws IOException { long sum = 0; if (multiArch) { // Warn if we've set an abiOverride for multi-lib packages.. // By definition, we need to copy both 32 and 64 bit libraries for // such packages. if (abiOverride != null && !CLEAR_ABI_OVERRIDE.equals(abiOverride)) { Slog.w(TAG, "Ignoring abiOverride for multi arch application."); } if (Build.SUPPORTED_32_BIT_ABIS.length > 0) { sum += sumNativeBinaries(handle, Build.SUPPORTED_32_BIT_ABIS); } if (Build.SUPPORTED_64_BIT_ABIS.length > 0) { sum += sumNativeBinaries(handle, Build.SUPPORTED_64_BIT_ABIS); } } else { String cpuAbiOverride = null; if (CLEAR_ABI_OVERRIDE.equals(abiOverride)) { cpuAbiOverride = null; } else if (abiOverride != null) { cpuAbiOverride = abiOverride; } String[] abiList = (cpuAbiOverride != null) ? new String[] { cpuAbiOverride } : Build.SUPPORTED_ABIS; if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null && hasRenderscriptBitcode(handle)) { abiList = Build.SUPPORTED_32_BIT_ABIS; } sum += sumNativeBinaries(handle, abiList); } return sum; } // We don't care about the other return values for now. private static final int BITCODE_PRESENT = 1; private static native int hasRenderscriptBitcode(long apkHandle); public static boolean hasRenderscriptBitcode(Handle handle) throws IOException { for (long apkHandle : handle.apkHandles) { final int res = hasRenderscriptBitcode(apkHandle); Loading @@ -258,6 +424,4 @@ public class NativeLibraryHelper { } return false; } private static native int hasRenderscriptBitcode(long apkHandle); }
core/java/com/android/internal/content/PackageHelper.java +40 −10 Original line number Diff line number Diff line Loading @@ -17,13 +17,17 @@ package com.android.internal.content; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Environment; import android.os.Environment.UserEnvironment; import android.os.FileUtils; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.os.storage.IMountService; import android.os.storage.StorageManager; import android.os.storage.StorageResultCode; Loading Loading @@ -215,7 +219,7 @@ public class PackageHelper { /** * Extract public files for the single given APK. */ public static int extractPublicFiles(String apkPath, File publicZipFile) public static long extractPublicFiles(File apkFile, File publicZipFile) throws IOException { final FileOutputStream fstr; final ZipOutputStream publicZipOutStream; Loading @@ -226,12 +230,13 @@ public class PackageHelper { } else { fstr = new FileOutputStream(publicZipFile); publicZipOutStream = new ZipOutputStream(fstr); Log.d(TAG, "Extracting " + apkFile + " to " + publicZipFile); } int size = 0; long size = 0L; try { final ZipFile privateZip = new ZipFile(apkPath); final ZipFile privateZip = new ZipFile(apkFile.getAbsolutePath()); try { // Copy manifest, resources.arsc and res directory to public zip for (final ZipEntry zipEntry : Collections.list(privateZip.entries())) { Loading Loading @@ -308,8 +313,15 @@ public class PackageHelper { * Given a requested {@link PackageInfo#installLocation} and calculated * install size, pick the actual location to install the app. */ public static int resolveInstallLocation(Context context, int installLocation, long sizeBytes, int installFlags) { public static int resolveInstallLocation(Context context, String packageName, int installLocation, long sizeBytes, int installFlags) { ApplicationInfo existingInfo = null; try { existingInfo = context.getPackageManager().getApplicationInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES); } catch (NameNotFoundException ignored) { } final int prefer; final boolean checkBoth; if ((installFlags & PackageManager.INSTALL_INTERNAL) != 0) { Loading @@ -325,7 +337,16 @@ public class PackageHelper { prefer = RECOMMEND_INSTALL_EXTERNAL; checkBoth = true; } else if (installLocation == PackageInfo.INSTALL_LOCATION_AUTO) { // When app is already installed, prefer same medium if (existingInfo != null) { if ((existingInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) { prefer = RECOMMEND_INSTALL_EXTERNAL; } else { prefer = RECOMMEND_INSTALL_INTERNAL; } } else { prefer = RECOMMEND_INSTALL_INTERNAL; } checkBoth = true; } else { prefer = RECOMMEND_INSTALL_INTERNAL; Loading @@ -337,14 +358,15 @@ public class PackageHelper { boolean fitsOnInternal = false; if (checkBoth || prefer == RECOMMEND_INSTALL_INTERNAL) { fitsOnInternal = (sizeBytes <= storage.getStorageBytesUntilLow(Environment.getDataDirectory())); final File target = Environment.getDataDirectory(); fitsOnInternal = (sizeBytes <= storage.getStorageBytesUntilLow(target)); } boolean fitsOnExternal = false; if (!emulated && (checkBoth || prefer == RECOMMEND_INSTALL_EXTERNAL)) { fitsOnExternal = (sizeBytes <= storage.getStorageBytesUntilLow(Environment.getExternalStorageDirectory())); final File target = new UserEnvironment(UserHandle.USER_OWNER) .getExternalStorageDirectory(); fitsOnExternal = (sizeBytes <= storage.getStorageBytesUntilLow(target)); } if (prefer == RECOMMEND_INSTALL_INTERNAL) { Loading Loading @@ -377,4 +399,12 @@ public class PackageHelper { return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE; } } public static String replaceEnd(String str, String before, String after) { if (!str.endsWith(before)) { throw new IllegalArgumentException( "Expected " + str + " to end with " + before); } return str.substring(0, str.length() - before.length()) + after; } }