Loading core/java/android/content/pm/ApplicationInfo.java +56 −5 Original line number Original line Diff line number Diff line Loading @@ -491,13 +491,55 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { public String nativeLibraryDir; public String nativeLibraryDir; /** /** * The ABI that this application requires, This is inferred from the ABIs * The path under the apps data directory we store unpacked libraries. For * new installs, we create subdirectories under legacyNativeLibraryDir that are * architecture specific. For legacy installs, the shared libraries are * placed directly under this path. * * For "legacy" installs {@code nativeLibraryDir} will be equal to this path. * For newer installs, it will be derived based on the codePath and the primary * cpu abi. * * @hide. */ public String legacyNativeLibraryDir; /** * The primary ABI that this application requires, This is inferred from the ABIs * of the native JNI libraries the application bundles. Will be {@code null} * of the native JNI libraries the application bundles. Will be {@code null} * if this application does not require any particular ABI. * if this application does not require any particular ABI. * * * If non-null, the application will always be launched with this ABI. * * {@hide} */ public String primaryCpuAbi; /** * The secondary ABI for this application. Might be non-null for multi-arch * installs. The application itself never uses this ABI, but other applications that * use its code might. * * {@hide} */ public String secondaryCpuAbi; /** * The derived APK "root" for the given package. Will be non-null for bundled and * updated system apps. This will be a top level path under which apks and libraries * are installed, for eg. {@code /system}, {@code /oem} or {@code /vendor}. This is * used to calculate the location of native code for a given package, for e.g * {@code /vendor/lib} or {@code /vendor/lib64}. * * For app updates or fresh app installs, this will be {@code null} and we will use * {@code legacyNativeLibraryDir} * * NOTE: This can be removed if we have a unified layout for bundled and installed * apps. * * {@hide} * {@hide} */ */ public String cpuAbi; public String apkRoot; /** /** * The kernel user-ID that has been assigned to this application; * The kernel user-ID that has been assigned to this application; Loading Loading @@ -641,7 +683,10 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { splitSourceDirs = orig.splitSourceDirs; splitSourceDirs = orig.splitSourceDirs; splitPublicSourceDirs = orig.splitPublicSourceDirs; splitPublicSourceDirs = orig.splitPublicSourceDirs; nativeLibraryDir = orig.nativeLibraryDir; nativeLibraryDir = orig.nativeLibraryDir; cpuAbi = orig.cpuAbi; legacyNativeLibraryDir = orig.legacyNativeLibraryDir; primaryCpuAbi = orig.primaryCpuAbi; secondaryCpuAbi = orig.secondaryCpuAbi; apkRoot = orig.apkRoot; resourceDirs = orig.resourceDirs; resourceDirs = orig.resourceDirs; seinfo = orig.seinfo; seinfo = orig.seinfo; sharedLibraryFiles = orig.sharedLibraryFiles; sharedLibraryFiles = orig.sharedLibraryFiles; Loading Loading @@ -685,7 +730,10 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { dest.writeStringArray(splitSourceDirs); dest.writeStringArray(splitSourceDirs); dest.writeStringArray(splitPublicSourceDirs); dest.writeStringArray(splitPublicSourceDirs); dest.writeString(nativeLibraryDir); dest.writeString(nativeLibraryDir); dest.writeString(cpuAbi); dest.writeString(legacyNativeLibraryDir); dest.writeString(primaryCpuAbi); dest.writeString(secondaryCpuAbi); dest.writeString(apkRoot); dest.writeStringArray(resourceDirs); dest.writeStringArray(resourceDirs); dest.writeString(seinfo); dest.writeString(seinfo); dest.writeStringArray(sharedLibraryFiles); dest.writeStringArray(sharedLibraryFiles); Loading Loading @@ -728,7 +776,10 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { splitSourceDirs = source.readStringArray(); splitSourceDirs = source.readStringArray(); splitPublicSourceDirs = source.readStringArray(); splitPublicSourceDirs = source.readStringArray(); nativeLibraryDir = source.readString(); nativeLibraryDir = source.readString(); cpuAbi = source.readString(); legacyNativeLibraryDir = source.readString(); primaryCpuAbi = source.readString(); secondaryCpuAbi = source.readString(); apkRoot = source.readString(); resourceDirs = source.readStringArray(); resourceDirs = source.readStringArray(); seinfo = source.readString(); seinfo = source.readString(); sharedLibraryFiles = source.readStringArray(); sharedLibraryFiles = source.readStringArray(); Loading core/java/android/content/pm/PackageInfoLite.java +7 −0 Original line number Original line Diff line number Diff line Loading @@ -36,6 +36,13 @@ public class PackageInfoLite implements Parcelable { */ */ public int versionCode; public int versionCode; /** * The android:multiArch flag from the package manifest. If set, * we will extract all native libraries for the given app, not just those * from the preferred ABI. */ public boolean multiArch; /** /** * Specifies the recommended install location. Can be one of * Specifies the recommended install location. Can be one of * {@link #PackageHelper.RECOMMEND_INSTALL_INTERNAL} to install on internal storage * {@link #PackageHelper.RECOMMEND_INSTALL_INTERNAL} to install on internal storage Loading core/java/android/content/pm/PackageParser.java +13 −3 Original line number Original line Diff line number Diff line Loading @@ -249,6 +249,8 @@ public class PackageParser { /** Paths of any split APKs, ordered by parsed splitName */ /** Paths of any split APKs, ordered by parsed splitName */ public final String[] splitCodePaths; public final String[] splitCodePaths; public final boolean multiArch; private PackageLite(String codePath, ApkLite baseApk, String[] splitNames, private PackageLite(String codePath, ApkLite baseApk, String[] splitNames, String[] splitCodePaths) { String[] splitCodePaths) { this.packageName = baseApk.packageName; this.packageName = baseApk.packageName; Loading @@ -259,6 +261,7 @@ public class PackageParser { this.codePath = codePath; this.codePath = codePath; this.baseCodePath = baseApk.codePath; this.baseCodePath = baseApk.codePath; this.splitCodePaths = splitCodePaths; this.splitCodePaths = splitCodePaths; this.multiArch = baseApk.multiArch; } } public List<String> getAllCodePaths() { public List<String> getAllCodePaths() { Loading @@ -282,9 +285,11 @@ public class PackageParser { public final int installLocation; public final int installLocation; public final VerifierInfo[] verifiers; public final VerifierInfo[] verifiers; public final Signature[] signatures; public final Signature[] signatures; public final boolean multiArch; public ApkLite(String codePath, String packageName, String splitName, int versionCode, public ApkLite(String codePath, String packageName, String splitName, int versionCode, int installLocation, List<VerifierInfo> verifiers, Signature[] signatures) { int installLocation, List<VerifierInfo> verifiers, Signature[] signatures, boolean multiArch) { this.codePath = codePath; this.codePath = codePath; this.packageName = packageName; this.packageName = packageName; this.splitName = splitName; this.splitName = splitName; Loading @@ -292,6 +297,7 @@ public class PackageParser { this.installLocation = installLocation; this.installLocation = installLocation; this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]); this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]); this.signatures = signatures; this.signatures = signatures; this.multiArch = multiArch; } } } } Loading Loading @@ -1114,6 +1120,7 @@ public class PackageParser { int installLocation = PARSE_DEFAULT_INSTALL_LOCATION; int installLocation = PARSE_DEFAULT_INSTALL_LOCATION; int versionCode = 0; int versionCode = 0; int numFound = 0; int numFound = 0; boolean multiArch = false; for (int i = 0; i < attrs.getAttributeCount(); i++) { for (int i = 0; i < attrs.getAttributeCount(); i++) { String attr = attrs.getAttributeName(i); String attr = attrs.getAttributeName(i); if (attr.equals("installLocation")) { if (attr.equals("installLocation")) { Loading @@ -1123,8 +1130,11 @@ public class PackageParser { } else if (attr.equals("versionCode")) { } else if (attr.equals("versionCode")) { versionCode = attrs.getAttributeIntValue(i, 0); versionCode = attrs.getAttributeIntValue(i, 0); numFound++; numFound++; } else if (attr.equals("multiArch")) { multiArch = attrs.getAttributeBooleanValue(i, false); numFound++; } } if (numFound >= 2) { if (numFound >= 3) { break; break; } } } } Loading @@ -1149,7 +1159,7 @@ public class PackageParser { } } return new ApkLite(codePath, packageSplit.first, packageSplit.second, versionCode, return new ApkLite(codePath, packageSplit.first, packageSplit.second, versionCode, installLocation, verifiers, signatures); installLocation, verifiers, signatures, multiArch); } } /** /** Loading core/java/com/android/internal/content/NativeLibraryHelper.java +31 −24 Original line number Original line Diff line number Diff line Loading @@ -131,11 +131,16 @@ public class NativeLibraryHelper { * * * @return size of all native binary files in bytes * @return size of all native binary files in bytes */ */ public static long sumNativeBinariesLI(Handle handle, String abi) { public static long sumNativeBinariesLI(Handle handle, String[] abis) { long sum = 0; long sum = 0; for (long apkHandle : handle.apkHandles) { 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); sum += nativeSumNativeBinaries(apkHandle, abi); } } } return sum; return sum; } } Loading Loading @@ -196,45 +201,47 @@ public class NativeLibraryHelper { private native static int nativeFindSupportedAbi(long handle, String[] supportedAbis); private native static int nativeFindSupportedAbi(long handle, String[] supportedAbis); // Convenience method to call removeNativeBinariesFromDirLI(File) // Convenience method to call removeNativeBinariesFromDirLI(File) public static boolean removeNativeBinariesLI(String nativeLibraryPath) { public static void removeNativeBinariesLI(String nativeLibraryPath) { if (nativeLibraryPath == null) return false; if (nativeLibraryPath == null) return; return removeNativeBinariesFromDirLI(new File(nativeLibraryPath)); removeNativeBinariesFromDirLI(new File(nativeLibraryPath), false /* delete root dir */); } } // Remove the native binaries of a given package. This simply /** // gets rid of the files in the 'lib' sub-directory. * Remove the native binaries of a given package. This deletes the files public static boolean removeNativeBinariesFromDirLI(File nativeLibraryDir) { */ public static void removeNativeBinariesFromDirLI(File nativeLibraryRoot, boolean deleteRootDir) { if (DEBUG_NATIVE) { if (DEBUG_NATIVE) { Slog.w(TAG, "Deleting native binaries from: " + nativeLibraryDir.getPath()); Slog.w(TAG, "Deleting native binaries from: " + nativeLibraryRoot.getPath()); } } boolean deletedFiles = false; /* /* * Just remove any file in the directory. Since the directory is owned * Just remove any file in the directory. Since the directory is owned * by the 'system' UID, the application is not supposed to have written * by the 'system' UID, the application is not supposed to have written * anything there. * anything there. */ */ if (nativeLibraryDir.exists()) { if (nativeLibraryRoot.exists()) { final File[] binaries = nativeLibraryDir.listFiles(); final File[] files = nativeLibraryRoot.listFiles(); if (binaries != null) { if (files != null) { for (int nn = 0; nn < binaries.length; nn++) { for (int nn = 0; nn < files.length; nn++) { if (DEBUG_NATIVE) { if (DEBUG_NATIVE) { Slog.d(TAG, " Deleting " + binaries[nn].getName()); Slog.d(TAG, " Deleting " + files[nn].getName()); } } if (!binaries[nn].delete()) { if (files[nn].isDirectory()) { Slog.w(TAG, "Could not delete native binary: " + binaries[nn].getPath()); removeNativeBinariesFromDirLI(files[nn], true /* delete root dir */); } else { } else if (!files[nn].delete()) { deletedFiles = true; Slog.w(TAG, "Could not delete native binary: " + files[nn].getPath()); } } } } } } // Do not delete 'lib' directory itself, or this will prevent // Do not delete 'lib' directory itself, unless we're specifically // installation of future updates. // asked to or this will prevent installation of future updates. if (deleteRootDir) { if (!nativeLibraryRoot.delete()) { Slog.w(TAG, "Could not delete native binary directory: " + nativeLibraryRoot.getPath()); } } } } return deletedFiles; } } // We don't care about the other return values for now. // We don't care about the other return values for now. Loading packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java +71 −35 Original line number Original line Diff line number Diff line Loading @@ -50,6 +50,7 @@ import com.android.internal.content.PackageHelper; import com.android.internal.os.IParcelFileDescriptorFactory; import com.android.internal.os.IParcelFileDescriptorFactory; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ArrayUtils; import dalvik.system.VMRuntime; import libcore.io.IoUtils; import libcore.io.IoUtils; import libcore.io.Streams; import libcore.io.Streams; Loading Loading @@ -186,6 +187,7 @@ public class DefaultContainerService extends IntentService { ret.verifiers = pkg.verifiers; ret.verifiers = pkg.verifiers; ret.recommendedInstallLocation = recommendAppInstallLocation(pkg, flags, threshold, ret.recommendedInstallLocation = recommendAppInstallLocation(pkg, flags, threshold, abiOverride); abiOverride); ret.multiArch = pkg.multiArch; return ret; return ret; } } Loading Loading @@ -363,31 +365,26 @@ public class DefaultContainerService extends IntentService { final String resFileName = "pkg.apk"; final String resFileName = "pkg.apk"; final String publicResFileName = "res.zip"; final String publicResFileName = "res.zip"; // The .apk file if (pkg.multiArch) { String codePath = pkg.baseCodePath; // TODO: Support multiArch installs on ASEC. File codeFile = new File(codePath); throw new IllegalArgumentException("multiArch not supported on ASEC installs."); } String[] abiList = Build.SUPPORTED_ABIS; // The .apk file if (abiOverride != null) { final String codePath = pkg.baseCodePath; abiList = new String[] { abiOverride }; final File codeFile = new File(codePath); } else { final String[] abis; try { try { if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && abis = calculateAbiList(handle, abiOverride, pkg.multiArch); NativeLibraryHelper.hasRenderscriptBitcode(handle)) { abiList = Build.SUPPORTED_32_BIT_ABIS; } } catch (IOException ioe) { } catch (IOException ioe) { Slog.w(TAG, "Problem determining ABI for: " + codeFile.getPath()); Slog.w(TAG, "Problem determining app ABIS: " + ioe); return null; return null; } } } final int abiIndex = NativeLibraryHelper.findSupportedAbi(handle, abiList); // Calculate size of container needed to hold base APK. // Calculate size of container needed to hold base APK. final int sizeMb; final int sizeMb; try { try { sizeMb = calculateContainerSize(pkg, handle, isForwardLocked, abiIndex); sizeMb = calculateContainerSize(pkg, handle, isForwardLocked, abis); } catch (IOException e) { } catch (IOException e) { Slog.w(TAG, "Problem when trying to copy " + codeFile.getPath()); Slog.w(TAG, "Problem when trying to copy " + codeFile.getPath()); return null; return null; Loading Loading @@ -451,18 +448,19 @@ public class DefaultContainerService extends IntentService { final File sharedLibraryDir = new File(newCachePath, LIB_DIR_NAME); final File sharedLibraryDir = new File(newCachePath, LIB_DIR_NAME); if (sharedLibraryDir.mkdir()) { if (sharedLibraryDir.mkdir()) { int ret = PackageManager.INSTALL_SUCCEEDED; int ret = PackageManager.INSTALL_SUCCEEDED; if (abiIndex >= 0) { if (abis != null) { // TODO(multiArch): Support multi-arch installs on asecs. Note that we are NOT // using an ISA specific subdir here for now. final String abi = abis[0]; ret = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle, ret = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle, sharedLibraryDir, abiList[abiIndex]); sharedLibraryDir, abi); } else if (abiIndex != PackageManager.NO_NATIVE_LIBRARIES) { ret = abiIndex; } if (ret != PackageManager.INSTALL_SUCCEEDED) { if (ret != PackageManager.INSTALL_SUCCEEDED) { Slog.e(TAG, "Could not copy native libraries to " + sharedLibraryDir.getPath()); Slog.e(TAG, "Could not copy native libraries to " + sharedLibraryDir.getPath()); PackageHelper.destroySdDir(newCid); PackageHelper.destroySdDir(newCid); return null; return null; } } } } else { } else { Slog.e(TAG, "Could not create native lib directory: " + sharedLibraryDir.getPath()); Slog.e(TAG, "Could not create native lib directory: " + sharedLibraryDir.getPath()); PackageHelper.destroySdDir(newCid); PackageHelper.destroySdDir(newCid); Loading Loading @@ -687,14 +685,53 @@ public class DefaultContainerService extends IntentService { NativeLibraryHelper.Handle handle = null; NativeLibraryHelper.Handle handle = null; try { try { handle = NativeLibraryHelper.Handle.create(pkg); handle = NativeLibraryHelper.Handle.create(pkg); final int abi = NativeLibraryHelper.findSupportedAbi(handle, return calculateContainerSize(pkg, handle, isForwardLocked, (abiOverride != null) ? new String[] { abiOverride } : Build.SUPPORTED_ABIS); calculateAbiList(handle, abiOverride, pkg.multiArch)); return calculateContainerSize(pkg, handle, isForwardLocked, abi); } finally { } finally { IoUtils.closeQuietly(handle); IoUtils.closeQuietly(handle); } } } } private String[] calculateAbiList(NativeLibraryHelper.Handle handle, String abiOverride, boolean isMultiArch) throws IOException { if (isMultiArch) { final int abi32 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_32_BIT_ABIS); final int abi64 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_64_BIT_ABIS); if (abi32 >= 0 && abi64 >= 0) { return new String[] { Build.SUPPORTED_64_BIT_ABIS[abi64], Build.SUPPORTED_32_BIT_ABIS[abi32] }; } else if (abi64 >= 0) { return new String[] { Build.SUPPORTED_64_BIT_ABIS[abi64] }; } else if (abi32 >= 0) { return new String[] { Build.SUPPORTED_32_BIT_ABIS[abi32] }; } if (abi64 != PackageManager.NO_NATIVE_LIBRARIES || abi32 != PackageManager.NO_NATIVE_LIBRARIES) { throw new IOException("Error determining ABI list: errorCode=[" + abi32 + "," + abi64 + "]"); } } else { String[] abiList = Build.SUPPORTED_ABIS; if (abiOverride != null) { abiList = new String[] { abiOverride }; } else if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && NativeLibraryHelper.hasRenderscriptBitcode(handle)) { abiList = Build.SUPPORTED_32_BIT_ABIS; } final int abi = NativeLibraryHelper.findSupportedAbi(handle,abiList); if (abi >= 0) { return new String[]{Build.SUPPORTED_ABIS[abi]}; } if (abi != PackageManager.NO_NATIVE_LIBRARIES) { throw new IOException("Error determining ABI list: errorCode=" + abi); } } return null; } /** /** * Calculate the container size for a package. * Calculate the container size for a package. * * Loading @@ -702,7 +739,7 @@ public class DefaultContainerService extends IntentService { * @throws IOException when there is a problem reading the file * @throws IOException when there is a problem reading the file */ */ private int calculateContainerSize(PackageLite pkg, NativeLibraryHelper.Handle handle, private int calculateContainerSize(PackageLite pkg, NativeLibraryHelper.Handle handle, boolean isForwardLocked, int abiIndex) throws IOException { boolean isForwardLocked, String[] abis) throws IOException { // Calculate size of container needed to hold APKs. // Calculate size of container needed to hold APKs. long sizeBytes = 0; long sizeBytes = 0; for (String codePath : pkg.getAllCodePaths()) { for (String codePath : pkg.getAllCodePaths()) { Loading @@ -715,9 +752,8 @@ public class DefaultContainerService extends IntentService { // Check all the native files that need to be copied and add that to the // Check all the native files that need to be copied and add that to the // container size. // container size. if (abiIndex >= 0) { if (abis != null) { sizeBytes += NativeLibraryHelper.sumNativeBinariesLI(handle, sizeBytes += NativeLibraryHelper.sumNativeBinariesLI(handle, abis); Build.SUPPORTED_ABIS[abiIndex]); } } int sizeMb = (int) (sizeBytes >> 20); int sizeMb = (int) (sizeBytes >> 20); Loading Loading
core/java/android/content/pm/ApplicationInfo.java +56 −5 Original line number Original line Diff line number Diff line Loading @@ -491,13 +491,55 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { public String nativeLibraryDir; public String nativeLibraryDir; /** /** * The ABI that this application requires, This is inferred from the ABIs * The path under the apps data directory we store unpacked libraries. For * new installs, we create subdirectories under legacyNativeLibraryDir that are * architecture specific. For legacy installs, the shared libraries are * placed directly under this path. * * For "legacy" installs {@code nativeLibraryDir} will be equal to this path. * For newer installs, it will be derived based on the codePath and the primary * cpu abi. * * @hide. */ public String legacyNativeLibraryDir; /** * The primary ABI that this application requires, This is inferred from the ABIs * of the native JNI libraries the application bundles. Will be {@code null} * of the native JNI libraries the application bundles. Will be {@code null} * if this application does not require any particular ABI. * if this application does not require any particular ABI. * * * If non-null, the application will always be launched with this ABI. * * {@hide} */ public String primaryCpuAbi; /** * The secondary ABI for this application. Might be non-null for multi-arch * installs. The application itself never uses this ABI, but other applications that * use its code might. * * {@hide} */ public String secondaryCpuAbi; /** * The derived APK "root" for the given package. Will be non-null for bundled and * updated system apps. This will be a top level path under which apks and libraries * are installed, for eg. {@code /system}, {@code /oem} or {@code /vendor}. This is * used to calculate the location of native code for a given package, for e.g * {@code /vendor/lib} or {@code /vendor/lib64}. * * For app updates or fresh app installs, this will be {@code null} and we will use * {@code legacyNativeLibraryDir} * * NOTE: This can be removed if we have a unified layout for bundled and installed * apps. * * {@hide} * {@hide} */ */ public String cpuAbi; public String apkRoot; /** /** * The kernel user-ID that has been assigned to this application; * The kernel user-ID that has been assigned to this application; Loading Loading @@ -641,7 +683,10 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { splitSourceDirs = orig.splitSourceDirs; splitSourceDirs = orig.splitSourceDirs; splitPublicSourceDirs = orig.splitPublicSourceDirs; splitPublicSourceDirs = orig.splitPublicSourceDirs; nativeLibraryDir = orig.nativeLibraryDir; nativeLibraryDir = orig.nativeLibraryDir; cpuAbi = orig.cpuAbi; legacyNativeLibraryDir = orig.legacyNativeLibraryDir; primaryCpuAbi = orig.primaryCpuAbi; secondaryCpuAbi = orig.secondaryCpuAbi; apkRoot = orig.apkRoot; resourceDirs = orig.resourceDirs; resourceDirs = orig.resourceDirs; seinfo = orig.seinfo; seinfo = orig.seinfo; sharedLibraryFiles = orig.sharedLibraryFiles; sharedLibraryFiles = orig.sharedLibraryFiles; Loading Loading @@ -685,7 +730,10 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { dest.writeStringArray(splitSourceDirs); dest.writeStringArray(splitSourceDirs); dest.writeStringArray(splitPublicSourceDirs); dest.writeStringArray(splitPublicSourceDirs); dest.writeString(nativeLibraryDir); dest.writeString(nativeLibraryDir); dest.writeString(cpuAbi); dest.writeString(legacyNativeLibraryDir); dest.writeString(primaryCpuAbi); dest.writeString(secondaryCpuAbi); dest.writeString(apkRoot); dest.writeStringArray(resourceDirs); dest.writeStringArray(resourceDirs); dest.writeString(seinfo); dest.writeString(seinfo); dest.writeStringArray(sharedLibraryFiles); dest.writeStringArray(sharedLibraryFiles); Loading Loading @@ -728,7 +776,10 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { splitSourceDirs = source.readStringArray(); splitSourceDirs = source.readStringArray(); splitPublicSourceDirs = source.readStringArray(); splitPublicSourceDirs = source.readStringArray(); nativeLibraryDir = source.readString(); nativeLibraryDir = source.readString(); cpuAbi = source.readString(); legacyNativeLibraryDir = source.readString(); primaryCpuAbi = source.readString(); secondaryCpuAbi = source.readString(); apkRoot = source.readString(); resourceDirs = source.readStringArray(); resourceDirs = source.readStringArray(); seinfo = source.readString(); seinfo = source.readString(); sharedLibraryFiles = source.readStringArray(); sharedLibraryFiles = source.readStringArray(); Loading
core/java/android/content/pm/PackageInfoLite.java +7 −0 Original line number Original line Diff line number Diff line Loading @@ -36,6 +36,13 @@ public class PackageInfoLite implements Parcelable { */ */ public int versionCode; public int versionCode; /** * The android:multiArch flag from the package manifest. If set, * we will extract all native libraries for the given app, not just those * from the preferred ABI. */ public boolean multiArch; /** /** * Specifies the recommended install location. Can be one of * Specifies the recommended install location. Can be one of * {@link #PackageHelper.RECOMMEND_INSTALL_INTERNAL} to install on internal storage * {@link #PackageHelper.RECOMMEND_INSTALL_INTERNAL} to install on internal storage Loading
core/java/android/content/pm/PackageParser.java +13 −3 Original line number Original line Diff line number Diff line Loading @@ -249,6 +249,8 @@ public class PackageParser { /** Paths of any split APKs, ordered by parsed splitName */ /** Paths of any split APKs, ordered by parsed splitName */ public final String[] splitCodePaths; public final String[] splitCodePaths; public final boolean multiArch; private PackageLite(String codePath, ApkLite baseApk, String[] splitNames, private PackageLite(String codePath, ApkLite baseApk, String[] splitNames, String[] splitCodePaths) { String[] splitCodePaths) { this.packageName = baseApk.packageName; this.packageName = baseApk.packageName; Loading @@ -259,6 +261,7 @@ public class PackageParser { this.codePath = codePath; this.codePath = codePath; this.baseCodePath = baseApk.codePath; this.baseCodePath = baseApk.codePath; this.splitCodePaths = splitCodePaths; this.splitCodePaths = splitCodePaths; this.multiArch = baseApk.multiArch; } } public List<String> getAllCodePaths() { public List<String> getAllCodePaths() { Loading @@ -282,9 +285,11 @@ public class PackageParser { public final int installLocation; public final int installLocation; public final VerifierInfo[] verifiers; public final VerifierInfo[] verifiers; public final Signature[] signatures; public final Signature[] signatures; public final boolean multiArch; public ApkLite(String codePath, String packageName, String splitName, int versionCode, public ApkLite(String codePath, String packageName, String splitName, int versionCode, int installLocation, List<VerifierInfo> verifiers, Signature[] signatures) { int installLocation, List<VerifierInfo> verifiers, Signature[] signatures, boolean multiArch) { this.codePath = codePath; this.codePath = codePath; this.packageName = packageName; this.packageName = packageName; this.splitName = splitName; this.splitName = splitName; Loading @@ -292,6 +297,7 @@ public class PackageParser { this.installLocation = installLocation; this.installLocation = installLocation; this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]); this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]); this.signatures = signatures; this.signatures = signatures; this.multiArch = multiArch; } } } } Loading Loading @@ -1114,6 +1120,7 @@ public class PackageParser { int installLocation = PARSE_DEFAULT_INSTALL_LOCATION; int installLocation = PARSE_DEFAULT_INSTALL_LOCATION; int versionCode = 0; int versionCode = 0; int numFound = 0; int numFound = 0; boolean multiArch = false; for (int i = 0; i < attrs.getAttributeCount(); i++) { for (int i = 0; i < attrs.getAttributeCount(); i++) { String attr = attrs.getAttributeName(i); String attr = attrs.getAttributeName(i); if (attr.equals("installLocation")) { if (attr.equals("installLocation")) { Loading @@ -1123,8 +1130,11 @@ public class PackageParser { } else if (attr.equals("versionCode")) { } else if (attr.equals("versionCode")) { versionCode = attrs.getAttributeIntValue(i, 0); versionCode = attrs.getAttributeIntValue(i, 0); numFound++; numFound++; } else if (attr.equals("multiArch")) { multiArch = attrs.getAttributeBooleanValue(i, false); numFound++; } } if (numFound >= 2) { if (numFound >= 3) { break; break; } } } } Loading @@ -1149,7 +1159,7 @@ public class PackageParser { } } return new ApkLite(codePath, packageSplit.first, packageSplit.second, versionCode, return new ApkLite(codePath, packageSplit.first, packageSplit.second, versionCode, installLocation, verifiers, signatures); installLocation, verifiers, signatures, multiArch); } } /** /** Loading
core/java/com/android/internal/content/NativeLibraryHelper.java +31 −24 Original line number Original line Diff line number Diff line Loading @@ -131,11 +131,16 @@ public class NativeLibraryHelper { * * * @return size of all native binary files in bytes * @return size of all native binary files in bytes */ */ public static long sumNativeBinariesLI(Handle handle, String abi) { public static long sumNativeBinariesLI(Handle handle, String[] abis) { long sum = 0; long sum = 0; for (long apkHandle : handle.apkHandles) { 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); sum += nativeSumNativeBinaries(apkHandle, abi); } } } return sum; return sum; } } Loading Loading @@ -196,45 +201,47 @@ public class NativeLibraryHelper { private native static int nativeFindSupportedAbi(long handle, String[] supportedAbis); private native static int nativeFindSupportedAbi(long handle, String[] supportedAbis); // Convenience method to call removeNativeBinariesFromDirLI(File) // Convenience method to call removeNativeBinariesFromDirLI(File) public static boolean removeNativeBinariesLI(String nativeLibraryPath) { public static void removeNativeBinariesLI(String nativeLibraryPath) { if (nativeLibraryPath == null) return false; if (nativeLibraryPath == null) return; return removeNativeBinariesFromDirLI(new File(nativeLibraryPath)); removeNativeBinariesFromDirLI(new File(nativeLibraryPath), false /* delete root dir */); } } // Remove the native binaries of a given package. This simply /** // gets rid of the files in the 'lib' sub-directory. * Remove the native binaries of a given package. This deletes the files public static boolean removeNativeBinariesFromDirLI(File nativeLibraryDir) { */ public static void removeNativeBinariesFromDirLI(File nativeLibraryRoot, boolean deleteRootDir) { if (DEBUG_NATIVE) { if (DEBUG_NATIVE) { Slog.w(TAG, "Deleting native binaries from: " + nativeLibraryDir.getPath()); Slog.w(TAG, "Deleting native binaries from: " + nativeLibraryRoot.getPath()); } } boolean deletedFiles = false; /* /* * Just remove any file in the directory. Since the directory is owned * Just remove any file in the directory. Since the directory is owned * by the 'system' UID, the application is not supposed to have written * by the 'system' UID, the application is not supposed to have written * anything there. * anything there. */ */ if (nativeLibraryDir.exists()) { if (nativeLibraryRoot.exists()) { final File[] binaries = nativeLibraryDir.listFiles(); final File[] files = nativeLibraryRoot.listFiles(); if (binaries != null) { if (files != null) { for (int nn = 0; nn < binaries.length; nn++) { for (int nn = 0; nn < files.length; nn++) { if (DEBUG_NATIVE) { if (DEBUG_NATIVE) { Slog.d(TAG, " Deleting " + binaries[nn].getName()); Slog.d(TAG, " Deleting " + files[nn].getName()); } } if (!binaries[nn].delete()) { if (files[nn].isDirectory()) { Slog.w(TAG, "Could not delete native binary: " + binaries[nn].getPath()); removeNativeBinariesFromDirLI(files[nn], true /* delete root dir */); } else { } else if (!files[nn].delete()) { deletedFiles = true; Slog.w(TAG, "Could not delete native binary: " + files[nn].getPath()); } } } } } } // Do not delete 'lib' directory itself, or this will prevent // Do not delete 'lib' directory itself, unless we're specifically // installation of future updates. // asked to or this will prevent installation of future updates. if (deleteRootDir) { if (!nativeLibraryRoot.delete()) { Slog.w(TAG, "Could not delete native binary directory: " + nativeLibraryRoot.getPath()); } } } } return deletedFiles; } } // We don't care about the other return values for now. // We don't care about the other return values for now. Loading
packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java +71 −35 Original line number Original line Diff line number Diff line Loading @@ -50,6 +50,7 @@ import com.android.internal.content.PackageHelper; import com.android.internal.os.IParcelFileDescriptorFactory; import com.android.internal.os.IParcelFileDescriptorFactory; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ArrayUtils; import dalvik.system.VMRuntime; import libcore.io.IoUtils; import libcore.io.IoUtils; import libcore.io.Streams; import libcore.io.Streams; Loading Loading @@ -186,6 +187,7 @@ public class DefaultContainerService extends IntentService { ret.verifiers = pkg.verifiers; ret.verifiers = pkg.verifiers; ret.recommendedInstallLocation = recommendAppInstallLocation(pkg, flags, threshold, ret.recommendedInstallLocation = recommendAppInstallLocation(pkg, flags, threshold, abiOverride); abiOverride); ret.multiArch = pkg.multiArch; return ret; return ret; } } Loading Loading @@ -363,31 +365,26 @@ public class DefaultContainerService extends IntentService { final String resFileName = "pkg.apk"; final String resFileName = "pkg.apk"; final String publicResFileName = "res.zip"; final String publicResFileName = "res.zip"; // The .apk file if (pkg.multiArch) { String codePath = pkg.baseCodePath; // TODO: Support multiArch installs on ASEC. File codeFile = new File(codePath); throw new IllegalArgumentException("multiArch not supported on ASEC installs."); } String[] abiList = Build.SUPPORTED_ABIS; // The .apk file if (abiOverride != null) { final String codePath = pkg.baseCodePath; abiList = new String[] { abiOverride }; final File codeFile = new File(codePath); } else { final String[] abis; try { try { if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && abis = calculateAbiList(handle, abiOverride, pkg.multiArch); NativeLibraryHelper.hasRenderscriptBitcode(handle)) { abiList = Build.SUPPORTED_32_BIT_ABIS; } } catch (IOException ioe) { } catch (IOException ioe) { Slog.w(TAG, "Problem determining ABI for: " + codeFile.getPath()); Slog.w(TAG, "Problem determining app ABIS: " + ioe); return null; return null; } } } final int abiIndex = NativeLibraryHelper.findSupportedAbi(handle, abiList); // Calculate size of container needed to hold base APK. // Calculate size of container needed to hold base APK. final int sizeMb; final int sizeMb; try { try { sizeMb = calculateContainerSize(pkg, handle, isForwardLocked, abiIndex); sizeMb = calculateContainerSize(pkg, handle, isForwardLocked, abis); } catch (IOException e) { } catch (IOException e) { Slog.w(TAG, "Problem when trying to copy " + codeFile.getPath()); Slog.w(TAG, "Problem when trying to copy " + codeFile.getPath()); return null; return null; Loading Loading @@ -451,18 +448,19 @@ public class DefaultContainerService extends IntentService { final File sharedLibraryDir = new File(newCachePath, LIB_DIR_NAME); final File sharedLibraryDir = new File(newCachePath, LIB_DIR_NAME); if (sharedLibraryDir.mkdir()) { if (sharedLibraryDir.mkdir()) { int ret = PackageManager.INSTALL_SUCCEEDED; int ret = PackageManager.INSTALL_SUCCEEDED; if (abiIndex >= 0) { if (abis != null) { // TODO(multiArch): Support multi-arch installs on asecs. Note that we are NOT // using an ISA specific subdir here for now. final String abi = abis[0]; ret = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle, ret = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle, sharedLibraryDir, abiList[abiIndex]); sharedLibraryDir, abi); } else if (abiIndex != PackageManager.NO_NATIVE_LIBRARIES) { ret = abiIndex; } if (ret != PackageManager.INSTALL_SUCCEEDED) { if (ret != PackageManager.INSTALL_SUCCEEDED) { Slog.e(TAG, "Could not copy native libraries to " + sharedLibraryDir.getPath()); Slog.e(TAG, "Could not copy native libraries to " + sharedLibraryDir.getPath()); PackageHelper.destroySdDir(newCid); PackageHelper.destroySdDir(newCid); return null; return null; } } } } else { } else { Slog.e(TAG, "Could not create native lib directory: " + sharedLibraryDir.getPath()); Slog.e(TAG, "Could not create native lib directory: " + sharedLibraryDir.getPath()); PackageHelper.destroySdDir(newCid); PackageHelper.destroySdDir(newCid); Loading Loading @@ -687,14 +685,53 @@ public class DefaultContainerService extends IntentService { NativeLibraryHelper.Handle handle = null; NativeLibraryHelper.Handle handle = null; try { try { handle = NativeLibraryHelper.Handle.create(pkg); handle = NativeLibraryHelper.Handle.create(pkg); final int abi = NativeLibraryHelper.findSupportedAbi(handle, return calculateContainerSize(pkg, handle, isForwardLocked, (abiOverride != null) ? new String[] { abiOverride } : Build.SUPPORTED_ABIS); calculateAbiList(handle, abiOverride, pkg.multiArch)); return calculateContainerSize(pkg, handle, isForwardLocked, abi); } finally { } finally { IoUtils.closeQuietly(handle); IoUtils.closeQuietly(handle); } } } } private String[] calculateAbiList(NativeLibraryHelper.Handle handle, String abiOverride, boolean isMultiArch) throws IOException { if (isMultiArch) { final int abi32 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_32_BIT_ABIS); final int abi64 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_64_BIT_ABIS); if (abi32 >= 0 && abi64 >= 0) { return new String[] { Build.SUPPORTED_64_BIT_ABIS[abi64], Build.SUPPORTED_32_BIT_ABIS[abi32] }; } else if (abi64 >= 0) { return new String[] { Build.SUPPORTED_64_BIT_ABIS[abi64] }; } else if (abi32 >= 0) { return new String[] { Build.SUPPORTED_32_BIT_ABIS[abi32] }; } if (abi64 != PackageManager.NO_NATIVE_LIBRARIES || abi32 != PackageManager.NO_NATIVE_LIBRARIES) { throw new IOException("Error determining ABI list: errorCode=[" + abi32 + "," + abi64 + "]"); } } else { String[] abiList = Build.SUPPORTED_ABIS; if (abiOverride != null) { abiList = new String[] { abiOverride }; } else if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && NativeLibraryHelper.hasRenderscriptBitcode(handle)) { abiList = Build.SUPPORTED_32_BIT_ABIS; } final int abi = NativeLibraryHelper.findSupportedAbi(handle,abiList); if (abi >= 0) { return new String[]{Build.SUPPORTED_ABIS[abi]}; } if (abi != PackageManager.NO_NATIVE_LIBRARIES) { throw new IOException("Error determining ABI list: errorCode=" + abi); } } return null; } /** /** * Calculate the container size for a package. * Calculate the container size for a package. * * Loading @@ -702,7 +739,7 @@ public class DefaultContainerService extends IntentService { * @throws IOException when there is a problem reading the file * @throws IOException when there is a problem reading the file */ */ private int calculateContainerSize(PackageLite pkg, NativeLibraryHelper.Handle handle, private int calculateContainerSize(PackageLite pkg, NativeLibraryHelper.Handle handle, boolean isForwardLocked, int abiIndex) throws IOException { boolean isForwardLocked, String[] abis) throws IOException { // Calculate size of container needed to hold APKs. // Calculate size of container needed to hold APKs. long sizeBytes = 0; long sizeBytes = 0; for (String codePath : pkg.getAllCodePaths()) { for (String codePath : pkg.getAllCodePaths()) { Loading @@ -715,9 +752,8 @@ public class DefaultContainerService extends IntentService { // Check all the native files that need to be copied and add that to the // Check all the native files that need to be copied and add that to the // container size. // container size. if (abiIndex >= 0) { if (abis != null) { sizeBytes += NativeLibraryHelper.sumNativeBinariesLI(handle, sizeBytes += NativeLibraryHelper.sumNativeBinariesLI(handle, abis); Build.SUPPORTED_ABIS[abiIndex]); } } int sizeMb = (int) (sizeBytes >> 20); int sizeMb = (int) (sizeBytes >> 20); Loading