diff options
12 files changed, 910 insertions, 564 deletions
| diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 1e93d92f53f9..4939fb653301 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -491,13 +491,55 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {      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}       * 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}       */ -    public String cpuAbi; +    public String apkRoot;      /**       * The kernel user-ID that has been assigned to this application; @@ -641,7 +683,10 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {          splitSourceDirs = orig.splitSourceDirs;          splitPublicSourceDirs = orig.splitPublicSourceDirs;          nativeLibraryDir = orig.nativeLibraryDir; -        cpuAbi = orig.cpuAbi; +        legacyNativeLibraryDir = orig.legacyNativeLibraryDir; +        primaryCpuAbi = orig.primaryCpuAbi; +        secondaryCpuAbi = orig.secondaryCpuAbi; +        apkRoot = orig.apkRoot;          resourceDirs = orig.resourceDirs;          seinfo = orig.seinfo;          sharedLibraryFiles = orig.sharedLibraryFiles; @@ -685,7 +730,10 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {          dest.writeStringArray(splitSourceDirs);          dest.writeStringArray(splitPublicSourceDirs);          dest.writeString(nativeLibraryDir); -        dest.writeString(cpuAbi); +        dest.writeString(legacyNativeLibraryDir); +        dest.writeString(primaryCpuAbi); +        dest.writeString(secondaryCpuAbi); +        dest.writeString(apkRoot);          dest.writeStringArray(resourceDirs);          dest.writeString(seinfo);          dest.writeStringArray(sharedLibraryFiles); @@ -728,7 +776,10 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {          splitSourceDirs = source.readStringArray();          splitPublicSourceDirs = source.readStringArray();          nativeLibraryDir = source.readString(); -        cpuAbi = source.readString(); +        legacyNativeLibraryDir = source.readString(); +        primaryCpuAbi = source.readString(); +        secondaryCpuAbi = source.readString(); +        apkRoot = source.readString();          resourceDirs = source.readStringArray();          seinfo = source.readString();          sharedLibraryFiles = source.readStringArray(); diff --git a/core/java/android/content/pm/PackageInfoLite.java b/core/java/android/content/pm/PackageInfoLite.java index a1566dadbadd..50a048322f83 100644 --- a/core/java/android/content/pm/PackageInfoLite.java +++ b/core/java/android/content/pm/PackageInfoLite.java @@ -37,6 +37,13 @@ public class PackageInfoLite implements Parcelable {      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       * {@link #PackageHelper.RECOMMEND_INSTALL_INTERNAL} to install on internal storage       * {@link #PackageHelper.RECOMMEND_INSTALL_EXTERNAL} to install on external media diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index ab0bf25f3a95..6e0ca505855d 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -249,6 +249,8 @@ public class PackageParser {          /** Paths of any split APKs, ordered by parsed splitName */          public final String[] splitCodePaths; +        public final boolean multiArch; +          private PackageLite(String codePath, ApkLite baseApk, String[] splitNames,                  String[] splitCodePaths) {              this.packageName = baseApk.packageName; @@ -259,6 +261,7 @@ public class PackageParser {              this.codePath = codePath;              this.baseCodePath = baseApk.codePath;              this.splitCodePaths = splitCodePaths; +            this.multiArch = baseApk.multiArch;          }          public List<String> getAllCodePaths() { @@ -282,9 +285,11 @@ public class PackageParser {          public final int installLocation;          public final VerifierInfo[] verifiers;          public final Signature[] signatures; +        public final boolean multiArch;          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.packageName = packageName;              this.splitName = splitName; @@ -292,6 +297,7 @@ public class PackageParser {              this.installLocation = installLocation;              this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]);              this.signatures = signatures; +            this.multiArch = multiArch;          }      } @@ -1114,6 +1120,7 @@ public class PackageParser {          int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;          int versionCode = 0;          int numFound = 0; +        boolean multiArch = false;          for (int i = 0; i < attrs.getAttributeCount(); i++) {              String attr = attrs.getAttributeName(i);              if (attr.equals("installLocation")) { @@ -1123,8 +1130,11 @@ public class PackageParser {              } else if (attr.equals("versionCode")) {                  versionCode = attrs.getAttributeIntValue(i, 0);                  numFound++; +            } else if (attr.equals("multiArch")) { +                multiArch = attrs.getAttributeBooleanValue(i, false); +                numFound++;              } -            if (numFound >= 2) { +            if (numFound >= 3) {                  break;              }          } @@ -1149,7 +1159,7 @@ public class PackageParser {          }          return new ApkLite(codePath, packageSplit.first, packageSplit.second, versionCode, -                installLocation, verifiers, signatures); +                installLocation, verifiers, signatures, multiArch);      }      /** diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java index d66a7bbf8f3e..d76d0d4aa251 100644 --- a/core/java/com/android/internal/content/NativeLibraryHelper.java +++ b/core/java/com/android/internal/content/NativeLibraryHelper.java @@ -131,10 +131,15 @@ public class NativeLibraryHelper {       *       * @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;          for (long apkHandle : handle.apkHandles) { -            sum += nativeSumNativeBinaries(apkHandle, abi); +            // 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;      } @@ -196,45 +201,47 @@ public class NativeLibraryHelper {      private native static int nativeFindSupportedAbi(long handle, String[] supportedAbis);      // Convenience method to call removeNativeBinariesFromDirLI(File) -    public static boolean removeNativeBinariesLI(String nativeLibraryPath) { -        if (nativeLibraryPath == null) return false; -        return removeNativeBinariesFromDirLI(new File(nativeLibraryPath)); +    public static void removeNativeBinariesLI(String nativeLibraryPath) { +        if (nativeLibraryPath == null) return; +        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. -    public static boolean removeNativeBinariesFromDirLI(File nativeLibraryDir) { +    /** +     * Remove the native binaries of a given package. This deletes the files +     */ +    public static void removeNativeBinariesFromDirLI(File nativeLibraryRoot, boolean deleteRootDir) {          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           * by the 'system' UID, the application is not supposed to have written           * anything there.           */ -        if (nativeLibraryDir.exists()) { -            final File[] binaries = nativeLibraryDir.listFiles(); -            if (binaries != null) { -                for (int nn = 0; nn < binaries.length; nn++) { +        if (nativeLibraryRoot.exists()) { +            final File[] files = nativeLibraryRoot.listFiles(); +            if (files != null) { +                for (int nn = 0; nn < files.length; nn++) {                      if (DEBUG_NATIVE) { -                        Slog.d(TAG, "    Deleting " + binaries[nn].getName()); +                        Slog.d(TAG, "    Deleting " + files[nn].getName());                      } -                    if (!binaries[nn].delete()) { -                        Slog.w(TAG, "Could not delete native binary: " + binaries[nn].getPath()); -                    } else { -                        deletedFiles = true; +                    if (files[nn].isDirectory()) { +                        removeNativeBinariesFromDirLI(files[nn], true /* delete root dir */); +                    } else if (!files[nn].delete()) { +                        Slog.w(TAG, "Could not delete native binary: " + files[nn].getPath());                      }                  }              } -            // Do not delete 'lib' directory itself, or this will prevent -            // installation of future updates. +            // Do not delete 'lib' directory itself, unless we're specifically +            // 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. diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java index 67ed97cf51d0..20a621bd8084 100644 --- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java +++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java @@ -50,6 +50,7 @@ import com.android.internal.content.PackageHelper;  import com.android.internal.os.IParcelFileDescriptorFactory;  import com.android.internal.util.ArrayUtils; +import dalvik.system.VMRuntime;  import libcore.io.IoUtils;  import libcore.io.Streams; @@ -186,6 +187,7 @@ public class DefaultContainerService extends IntentService {              ret.verifiers = pkg.verifiers;              ret.recommendedInstallLocation = recommendAppInstallLocation(pkg, flags, threshold,                      abiOverride); +            ret.multiArch = pkg.multiArch;              return ret;          } @@ -363,31 +365,26 @@ public class DefaultContainerService extends IntentService {          final String resFileName = "pkg.apk";          final String publicResFileName = "res.zip"; -        // The .apk file -        String codePath = pkg.baseCodePath; -        File codeFile = new File(codePath); - -        String[] abiList = Build.SUPPORTED_ABIS; -        if (abiOverride != null) { -            abiList = new String[] { abiOverride }; -        } else { -            try { -                if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && -                        NativeLibraryHelper.hasRenderscriptBitcode(handle)) { -                    abiList = Build.SUPPORTED_32_BIT_ABIS; -                } -            } catch (IOException ioe) { -                Slog.w(TAG, "Problem determining ABI for: " + codeFile.getPath()); -                return null; -            } +        if (pkg.multiArch) { +            // TODO: Support multiArch installs on ASEC. +            throw new IllegalArgumentException("multiArch not supported on ASEC installs.");          } -        final int abiIndex = NativeLibraryHelper.findSupportedAbi(handle, abiList); +        // The .apk file +        final String codePath = pkg.baseCodePath; +        final File codeFile = new File(codePath); +        final String[] abis; +        try { +            abis = calculateAbiList(handle, abiOverride, pkg.multiArch); +        } catch (IOException ioe) { +            Slog.w(TAG, "Problem determining app ABIS: " + ioe); +            return null; +        }          // Calculate size of container needed to hold base APK.          final int sizeMb;          try { -            sizeMb = calculateContainerSize(pkg, handle, isForwardLocked, abiIndex); +            sizeMb = calculateContainerSize(pkg, handle, isForwardLocked, abis);          } catch (IOException e) {              Slog.w(TAG, "Problem when trying to copy " + codeFile.getPath());              return null; @@ -451,17 +448,18 @@ public class DefaultContainerService extends IntentService {          final File sharedLibraryDir = new File(newCachePath, LIB_DIR_NAME);          if (sharedLibraryDir.mkdir()) {              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, -                        sharedLibraryDir, abiList[abiIndex]); -            } else if (abiIndex != PackageManager.NO_NATIVE_LIBRARIES) { -                ret = abiIndex; -            } +                        sharedLibraryDir, abi); -            if (ret != PackageManager.INSTALL_SUCCEEDED) { -                Slog.e(TAG, "Could not copy native libraries to " + sharedLibraryDir.getPath()); -                PackageHelper.destroySdDir(newCid); -                return null; +                if (ret != PackageManager.INSTALL_SUCCEEDED) { +                    Slog.e(TAG, "Could not copy native libraries to " + sharedLibraryDir.getPath()); +                    PackageHelper.destroySdDir(newCid); +                    return null; +                }              }          } else {              Slog.e(TAG, "Could not create native lib directory: " + sharedLibraryDir.getPath()); @@ -687,14 +685,53 @@ public class DefaultContainerService extends IntentService {          NativeLibraryHelper.Handle handle = null;          try {              handle = NativeLibraryHelper.Handle.create(pkg); -            final int abi = NativeLibraryHelper.findSupportedAbi(handle, -                    (abiOverride != null) ? new String[] { abiOverride } : Build.SUPPORTED_ABIS); -            return calculateContainerSize(pkg, handle, isForwardLocked, abi); +            return calculateContainerSize(pkg, handle, isForwardLocked, +                    calculateAbiList(handle, abiOverride, pkg.multiArch));          } finally {              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.       *  @@ -702,7 +739,7 @@ public class DefaultContainerService extends IntentService {       * @throws IOException when there is a problem reading the file       */      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.          long sizeBytes = 0;          for (String codePath : pkg.getAllCodePaths()) { @@ -715,9 +752,8 @@ public class DefaultContainerService extends IntentService {          // Check all the native files that need to be copied and add that to the          // container size. -        if (abiIndex >= 0) { -            sizeBytes += NativeLibraryHelper.sumNativeBinariesLI(handle, -                    Build.SUPPORTED_ABIS[abiIndex]); +        if (abis != null) { +            sizeBytes += NativeLibraryHelper.sumNativeBinariesLI(handle, abis);          }          int sizeMb = (int) (sizeBytes >> 20); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 053fb5a53632..c7eabe86d0af 100755 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -2985,7 +2985,7 @@ public final class ActivityManagerService extends ActivityManagerNative                  debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;              } -            String requiredAbi = (abiOverride != null) ? abiOverride : app.info.cpuAbi; +            String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi;              if (requiredAbi == null) {                  requiredAbi = Build.SUPPORTED_ABIS[0];              } diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index 6ad2e6002753..1193968ac6be 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -365,7 +365,7 @@ public final class Installer extends SystemService {      }      public int getSizeInfo(String pkgName, int persona, String apkPath, String libDirPath, -            String fwdLockApkPath, String asecPath, String instructionSet, PackageStats pStats) { +            String fwdLockApkPath, String asecPath, String[] instructionSets, PackageStats pStats) {          StringBuilder builder = new StringBuilder("getsize");          builder.append(' ');          builder.append(pkgName); @@ -374,13 +374,17 @@ public final class Installer extends SystemService {          builder.append(' ');          builder.append(apkPath);          builder.append(' '); +        // TODO: Extend getSizeInfo to look at the full subdirectory tree, +        // not just the first level.          builder.append(libDirPath != null ? libDirPath : "!");          builder.append(' ');          builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!");          builder.append(' ');          builder.append(asecPath != null ? asecPath : "!");          builder.append(' '); -        builder.append(instructionSet); +        // TODO: Extend getSizeInfo to look at *all* instrution sets, not +        // just the primary. +        builder.append(instructionSets[0]);          String s = transaction(builder.toString());          String res[] = s.split(" "); @@ -404,18 +408,17 @@ public final class Installer extends SystemService {      }      /** -     * Links the native library directory in an application's directory to its -     * real location. +     * Links the 32 bit native library directory in an application's data directory to the +     * real location for backward compatibility. Note that no such symlink is created for +     * 64 bit shared libraries.       * -     * @param dataPath data directory where the application is -     * @param nativeLibPath target native library path       * @return -1 on error       */ -    public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath, int userId) { +    public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath32, int userId) {          if (dataPath == null) {              Slog.e(TAG, "linkNativeLibraryDirectory dataPath is null");              return -1; -        } else if (nativeLibPath == null) { +        } else if (nativeLibPath32 == null) {              Slog.e(TAG, "linkNativeLibraryDirectory nativeLibPath is null");              return -1;          } @@ -423,7 +426,7 @@ public final class Installer extends SystemService {          StringBuilder builder = new StringBuilder("linklib ");          builder.append(dataPath);          builder.append(' '); -        builder.append(nativeLibPath); +        builder.append(nativeLibPath32);          builder.append(' ');          builder.append(userId); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index fe9ce8ffd471..5c05f45cc77f 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -18,7 +18,6 @@ package com.android.server.pm;  import static android.Manifest.permission.GRANT_REVOKE_PERMISSIONS;  import static android.Manifest.permission.READ_EXTERNAL_STORAGE; -import static android.Manifest.permission.INSTALL_PACKAGES;  import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;  import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;  import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED; @@ -34,7 +33,6 @@ import static android.system.OsConstants.O_CREAT;  import static android.system.OsConstants.EEXIST;  import static android.system.OsConstants.O_EXCL;  import static android.system.OsConstants.O_RDWR; -import static android.system.OsConstants.O_WRONLY;  import static android.system.OsConstants.S_IRGRP;  import static android.system.OsConstants.S_IROTH;  import static android.system.OsConstants.S_IRWXU; @@ -57,7 +55,6 @@ import com.android.internal.util.ArrayUtils;  import com.android.internal.util.FastPrintWriter;  import com.android.internal.util.FastXmlSerializer;  import com.android.internal.util.Preconditions; -import com.android.internal.util.XmlUtils;  import com.android.server.EventLogTags;  import com.android.server.IntentResolver;  import com.android.server.LocalServices; @@ -67,14 +64,11 @@ import com.android.server.Watchdog;  import com.android.server.pm.Settings.DatabaseVersion;  import com.android.server.storage.DeviceStorageMonitorInternal; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException;  import org.xmlpull.v1.XmlSerializer;  import android.app.ActivityManager;  import android.app.ActivityManagerNative;  import android.app.IActivityManager; -import android.app.PackageInstallObserver;  import android.app.admin.IDevicePolicyManager;  import android.app.backup.IBackupManager;  import android.content.BroadcastReceiver; @@ -149,7 +143,6 @@ import android.security.KeyStore;  import android.security.SystemKeyStore;  import android.system.ErrnoException;  import android.system.Os; -import android.system.OsConstants;  import android.system.StructStat;  import android.text.TextUtils;  import android.util.ArraySet; @@ -162,7 +155,6 @@ import android.util.PrintStreamPrinter;  import android.util.Slog;  import android.util.SparseArray;  import android.util.SparseBooleanArray; -import android.util.Xml;  import android.view.Display;  import java.io.BufferedInputStream; @@ -172,7 +164,6 @@ import java.io.FileDescriptor;  import java.io.FileInputStream;  import java.io.FileNotFoundException;  import java.io.FileOutputStream; -import java.io.FileReader;  import java.io.FilenameFilter;  import java.io.IOException;  import java.io.InputStream; @@ -204,7 +195,6 @@ import dalvik.system.StaleDexCacheError;  import dalvik.system.VMRuntime;  import libcore.io.IoUtils; -import libcore.io.Libcore;  /**   * Keep track of all those .apks everywhere. @@ -233,6 +223,7 @@ public class PackageManagerService extends IPackageManager.Stub {      private static final boolean DEBUG_APP_DIR_OBSERVER = false;      private static final boolean DEBUG_VERIFY = false;      private static final boolean DEBUG_DEXOPT = false; +    private static final boolean DEBUG_ABI_SELECTION = false;      private static final int RADIO_UID = Process.PHONE_UID;      private static final int LOG_UID = Process.LOG_UID; @@ -368,10 +359,10 @@ public class PackageManagerService extends IPackageManager.Stub {      final File mAppInstallDir;      /** -     * Directory to which applications installed internally have native -     * libraries copied. +     * Directory to which applications installed internally have their +     * 32 bit native libraries copied.       */ -    private File mAppLibInstallDir; +    private File mAppLib32InstallDir;      // Directory containing the private parts (e.g. code and non-resource assets) of forward-locked      // apps. @@ -1354,7 +1345,7 @@ public class PackageManagerService extends IPackageManager.Stub {              File dataDir = Environment.getDataDirectory();              mAppDataDir = new File(dataDir, "data");              mAppInstallDir = new File(dataDir, "app"); -            mAppLibInstallDir = new File(dataDir, "app-lib"); +            mAppLib32InstallDir = new File(dataDir, "app-lib");              mAsecInternalPath = new File(dataDir, "app-asec").getPath();              mUserAppDataDir = new File(dataDir, "user");              mDrmAppPrivateInstallDir = new File(dataDir, "app-private"); @@ -2089,7 +2080,8 @@ public class PackageManagerService extends IPackageManager.Stub {                  pkg.applicationInfo.flags = ps.pkgFlags | ApplicationInfo.FLAG_IS_DATA_ONLY;                  pkg.applicationInfo.dataDir =                          getDataPathForPackage(packageName, 0).getPath(); -                pkg.applicationInfo.cpuAbi = ps.cpuAbiString; +                pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString; +                pkg.applicationInfo.secondaryCpuAbi = ps.secondaryCpuAbiString;              }              return generatePackageInfo(pkg, flags, userId);          } @@ -4269,8 +4261,8 @@ public class PackageManagerService extends IPackageManager.Stub {                              + " better than installed " + ps.versionCode);                      InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps), -                            ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString, -                            getAppInstructionSetFromSettings(ps)); +                            ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString, +                            getAppDexInstructionSets(ps), isMultiArch(ps));                      synchronized (mInstallLock) {                          args.cleanUpResourcesLI();                      } @@ -4334,8 +4326,8 @@ public class PackageManagerService extends IPackageManager.Stub {                              + ps.codePathString + ": new version " + pkg.mVersionCode                              + " better than installed " + ps.versionCode);                      InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps), -                            ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString, -                            getAppInstructionSetFromSettings(ps)); +                            ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString, +                            getAppDexInstructionSets(ps), isMultiArch(ps));                      synchronized (mInstallLock) {                          args.cleanUpResourcesLI();                      } @@ -4585,7 +4577,7 @@ public class PackageManagerService extends IPackageManager.Stub {          mPackageUsage.write(true);      } -    private void performDexOptLibsLI(ArrayList<String> libs, String instructionSet, +    private void performDexOptLibsLI(ArrayList<String> libs, String[] instructionSets,               boolean forceDex, boolean defer, HashSet<String> done) {          for (int i=0; i<libs.size(); i++) {              PackageParser.Package libPkg; @@ -4600,7 +4592,7 @@ public class PackageManagerService extends IPackageManager.Stub {                  }              }              if (libPkg != null && !done.contains(libName)) { -                performDexOptLI(libPkg, instructionSet, forceDex, defer, done); +                performDexOptLI(libPkg, instructionSets, forceDex, defer, done);              }          }      } @@ -4610,89 +4602,98 @@ public class PackageManagerService extends IPackageManager.Stub {      static final int DEX_OPT_DEFERRED = 2;      static final int DEX_OPT_FAILED = -1; -    private int performDexOptLI(PackageParser.Package pkg, String instructionSetOverride, +    private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets,              boolean forceDex, boolean defer, HashSet<String> done) { -        final String instructionSet = instructionSetOverride != null ? -                instructionSetOverride : getAppInstructionSet(pkg.applicationInfo); +        final String[] instructionSets = targetInstructionSets != null ? +                targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);          if (done != null) {              done.add(pkg.packageName);              if (pkg.usesLibraries != null) { -                performDexOptLibsLI(pkg.usesLibraries, instructionSet, forceDex, defer, done); +                performDexOptLibsLI(pkg.usesLibraries, instructionSets, forceDex, defer, done);              }              if (pkg.usesOptionalLibraries != null) { -                performDexOptLibsLI(pkg.usesOptionalLibraries, instructionSet, forceDex, defer, done); +                performDexOptLibsLI(pkg.usesOptionalLibraries, instructionSets, forceDex, defer, done);              }          }          if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) {              final Collection<String> paths = pkg.getAllCodePaths();              for (String path : paths) { -                try { -                    boolean isDexOptNeededInternal = DexFile.isDexOptNeededInternal(path, -                            pkg.packageName, instructionSet, defer); -                    // There are three basic cases here: -                    // 1.) we need to dexopt, either because we are forced or it is needed -                    // 2.) we are defering a needed dexopt -                    // 3.) we are skipping an unneeded dexopt -                    if (forceDex || (!defer && isDexOptNeededInternal)) { -                        Log.i(TAG, "Running dexopt on: " + pkg.applicationInfo.packageName); -                        final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid); -                        int ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg), -                                                    pkg.packageName, instructionSet); -                        // Note that we ran dexopt, since rerunning will -                        // probably just result in an error again. -                        pkg.mDexOptNeeded = false; -                        if (ret < 0) { -                            return DEX_OPT_FAILED; +                for (String instructionSet : instructionSets) { +                    try { +                        boolean isDexOptNeededInternal = DexFile.isDexOptNeededInternal(path, +                                pkg.packageName, instructionSet, defer); +                        // There are three basic cases here: +                        // 1.) we need to dexopt, either because we are forced or it is needed +                        // 2.) we are defering a needed dexopt +                        // 3.) we are skipping an unneeded dexopt +                        if (forceDex || (!defer && isDexOptNeededInternal)) { +                            Log.i(TAG, "Running dexopt on: " + pkg.applicationInfo.packageName); +                            final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid); +                            int ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg), +                                    pkg.packageName, instructionSet); +                            // Note that we ran dexopt, since rerunning will +                            // probably just result in an error again. +                            pkg.mDexOptNeeded = false; +                            if (ret < 0) { +                                return DEX_OPT_FAILED; +                            } +                            return DEX_OPT_PERFORMED;                          } -                        return DEX_OPT_PERFORMED; -                    } -                    if (defer && isDexOptNeededInternal) { -                        if (mDeferredDexOpt == null) { -                            mDeferredDexOpt = new HashSet<PackageParser.Package>(); +                        if (defer && isDexOptNeededInternal) { +                            if (mDeferredDexOpt == null) { +                                mDeferredDexOpt = new HashSet<PackageParser.Package>(); +                            } +                            mDeferredDexOpt.add(pkg); +                            return DEX_OPT_DEFERRED;                          } -                        mDeferredDexOpt.add(pkg); -                        return DEX_OPT_DEFERRED; +                        pkg.mDexOptNeeded = false; +                        return DEX_OPT_SKIPPED; +                    } catch (FileNotFoundException e) { +                        Slog.w(TAG, "Apk not found for dexopt: " + path); +                        return DEX_OPT_FAILED; +                    } catch (IOException e) { +                        Slog.w(TAG, "IOException reading apk: " + path, e); +                        return DEX_OPT_FAILED; +                    } catch (StaleDexCacheError e) { +                        Slog.w(TAG, "StaleDexCacheError when reading apk: " + path, e); +                        return DEX_OPT_FAILED; +                    } catch (Exception e) { +                        Slog.w(TAG, "Exception when doing dexopt : ", e); +                        return DEX_OPT_FAILED;                      } -                    pkg.mDexOptNeeded = false; -                    return DEX_OPT_SKIPPED; -                } catch (FileNotFoundException e) { -                    Slog.w(TAG, "Apk not found for dexopt: " + path); -                    return DEX_OPT_FAILED; -                } catch (IOException e) { -                    Slog.w(TAG, "IOException reading apk: " + path, e); -                    return DEX_OPT_FAILED; -                } catch (StaleDexCacheError e) { -                    Slog.w(TAG, "StaleDexCacheError when reading apk: " + path, e); -                    return DEX_OPT_FAILED; -                } catch (Exception e) { -                    Slog.w(TAG, "Exception when doing dexopt : ", e); -                    return DEX_OPT_FAILED;                  }              }          }          return DEX_OPT_SKIPPED;      } -    private String getAppInstructionSet(ApplicationInfo info) { -        String instructionSet = getPreferredInstructionSet(); - -        if (info.cpuAbi != null) { -            instructionSet = VMRuntime.getInstructionSet(info.cpuAbi); +    private static String[] getAppDexInstructionSets(ApplicationInfo info) { +        if (info.primaryCpuAbi != null) { +            if (info.secondaryCpuAbi != null) { +                return new String[] { +                        VMRuntime.getInstructionSet(info.primaryCpuAbi), +                        VMRuntime.getInstructionSet(info.secondaryCpuAbi) }; +            } else { +                return new String[] { +                        VMRuntime.getInstructionSet(info.primaryCpuAbi) }; +            }          } -        return instructionSet; +        return new String[] { getPreferredInstructionSet() };      } -    private String getAppInstructionSetFromSettings(PackageSetting ps) { -        String instructionSet = getPreferredInstructionSet(); - -        if (ps.cpuAbiString != null) { -            instructionSet = VMRuntime.getInstructionSet(ps.cpuAbiString); +    private static String[] getAppDexInstructionSets(PackageSetting ps) { +        if (ps.primaryCpuAbiString != null) { +            if (ps.secondaryCpuAbiString != null) { +                return new String[] { ps.primaryCpuAbiString, ps.secondaryCpuAbiString }; +            } else { +                return new String[] { ps.primaryCpuAbiString }; +            }          } -        return instructionSet; +        return new String[] { getPreferredInstructionSet() };      }      private static String getPreferredInstructionSet() { @@ -4726,7 +4727,7 @@ public class PackageManagerService extends IPackageManager.Stub {          } else {              done = null;          } -        return performDexOptLI(pkg, null /* instruction set override */,  forceDex, defer, done); +        return performDexOptLI(pkg, null /* target instruction sets */,  forceDex, defer, done);      }      private boolean verifyPackageUpdateLPr(PackageSetting oldPkg, PackageParser.Package newPkg) { @@ -4790,12 +4791,6 @@ public class PackageManagerService extends IPackageManager.Stub {              }          } -        final File nativeLibraryFile = new File(mAppLibInstallDir, packageName); -        NativeLibraryHelper.removeNativeBinariesFromDirLI(nativeLibraryFile); -        if (!nativeLibraryFile.delete()) { -            Slog.w(TAG, "Couldn't delete native library directory " + nativeLibraryFile.getPath()); -        } -          return res;      } @@ -4827,7 +4822,7 @@ public class PackageManagerService extends IPackageManager.Stub {          // Fix that up here.          if (isSystemApp(pkg)) {              PackageSetting ps = mSettings.mPackages.get(pkg.applicationInfo.packageName); -            setInternalAppNativeLibraryPath(pkg, ps); +            setBundledAppAbisAndRoots(pkg, ps);          }          if (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null) { @@ -5064,8 +5059,9 @@ public class PackageManagerService extends IPackageManager.Stub {              // Just create the setting, don't add it yet. For already existing packages              // the PkgSetting exists already and doesn't have to be created.              pkgSetting = mSettings.getPackageLPw(pkg, origPackage, realName, suid, destCodeFile, -                    destResourceFile, pkg.applicationInfo.nativeLibraryDir, -                    pkg.applicationInfo.cpuAbi, +                    destResourceFile, pkg.applicationInfo.legacyNativeLibraryDir, +                    pkg.applicationInfo.primaryCpuAbi, +                    pkg.applicationInfo.secondaryCpuAbi,                      pkg.applicationInfo.flags, user, false);              if (pkgSetting == null) {                  Slog.w(TAG, "Creating application package " + pkg.packageName + " failed"); @@ -5289,6 +5285,7 @@ public class PackageManagerService extends IPackageManager.Stub {                              + pkg.applicationInfo.uid + "/fs_"                              + currentUid;                          pkg.applicationInfo.nativeLibraryDir = pkg.applicationInfo.dataDir; +                        pkg.applicationInfo.legacyNativeLibraryDir = pkg.applicationInfo.dataDir;                          String msg = "Package " + pkg.packageName                                  + " has mismatched uid: "                                  + currentUid + " on disk, " @@ -5320,6 +5317,7 @@ public class PackageManagerService extends IPackageManager.Stub {                                             pkg.applicationInfo.seinfo);                  if (ret < 0) {                      // Error from installer +                    Slog.w(TAG, "Unable to create data dirs [errorCode=" + ret + "]");                      mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;                      return null;                  } @@ -5332,158 +5330,185 @@ public class PackageManagerService extends IPackageManager.Stub {                  }              } -            /* -             * Set the data dir to the default "/data/data/<package name>/lib" -             * if we got here without anyone telling us different (e.g., apps -             * stored on SD card have their native libraries stored in the ASEC -             * container with the APK). -             * -             * This happens during an upgrade from a package settings file that -             * doesn't have a native library path attribute at all. -             */ -            if (pkg.applicationInfo.nativeLibraryDir == null && pkg.applicationInfo.dataDir != null) { -                if (pkgSetting.nativeLibraryPathString == null) { -                    setInternalAppNativeLibraryPath(pkg, pkgSetting); -                } else { -                    pkg.applicationInfo.nativeLibraryDir = pkgSetting.nativeLibraryPathString; -                } -            }              pkgSetting.uidError = uidError;          }          final String path = scanFile.getPath(); -        /* Note: We don't want to unpack the native binaries for -         *        system applications, unless they have been updated -         *        (the binaries are already under /system/lib). -         *        Also, don't unpack libs for apps on the external card -         *        since they should have their libraries in the ASEC -         *        container already. -         * -         *        In other words, we're going to unpack the binaries -         *        only for non-system apps and system app upgrades. -         */ -        if (pkg.applicationInfo.nativeLibraryDir != null) { +        final String codePath = pkg.applicationInfo.getCodePath(); +        if (isSystemApp(pkg) && !isUpdatedSystemApp(pkg)) { +            // For the case where we had previously uninstalled an update, get rid +            // of any native binaries we might have unpackaged. Note that this assumes +            // that system app updates were not installed via ASEC. +            // +            // TODO(multiArch): Is this cleanup really necessary ? +            NativeLibraryHelper.removeNativeBinariesFromDirLI( +                    new File(codePath, LIB_DIR_NAME), false /* delete dirs */); +            setBundledAppAbisAndRoots(pkg, pkgSetting); +        } else { +            // TODO: We can probably be smarter about this stuff. For installed apps, +            // we can calculate this information at install time once and for all. For +            // system apps, we can probably assume that this information doesn't change +            // after the first boot scan. As things stand, we do lots of unnecessary work. + +            final boolean isAsec = isForwardLocked(pkg) || isExternal(pkg); +            final String nativeLibraryRootStr; +            final boolean useIsaSpecificSubdirs; +            if (pkg.applicationInfo.legacyNativeLibraryDir != null) { +                nativeLibraryRootStr = pkg.applicationInfo.legacyNativeLibraryDir; +                useIsaSpecificSubdirs = false; +            } else { +                nativeLibraryRootStr = new File(pkg.codePath, LIB_DIR_NAME).getAbsolutePath(); +                useIsaSpecificSubdirs = true; +            } +              NativeLibraryHelper.Handle handle = null;              try {                  handle = NativeLibraryHelper.Handle.create(scanFile); -                // Enable gross and lame hacks for apps that are built with old -                // SDK tools. We must scan their APKs for renderscript bitcode and -                // not launch them if it's present. Don't bother checking on devices -                // that don't have 64 bit support. -                String[] abiList = Build.SUPPORTED_ABIS; -                boolean hasLegacyRenderscriptBitcode = false; -                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; -                    hasLegacyRenderscriptBitcode = true; -                } - -                File nativeLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir); -                final String dataPathString = dataPath.getCanonicalPath(); - -                if (isSystemApp(pkg) && !isUpdatedSystemApp(pkg)) { -                    /* -                     * Upgrading from a previous version of the OS sometimes -                     * leaves native libraries in the /data/data/<app>/lib -                     * directory for system apps even when they shouldn't be. -                     * Recent changes in the JNI library search path -                     * necessitates we remove those to match previous behavior. -                     */ -                    if (NativeLibraryHelper.removeNativeBinariesFromDirLI(nativeLibraryDir)) { -                        Log.i(TAG, "removed obsolete native libraries for system package " -                                + path); +                // TODO(multiArch): This can be null for apps that didn't go through the +                // usual installation process. We can calculate it again, like we +                // do during install time. +                // +                // TODO(multiArch): Why do we need to rescan ASEC apps again ? It seems totally +                // unnecessary. +                final File nativeLibraryRoot = new File(nativeLibraryRootStr); + +                // Null out the abis so that they can be recalculated. +                pkg.applicationInfo.primaryCpuAbi = null; +                pkg.applicationInfo.secondaryCpuAbi = null; +                if (isMultiArch(pkg.applicationInfo)) { +                    // 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) { +                        Slog.w(TAG, "Ignoring abiOverride for multi arch application."); +                    } + +                    int abi32 = PackageManager.NO_NATIVE_LIBRARIES; +                    int abi64 = PackageManager.NO_NATIVE_LIBRARIES; +                    if (Build.SUPPORTED_32_BIT_ABIS.length > 0) { +                        if (isAsec) { +                            abi32 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_32_BIT_ABIS); +                        } else { +                            abi32 = copyNativeLibrariesForInternalApp(handle, +                                    nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS, useIsaSpecificSubdirs); +                        }                      } -                    if (abiOverride != null || hasLegacyRenderscriptBitcode) { -                        pkg.applicationInfo.cpuAbi = abiList[0]; -                        pkgSetting.cpuAbiString = abiList[0]; -                    } else { -                        setInternalAppAbi(pkg, pkgSetting); + +                    if (abi32 < 0 && abi32 != PackageManager.NO_NATIVE_LIBRARIES) { +                        Slog.w(TAG, "Error unpackaging 32 bit native libs for multiarch app, errorCode=" + abi32); +                        mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR; +                        return null;                      } -                } else { -                    if (!isForwardLocked(pkg) && !isExternal(pkg)) { -                        /* -                        * Update native library dir if it starts with -                        * /data/data -                        */ -                        if (nativeLibraryDir.getPath().startsWith(dataPathString)) { -                            setInternalAppNativeLibraryPath(pkg, pkgSetting); -                            nativeLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir); + +                    if (Build.SUPPORTED_64_BIT_ABIS.length > 0) { +                        if (isAsec) { +                            abi64 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_64_BIT_ABIS); +                        } else { +                            abi64 = copyNativeLibrariesForInternalApp(handle, +                                    nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS, useIsaSpecificSubdirs);                          } +                    } -                        try { -                            int copyRet = copyNativeLibrariesForInternalApp(handle, -                                    nativeLibraryDir, abiList); -                            if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) { -                                Slog.e(TAG, "Unable to copy native libraries"); -                                mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR; -                                return null; -                            } +                    if (abi64 < 0 && abi64 != PackageManager.NO_NATIVE_LIBRARIES) { +                        Slog.w(TAG, "Error unpackaging 64 bit native libs for multiarch app, errorCode=" + abi32); +                        mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR; +                        return null; +                    } -                            // We've successfully copied native libraries across, so we make a -                            // note of what ABI we're using -                            if (copyRet != PackageManager.NO_NATIVE_LIBRARIES) { -                                pkg.applicationInfo.cpuAbi = abiList[copyRet]; -                            } else if (abiOverride != null || hasLegacyRenderscriptBitcode) { -                                pkg.applicationInfo.cpuAbi = abiList[0]; -                            } else { -                                pkg.applicationInfo.cpuAbi = null; -                            } -                        } catch (IOException e) { -                            Slog.e(TAG, "Unable to copy native libraries", e); -                            mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR; -                            return null; -                        } -                    } else { -                        // We don't have to copy the shared libraries if we're in the ASEC container -                        // but we still need to scan the file to figure out what ABI the app needs. -                        // -                        // TODO: This duplicates work done in the default container service. It's possible -                        // to clean this up but we'll need to change the interface between this service -                        // and IMediaContainerService (but doing so will spread this logic out, rather -                        // than centralizing it). -                        final int abi = NativeLibraryHelper.findSupportedAbi(handle, abiList); -                        if (abi >= 0) { -                            pkg.applicationInfo.cpuAbi = abiList[abi]; -                        } else if (abi == PackageManager.NO_NATIVE_LIBRARIES) { -                            // Note that (non upgraded) system apps will not have any native -                            // libraries bundled in their APK, but we're guaranteed not to be -                            // such an app at this point. -                            if (abiOverride != null || hasLegacyRenderscriptBitcode) { -                                pkg.applicationInfo.cpuAbi = abiList[0]; -                            } else { -                                pkg.applicationInfo.cpuAbi = null; -                            } + +                    if (abi64 >= 0) { +                        pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[abi64]; +                    } + +                    if (abi32 >= 0) { +                        final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32]; +                        if (abi64 >= 0) { +                            pkg.applicationInfo.secondaryCpuAbi = abi;                          } else { -                            mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR; -                            return null; +                            pkg.applicationInfo.primaryCpuAbi = abi;                          }                      } +                } else { +                    String[] abiList = (abiOverride != null) ? +                            new String[] { abiOverride } : Build.SUPPORTED_ABIS; + +                    // Enable gross and lame hacks for apps that are built with old +                    // SDK tools. We must scan their APKs for renderscript bitcode and +                    // not launch them if it's present. Don't bother checking on devices +                    // that don't have 64 bit support. +                    if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && abiOverride == null && +                            NativeLibraryHelper.hasRenderscriptBitcode(handle)) { +                        abiList = Build.SUPPORTED_32_BIT_ABIS; +                    } -                    if (DEBUG_INSTALL) Slog.i(TAG, "Linking native library dir for " + path); -                    final int[] userIds = sUserManager.getUserIds(); -                    synchronized (mInstallLock) { -                        for (int userId : userIds) { -                            if (mInstaller.linkNativeLibraryDirectory(pkg.packageName, -                                    pkg.applicationInfo.nativeLibraryDir, userId) < 0) { -                                Slog.w(TAG, "Failed linking native library dir (user=" + userId -                                        + ")"); -                                mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR; -                                return null; -                            } -                        } +                    final int copyRet; +                    if (isAsec) { +                        copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList); +                    } else { +                        copyRet = copyNativeLibrariesForInternalApp(handle, nativeLibraryRoot, abiList, +                                useIsaSpecificSubdirs); +                    } + +                    if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) { +                        Slog.w(TAG, "Error unpackaging native libs for app, errorCode=" + copyRet); +                        mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR; +                        return null;                      } -                } -                pkgSetting.cpuAbiString = pkg.applicationInfo.cpuAbi; +                    if (copyRet >= 0) { +                        pkg.applicationInfo.primaryCpuAbi = abiList[copyRet]; +                    } +                }              } catch (IOException ioe) {                  Slog.e(TAG, "Unable to get canonical file " + ioe.toString());              } finally {                  IoUtils.closeQuietly(handle);              } + +            if (DEBUG_INSTALL) Slog.i(TAG, "Linking native library dir for " + path); +            final int[] userIds = sUserManager.getUserIds(); +            synchronized (mInstallLock) { +                // Create a native library symlink only if we have native libraries +                // and if the native libraries are 32 bit libraries. We do not provide +                // this symlink for 64 bit libraries. +                if (pkg.applicationInfo.primaryCpuAbi != null && +                        !VMRuntime.is64BitAbi(pkg.applicationInfo.primaryCpuAbi)) { +                    final String nativeLibPath; +                    if (pkg.applicationInfo.legacyNativeLibraryDir != null) { +                        nativeLibPath = pkg.applicationInfo.legacyNativeLibraryDir; +                    } else { +                        nativeLibPath = new File(nativeLibraryRootStr, +                                VMRuntime.getInstructionSet(pkg.applicationInfo.primaryCpuAbi)).getAbsolutePath(); +                    } + +                    for (int userId : userIds) { +                        if (mInstaller.linkNativeLibraryDirectory(pkg.packageName, nativeLibPath, userId) < 0) { +                            Slog.w(TAG, "Failed linking native library dir (user=" + userId +                                    + ")"); +                            mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR; +                            return null; +                        } +                    } +                } +            } + +            pkgSetting.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi; +            pkgSetting.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi; +        } + +        if (DEBUG_ABI_SELECTION) { +            Log.d(TAG, "Abis for package[" + pkg.packageName + "] are" + +                    " primary=" + pkg.applicationInfo.primaryCpuAbi + +                    " secondary=" + pkg.applicationInfo.secondaryCpuAbi);          } +        // Check if we have a legacy native library path, use it if we do. +        pkg.applicationInfo.legacyNativeLibraryDir = pkgSetting.legacyNativeLibraryPathString; + +        // Now that we've calculated the ABIs and determined if it's an internal app, +        // we will go ahead and populate the nativeLibraryPath. +        populateDefaultNativeLibraryPath(pkg, pkg.applicationInfo); +          if ((scanMode&SCAN_BOOTING) == 0 && pkgSetting.sharedUser != null) {              // We don't do this here during boot because we can do it all              // at once after scanning all existing packages. @@ -5929,6 +5954,9 @@ public class PackageManagerService extends IPackageManager.Stub {                  a.info.splitSourceDirs = pkg.applicationInfo.splitSourceDirs;                  a.info.splitPublicSourceDirs = pkg.applicationInfo.splitPublicSourceDirs;                  a.info.dataDir = pkg.applicationInfo.dataDir; + +                // TODO: Update instrumentation.nativeLibraryDir as well ? Does it +                // need other information about the application, like the ABI and what not ?                  a.info.nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir;                  mInstrumentation.put(a.getComponentName(), a);                  if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { @@ -5989,13 +6017,16 @@ public class PackageManagerService extends IPackageManager.Stub {       * match {@code scannedPackage} or will update the ABI of {@code scannedPackage} to match       * the ABI selected for {@code packagesForUser}. This variant is used when installing or       * updating a package that belongs to a shared user. +     * +     * NOTE: We currently only match for the primary CPU abi string. Matching the secondary +     * adds unnecessary complexity.       */      private boolean adjustCpuAbisForSharedUserLPw(Set<PackageSetting> packagesForUser,              PackageParser.Package scannedPackage, boolean forceDexOpt, boolean deferDexOpt) {          String requiredInstructionSet = null; -        if (scannedPackage != null && scannedPackage.applicationInfo.cpuAbi != null) { +        if (scannedPackage != null && scannedPackage.applicationInfo.primaryCpuAbi != null) {              requiredInstructionSet = VMRuntime.getInstructionSet( -                     scannedPackage.applicationInfo.cpuAbi); +                     scannedPackage.applicationInfo.primaryCpuAbi);          }          PackageSetting requirer = null; @@ -6005,11 +6036,11 @@ public class PackageManagerService extends IPackageManager.Stub {              // we will never be able to change the ABI of any package belonging to a shared              // user, even if it's compatible with other packages.              if (scannedPackage == null || ! scannedPackage.packageName.equals(ps.name)) { -                if (ps.cpuAbiString == null) { +                if (ps.primaryCpuAbiString == null) {                      continue;                  } -                final String instructionSet = VMRuntime.getInstructionSet(ps.cpuAbiString); +                final String instructionSet = VMRuntime.getInstructionSet(ps.primaryCpuAbiString);                  if (requiredInstructionSet != null) {                      if (!instructionSet.equals(requiredInstructionSet)) {                          // We have a mismatch between instruction sets (say arm vs arm64). @@ -6037,30 +6068,30 @@ public class PackageManagerService extends IPackageManager.Stub {                  // requirer != null implies that either scannedPackage was null or that scannedPackage                  // did not require an ABI, in which case we have to adjust scannedPackage to match                  // the ABI of the set (which is the same as requirer's ABI) -                adjustedAbi = requirer.cpuAbiString; +                adjustedAbi = requirer.primaryCpuAbiString;                  if (scannedPackage != null) { -                    scannedPackage.applicationInfo.cpuAbi = adjustedAbi; +                    scannedPackage.applicationInfo.primaryCpuAbi = adjustedAbi;                  }              } else {                  // requirer == null implies that we're updating all ABIs in the set to                  // match scannedPackage. -                adjustedAbi =  scannedPackage.applicationInfo.cpuAbi; +                adjustedAbi =  scannedPackage.applicationInfo.primaryCpuAbi;              }              for (PackageSetting ps : packagesForUser) {                  if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) { -                    if (ps.cpuAbiString != null) { +                    if (ps.primaryCpuAbiString != null) {                          continue;                      } -                    ps.cpuAbiString = adjustedAbi; +                    ps.primaryCpuAbiString = adjustedAbi;                      if (ps.pkg != null && ps.pkg.applicationInfo != null) { -                        ps.pkg.applicationInfo.cpuAbi = adjustedAbi; +                        ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;                          Slog.i(TAG, "Adjusting ABI for : " + ps.name + " to " + adjustedAbi);                          if (performDexOptLI(ps.pkg, forceDexOpt, deferDexOpt, true) == DEX_OPT_FAILED) { -                            ps.cpuAbiString = null; -                            ps.pkg.applicationInfo.cpuAbi = null; +                            ps.primaryCpuAbiString = null; +                            ps.pkg.applicationInfo.primaryCpuAbi = null;                              return false;                          } else {                              mInstaller.rmdex(ps.codePathString, getPreferredInstructionSet()); @@ -6097,7 +6128,7 @@ public class PackageManagerService extends IPackageManager.Stub {          }      } -    private String calculateApkRoot(final String codePathString) { +    private static String calculateApkRoot(final String codePathString) {          final File codePath = new File(codePathString);          final File codeRoot;          if (FileUtils.contains(Environment.getRootDirectory(), codePath)) { @@ -6121,7 +6152,7 @@ public class PackageManagerService extends IPackageManager.Stub {                  Slog.w(TAG, "Unrecognized code path "                          + codePath + " - using " + codeRoot);              } catch (IOException e) { -                // Can't canonicalize the lib path -- shenanigans? +                // Can't canonicalize the code path -- shenanigans?                  Slog.w(TAG, "Can't canonicalize code path " + codePath);                  return Environment.getRootDirectory().getPath();              } @@ -6129,104 +6160,154 @@ public class PackageManagerService extends IPackageManager.Stub {          return codeRoot.getPath();      } -    // This is the initial scan-time determination of how to handle a given -    // package for purposes of native library location. -    private void setInternalAppNativeLibraryPath(PackageParser.Package pkg, -            PackageSetting pkgSetting) { -        // "bundled" here means system-installed with no overriding update -        final boolean bundledApk = isSystemApp(pkg) && !isUpdatedSystemApp(pkg); -        final File codeFile = new File(pkg.applicationInfo.getCodePath()); -        final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath()); - -        String nativeLibraryPath = null; -        if (bundledApk) { -            // If "/system/lib64/apkname" exists, assume that is the per-package -            // native library directory to use; otherwise use "/system/lib/apkname". -            String apkRoot = calculateApkRoot(pkg.applicationInfo.getCodePath()); -            File lib64 = new File(apkRoot, LIB64_DIR_NAME); -            File packLib64 = new File(lib64, apkName); -            File libDir = (packLib64.exists()) ? lib64 : new File(apkRoot, LIB_DIR_NAME); -            nativeLibraryPath = (new File(libDir, apkName)).getAbsolutePath(); -        } else if (isApkFile(codeFile)) { -            // Monolithic install -            nativeLibraryPath = (new File(mAppLibInstallDir, apkName)).getAbsolutePath(); -        } else { -            // Cluster install -            // TODO: pipe through abiOverride -            String[] abiList = Build.SUPPORTED_ABIS; -            NativeLibraryHelper.Handle handle = null; -            try { -                handle = NativeLibraryHelper.Handle.create(codeFile); -                if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && -                        NativeLibraryHelper.hasRenderscriptBitcode(handle)) { -                    abiList = Build.SUPPORTED_32_BIT_ABIS; +    private void populateDefaultNativeLibraryPath(PackageParser.Package pkg, +                                                  ApplicationInfo info) { +        if (info.legacyNativeLibraryDir != null) { +            // Not a cluster install. +            if (DEBUG_ABI_SELECTION) { +                Log.i(TAG, "Set nativeLibraryDir [non_cluster] for: " + pkg.packageName + +                        " to " + info.legacyNativeLibraryDir); +            } +            info.nativeLibraryDir = info.legacyNativeLibraryDir; +        } else if (info.primaryCpuAbi != null) { +            final boolean is64Bit = VMRuntime.is64BitAbi(info.primaryCpuAbi); +            if (info.apkRoot != null) { +                // This is a bundled system app so choose the path based on the ABI. +                // if it's a 64 bit abi, use lib64 otherwise use lib32. Note that this +                // is just the default path. +                final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath()); +                final String libDir = is64Bit ? LIB64_DIR_NAME : LIB_DIR_NAME; +                info.nativeLibraryDir = (new File(info.apkRoot, new File(libDir, apkName).getAbsolutePath())) +                        .getAbsolutePath(); + +                if (DEBUG_ABI_SELECTION) { +                    Log.i(TAG, "Set nativeLibraryDir [system] for: " + pkg.packageName + +                            " to " + info.nativeLibraryDir);                  } +            } else { +                // Cluster install. legacyNativeLibraryDir == null && primaryCpuAbi = null +                // implies this must be a cluster package. +                final String codePath = pkg.codePath; +                final File libPath = new File(new File(codePath, LIB_DIR_NAME), +                        VMRuntime.getInstructionSet(info.primaryCpuAbi)); +                info.nativeLibraryDir = libPath.getAbsolutePath(); -                final int abiIndex = NativeLibraryHelper.findSupportedAbi(handle, abiList); -                if (abiIndex >= 0) { -                    final File baseLibFile = new File(codeFile, LIB_DIR_NAME); -                    final String abi = Build.SUPPORTED_ABIS[abiIndex]; -                    final String instructionSet = VMRuntime.getInstructionSet(abi); -                    nativeLibraryPath = new File(baseLibFile, instructionSet).getAbsolutePath(); +                if (DEBUG_ABI_SELECTION) { +                    Log.i(TAG, "Set nativeLibraryDir [cluster] for: " + pkg.packageName + +                            " to " + info.nativeLibraryDir);                  } -            } catch (IOException e) { -                Slog.e(TAG, "Failed to detect native libraries", e); -            } finally { -                IoUtils.closeQuietly(handle);              } +        } else { +            if (DEBUG_ABI_SELECTION) { +                Log.i(TAG, "Setting nativeLibraryDir to null for: " + pkg.packageName); +            } + +            info.nativeLibraryDir = null;          } -        pkg.applicationInfo.nativeLibraryDir = nativeLibraryPath; +    } + +    /** +     * Calculate the abis and roots for a bundled app. These can uniquely +     * be determined from the contents of the system partition, i.e whether +     * it contains 64 or 32 bit shared libraries etc. We do not validate any +     * of this information, and instead assume that the system was built +     * sensibly. +     */ +    private void setBundledAppAbisAndRoots(PackageParser.Package pkg, +                                           PackageSetting pkgSetting) { +        final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath()); + +        // If "/system/lib64/apkname" exists, assume that is the per-package +        // native library directory to use; otherwise use "/system/lib/apkname". +        final String apkRoot = calculateApkRoot(pkg.applicationInfo.sourceDir); +        pkg.applicationInfo.apkRoot = apkRoot; +        setBundledAppAbi(pkg, apkRoot, apkName);          // pkgSetting might be null during rescan following uninstall of updates          // to a bundled app, so accommodate that possibility.  The settings in          // that case will be established later from the parsed package. +        // +        // If the settings aren't null, sync them up with what we've just derived. +        // note that apkRoot isn't stored in the package settings.          if (pkgSetting != null) { -            pkgSetting.nativeLibraryPathString = nativeLibraryPath; +            pkgSetting.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi; +            pkgSetting.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;          }      } -    // Deduces the required ABI of an upgraded system app. -    private void setInternalAppAbi(PackageParser.Package pkg, PackageSetting pkgSetting) { -        final String apkRoot = calculateApkRoot(pkg.applicationInfo.getCodePath()); -        final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath()); - +    /** +     * Deduces the ABI of a bundled app and sets the relevant fields on the +     * parsed pkg object. +     * +     * @param apkRoot the root of the installed apk, something like {@code /system} or {@code /oem} +     *        under which system libraries are installed. +     * @param apkName the name of the installed package. +     */ +    private static void setBundledAppAbi(PackageParser.Package pkg, String apkRoot, String apkName) {          // This is of the form "/system/lib64/<packagename>", "/vendor/lib64/<packagename>"          // or similar. -        final File lib64 = new File(apkRoot, new File(LIB64_DIR_NAME, apkName).getPath()); -        final File lib = new File(apkRoot, new File(LIB_DIR_NAME, apkName).getPath()); - -        // Assume that the bundled native libraries always correspond to the -        // most preferred 32 or 64 bit ABI. -        if (lib64.exists()) { -            pkg.applicationInfo.cpuAbi = Build.SUPPORTED_64_BIT_ABIS[0]; -            pkgSetting.cpuAbiString = Build.SUPPORTED_64_BIT_ABIS[0]; -        } else if (lib.exists()) { -            pkg.applicationInfo.cpuAbi = Build.SUPPORTED_32_BIT_ABIS[0]; -            pkgSetting.cpuAbiString = Build.SUPPORTED_32_BIT_ABIS[0]; +        final boolean has64BitLibs = (new File(apkRoot, new File(LIB64_DIR_NAME, apkName).getPath())).exists(); +        final boolean has32BitLibs = (new File(apkRoot, new File(LIB_DIR_NAME, apkName).getPath())).exists(); + +        if (has64BitLibs && !has32BitLibs) { +            // The package has 64 bit libs, but not 32 bit libs. Its primary +            // ABI should be 64 bit. We can safely assume here that the bundled +            // native libraries correspond to the most preferred ABI in the list. + +            pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0]; +            pkg.applicationInfo.secondaryCpuAbi = null; +        } else if (has32BitLibs && !has64BitLibs) { +            // The package has 32 bit libs but not 64 bit libs. Its primary +            // ABI should be 32 bit. + +            pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0]; +            pkg.applicationInfo.secondaryCpuAbi = null; +        } else if (has32BitLibs && has64BitLibs) { +            // The application has both 64 and 32 bit bundled libraries. We check +            // here that the app declares multiArch support, and warn if it doesn't. +            // +            // We will be lenient here and record both ABIs. The primary will be the +            // ABI that's higher on the list, i.e, a device that's configured to prefer +            // 64 bit apps will see a 64 bit primary ABI, + +            if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) == 0) { +                Slog.e(TAG, "Package: " + pkg + " has multiple bundled libs, but is not multiarch."); +            } + +            if (VMRuntime.is64BitAbi(getPreferredInstructionSet())) { +                pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0]; +                pkg.applicationInfo.secondaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0]; +            } else { +                pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0]; +                pkg.applicationInfo.secondaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0]; +            }          } else { -            // This is the case where the app has no native code. -            pkg.applicationInfo.cpuAbi = null; -            pkgSetting.cpuAbiString = null; +            pkg.applicationInfo.primaryCpuAbi = null; +            pkg.applicationInfo.secondaryCpuAbi = null;          }      } -    private static int copyNativeLibrariesForInternalApp(NativeLibraryHelper.Handle handle, -            final File nativeLibraryDir, String[] abiList) throws IOException { -        if (!nativeLibraryDir.isDirectory()) { -            nativeLibraryDir.delete(); +    private static void createNativeLibrarySubdir(File path) throws IOException { +        if (!path.isDirectory()) { +            path.delete(); -            if (!nativeLibraryDir.mkdir()) { -                throw new IOException("Cannot create " + nativeLibraryDir.getPath()); +            if (!path.mkdir()) { +                throw new IOException("Cannot create " + path.getPath());              }              try { -                Os.chmod(nativeLibraryDir.getPath(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); +                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 " -                        + nativeLibraryDir.getPath(), e); +                        + path.getPath(), e);              } -        } else if (!SELinux.restorecon(nativeLibraryDir)) { -            throw new IOException("Cannot set SELinux context for " + nativeLibraryDir.getPath()); +        } else if (!SELinux.restorecon(path)) { +            throw new IOException("Cannot set SELinux context for " + path.getPath());          } +    } + +    private static int copyNativeLibrariesForInternalApp(NativeLibraryHelper.Handle handle, +            final File nativeLibraryRoot, String[] abiList, boolean useIsaSubdir) throws IOException { +        createNativeLibrarySubdir(nativeLibraryRoot);          /*           * If this is an internal application or our nativeLibraryPath points to @@ -6234,8 +6315,22 @@ public class PackageManagerService extends IPackageManager.Stub {           */          int abi = NativeLibraryHelper.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(nativeLibraryRoot, instructionSet); +                createNativeLibrarySubdir(isaSubdir); +                subDir = isaSubdir; +            } else { +                subDir = nativeLibraryRoot; +            } +              int copyRet = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle, -                    nativeLibraryDir, Build.SUPPORTED_ABIS[abi]); +                    subDir, Build.SUPPORTED_ABIS[abi]);              if (copyRet != PackageManager.INSTALL_SUCCEEDED) {                  return copyRet;              } @@ -8374,7 +8469,7 @@ public class PackageManagerService extends IPackageManager.Stub {          private InstallArgs mArgs;          private int mRet;          final String packageAbiOverride; -        final String packageInstructionSetOverride; +        boolean multiArch;          InstallParams(File originFile, boolean originStaged, IPackageInstallObserver2 observer,                  int flags, String installerPackageName, VerificationParams verificationParams, @@ -8387,8 +8482,6 @@ public class PackageManagerService extends IPackageManager.Stub {              this.installerPackageName = installerPackageName;              this.verificationParams = verificationParams;              this.packageAbiOverride = packageAbiOverride; -            this.packageInstructionSetOverride = (packageAbiOverride == null) ? -                    packageAbiOverride : VMRuntime.getInstructionSet(packageAbiOverride);          }          @Override @@ -8499,6 +8592,11 @@ public class PackageManagerService extends IPackageManager.Stub {                  final String originPath = originFile.getAbsolutePath();                  pkgLite = mContainerService.getMinimalPackageInfo(originPath, flags, lowThreshold,                          packageAbiOverride); +                // Keep track of whether this package is a multiArch package until +                // we perform a full scan of it. We need to do this because we might +                // end up extracting the package shared libraries before we perform +                // a full scan. +                multiArch = pkgLite.multiArch;                  /*                   * If we have too little free space, try to free cache @@ -8744,7 +8842,8 @@ public class PackageManagerService extends IPackageManager.Stub {          int mRet;          MoveParams(InstallArgs srcArgs, IPackageMoveObserver observer, int flags, -                String packageName, String instructionSet, int uid, UserHandle user) { +                String packageName, String[] instructionSets, int uid, UserHandle user, +                boolean isMultiArch) {              super(user);              this.srcArgs = srcArgs;              this.observer = observer; @@ -8754,7 +8853,7 @@ public class PackageManagerService extends IPackageManager.Stub {              if (srcArgs != null) {                  final String codePath = srcArgs.getCodePath();                  targetArgs = createInstallArgsForMoveTarget(codePath, flags, packageName, -                        instructionSet); +                        instructionSets, isMultiArch);              } else {                  targetArgs = null;              } @@ -8869,7 +8968,8 @@ public class PackageManagerService extends IPackageManager.Stub {       * when cleaning up old installs, or used as a move source.       */      private InstallArgs createInstallArgsForExisting(int flags, String codePath, -            String resourcePath, String nativeLibraryPath, String instructionSet) { +            String resourcePath, String nativeLibraryRoot, String[] instructionSets, +            boolean isMultiArch) {          final boolean isInAsec;          if (installOnSd(flags)) {              /* Apps on SD card are always in ASEC containers. */ @@ -8886,23 +8986,24 @@ public class PackageManagerService extends IPackageManager.Stub {          }          if (isInAsec) { -            return new AsecInstallArgs(codePath, resourcePath, nativeLibraryPath, -                    instructionSet, installOnSd(flags), installForwardLocked(flags)); +            return new AsecInstallArgs(codePath, instructionSets, +                    installOnSd(flags), installForwardLocked(flags), isMultiArch);          } else { -            return new FileInstallArgs(codePath, resourcePath, nativeLibraryPath, instructionSet); +            return new FileInstallArgs(codePath, resourcePath, nativeLibraryRoot, +                    instructionSets, isMultiArch);          }      }      private InstallArgs createInstallArgsForMoveTarget(String codePath, int flags, String pkgName, -            String instructionSet) { +            String[] instructionSets, boolean isMultiArch) {          final File codeFile = new File(codePath);          if (installOnSd(flags) || installForwardLocked(flags)) {              String cid = getNextCodePath(codePath, pkgName, "/"                      + AsecInstallArgs.RES_FILE_NAME); -            return new AsecInstallArgs(codeFile, cid, instructionSet, installOnSd(flags), -                    installForwardLocked(flags)); +            return new AsecInstallArgs(codeFile, cid, instructionSets, installOnSd(flags), +                    installForwardLocked(flags), isMultiArch);          } else { -            return new FileInstallArgs(codeFile, instructionSet); +            return new FileInstallArgs(codeFile, instructionSets, isMultiArch);          }      } @@ -8920,12 +9021,18 @@ public class PackageManagerService extends IPackageManager.Stub {          final String installerPackageName;          final ManifestDigest manifestDigest;          final UserHandle user; -        final String instructionSet;          final String abiOverride; +        final boolean multiArch; + +        // The list of instruction sets supported by this app. This is currently +        // only used during the rmdex() phase to clean up resources. We can get rid of this +        // if we move dex files under the common app path. +        /* nullable */ String[] instructionSets;          InstallArgs(File originFile, boolean originStaged, IPackageInstallObserver2 observer, -                int flags, String installerPackageName, ManifestDigest manifestDigest, -                UserHandle user, String instructionSet, String abiOverride) { +                    int flags, String installerPackageName, ManifestDigest manifestDigest, +                    UserHandle user, String[] instructionSets, +                    String abiOverride, boolean multiArch) {              this.originFile = originFile;              this.originStaged = originStaged;              this.flags = flags; @@ -8933,8 +9040,9 @@ public class PackageManagerService extends IPackageManager.Stub {              this.installerPackageName = installerPackageName;              this.manifestDigest = manifestDigest;              this.user = user; -            this.instructionSet = instructionSet; +            this.instructionSets = instructionSets;              this.abiOverride = abiOverride; +            this.multiArch = multiArch;          }          abstract int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException; @@ -8951,8 +9059,7 @@ public class PackageManagerService extends IPackageManager.Stub {          abstract String getCodePath();          /** @see PackageSettingBase#resourcePathString */          abstract String getResourcePath(); -        /** @see PackageSettingBase#nativeLibraryPathString */ -        abstract String getNativeLibraryPath(); +        abstract String getLegacyNativeLibraryPath();          // Need installer lock especially for dex file removal.          abstract void cleanUpResourcesLI(); @@ -8995,7 +9102,7 @@ public class PackageManagerService extends IPackageManager.Stub {      class FileInstallArgs extends InstallArgs {          private File codeFile;          private File resourceFile; -        private File nativeLibraryFile; +        private File legacyNativeLibraryPath;          // Example topology:          // /data/app/com.example/base.apk @@ -9008,24 +9115,27 @@ public class PackageManagerService extends IPackageManager.Stub {          FileInstallArgs(InstallParams params) {              super(params.originFile, params.originStaged, params.observer, params.flags,                      params.installerPackageName, params.getManifestDigest(), params.getUser(), -                    params.packageInstructionSetOverride, params.packageAbiOverride); +                    null /* instruction sets */, params.packageAbiOverride, +                    params.multiArch);              if (isFwdLocked()) {                  throw new IllegalArgumentException("Forward locking only supported in ASEC");              }          }          /** Existing install */ -        FileInstallArgs(String codePath, String resourcePath, String nativeLibraryPath, -                String instructionSet) { -            super(null, false, null, 0, null, null, null, instructionSet, null); +        FileInstallArgs(String codePath, String resourcePath, String legacyNativeLibraryRoot, +                String[] instructionSets, boolean isMultiArch) { +            super(null, false, null, 0, null, null, null, instructionSets, null, isMultiArch);              this.codeFile = (codePath != null) ? new File(codePath) : null;              this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null; -            this.nativeLibraryFile = (nativeLibraryPath != null) ? new File(nativeLibraryPath) : null; +            this.legacyNativeLibraryPath = (legacyNativeLibraryRoot != null) ? +                    new File(legacyNativeLibraryRoot) : null;          }          /** New install from existing */ -        FileInstallArgs(File originFile, String instructionSet) { -            super(originFile, false, null, 0, null, null, null, instructionSet, null); +        FileInstallArgs(File originFile, String[] instructionSets, boolean isMultiArch) { +            super(originFile, false, null, 0, null, null, null, instructionSets, null, +                    isMultiArch);          }          boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException { @@ -9091,35 +9201,67 @@ public class PackageManagerService extends IPackageManager.Stub {                  }              } -            String[] abiList = (abiOverride != null) ? -                    new String[] { abiOverride } : Build.SUPPORTED_ABIS; +            final File libraryRoot = new File(codeFile, LIB_DIR_NAME);              NativeLibraryHelper.Handle handle = null;              try {                  handle = NativeLibraryHelper.Handle.create(codeFile); -                if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && -                        abiOverride == null && -                        NativeLibraryHelper.hasRenderscriptBitcode(handle)) { -                    abiList = Build.SUPPORTED_32_BIT_ABIS; -                } - -                // TODO: refactor to avoid double findSupportedAbi() -                final int abiIndex = NativeLibraryHelper.findSupportedAbi(handle, abiList); -                if (abiIndex < 0 && abiIndex != PackageManager.NO_NATIVE_LIBRARIES) { -                    return abiIndex; -                } else if (abiIndex >= 0) { -                    final File baseLibFile = new File(codeFile, LIB_DIR_NAME); -                    baseLibFile.mkdir(); -                    Os.chmod(baseLibFile.getAbsolutePath(), 0755); - -                    final String abi = Build.SUPPORTED_ABIS[abiIndex]; -                    final String instructionSet = VMRuntime.getInstructionSet(abi); -                    nativeLibraryFile = new File(baseLibFile, instructionSet); -                    nativeLibraryFile.mkdir(); -                    Os.chmod(nativeLibraryFile.getAbsolutePath(), 0755); - -                    copyNativeLibrariesForInternalApp(handle, nativeLibraryFile, abiList); -                } -            } catch (IOException | ErrnoException e) { +                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) { +                        Slog.w(TAG, "Ignoring abiOverride for multi arch application."); +                    } + +                    int copyRet = PackageManager.NO_NATIVE_LIBRARIES; +                    if (Build.SUPPORTED_32_BIT_ABIS.length > 0) { +                        copyRet = copyNativeLibrariesForInternalApp(handle, libraryRoot, +                                Build.SUPPORTED_32_BIT_ABIS, true /* use isa specific subdirs */); +                        if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) { +                            Slog.w(TAG, "Failure copying 32 bit native libraries [errorCode=" + copyRet + "]"); +                            return copyRet; +                        } +                    } + +                    if (DEBUG_ABI_SELECTION && copyRet >= 0) { +                        Log.d(TAG, "Installed 32 bit libraries under: " + codeFile + " abi=" + +                                Build.SUPPORTED_32_BIT_ABIS[copyRet]); +                    } + +                    if (Build.SUPPORTED_64_BIT_ABIS.length > 0) { +                        copyRet = copyNativeLibrariesForInternalApp(handle, libraryRoot, +                                Build.SUPPORTED_64_BIT_ABIS, true /* use isa specific subdirs */); +                        if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) { +                            Slog.w(TAG, "Failure copying 64 bit native libraries [errorCode=" + copyRet + "]"); +                            return copyRet; +                        } +                    } + +                    if (DEBUG_ABI_SELECTION && copyRet >= 0) { +                        Log.d(TAG, "Installed 64 bit libraries under: " + codeFile + " abi=" + +                                Build.SUPPORTED_64_BIT_ABIS[copyRet]); +                    } +                } else { +                    String[] abiList = (abiOverride != null) ? +                            new String[] { abiOverride } : Build.SUPPORTED_ABIS; + +                    if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && abiOverride == null && +                            NativeLibraryHelper.hasRenderscriptBitcode(handle)) { +                        abiList = Build.SUPPORTED_32_BIT_ABIS; +                    } + +                    int copyRet = copyNativeLibrariesForInternalApp(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; +                    } + +                    if (DEBUG_ABI_SELECTION && copyRet >= 0) { +                        Log.d(TAG, "Installed libraries under: " + codeFile + " abi=" + abiList[copyRet]); +                    } +                } +            } catch (IOException e) {                  Slog.e(TAG, "Copying native libraries failed", e);                  ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;              } finally { @@ -9156,8 +9298,6 @@ public class PackageManagerService extends IPackageManager.Stub {                  // Reflect the rename internally                  codeFile = afterCodeFile;                  resourceFile = afterCodeFile; -                nativeLibraryFile = FileUtils.rewriteAfterRename(beforeCodeFile, afterCodeFile, -                        nativeLibraryFile);                  // Reflect the rename in scanned details                  pkg.codePath = afterCodeFile.getAbsolutePath(); @@ -9173,7 +9313,8 @@ public class PackageManagerService extends IPackageManager.Stub {                  pkg.applicationInfo.setResourcePath(pkg.codePath);                  pkg.applicationInfo.setBaseResourcePath(pkg.baseCodePath);                  pkg.applicationInfo.setSplitResourcePaths(pkg.splitCodePaths); -                pkg.applicationInfo.nativeLibraryDir = getNativeLibraryPath(); +                // Null out the legacy native dir so we stop using it. +                pkg.applicationInfo.legacyNativeLibraryDir = null;                  return true;              } @@ -9197,8 +9338,8 @@ public class PackageManagerService extends IPackageManager.Stub {          }          @Override -        String getNativeLibraryPath() { -            return (nativeLibraryFile != null) ? nativeLibraryFile.getAbsolutePath() : null; +        String getLegacyNativeLibraryPath() { +            return (legacyNativeLibraryPath != null) ? legacyNativeLibraryPath.getAbsolutePath() : null;          }          private boolean cleanUp() { @@ -9215,9 +9356,11 @@ public class PackageManagerService extends IPackageManager.Stub {                  resourceFile.delete();              } -            if (nativeLibraryFile != null && !FileUtils.contains(codeFile, nativeLibraryFile)) { -                FileUtils.deleteContents(nativeLibraryFile); -                nativeLibraryFile.delete(); +            if (legacyNativeLibraryPath != null && !FileUtils.contains(codeFile, legacyNativeLibraryPath)) { +                if (!FileUtils.deleteContents(legacyNativeLibraryPath)) { +                    Slog.w(TAG, "Couldn't delete native library directory " + legacyNativeLibraryPath); +                } +                legacyNativeLibraryPath.delete();              }              return true; @@ -9238,16 +9381,18 @@ public class PackageManagerService extends IPackageManager.Stub {              cleanUp();              if (!allCodePaths.isEmpty()) { -                if (instructionSet == null) { +                if (instructionSets == null) {                      throw new IllegalStateException("instructionSet == null");                  }                  for (String codePath : allCodePaths) { -                    int retCode = mInstaller.rmdex(codePath, instructionSet); -                    if (retCode < 0) { -                        Slog.w(TAG, "Couldn't remove dex file for package: " -                                +  " at location " + codePath + ", retcode=" + retCode); -                        // we don't consider this to be a failure of the core package deletion +                    for (String instructionSet : instructionSets) { +                        int retCode = mInstaller.rmdex(codePath, instructionSet); +                        if (retCode < 0) { +                            Slog.w(TAG, "Couldn't remove dex file for package: " +                                    + " at location " + codePath + ", retcode=" + retCode); +                            // we don't consider this to be a failure of the core package deletion +                        }                      }                  }              } @@ -9289,21 +9434,22 @@ public class PackageManagerService extends IPackageManager.Stub {          String cid;          String packagePath;          String resourcePath; -        String libraryPath; +        String legacyNativeLibraryDir;          /** New install */          AsecInstallArgs(InstallParams params) {              super(params.originFile, params.originStaged, params.observer, params.flags, -                    params.installerPackageName, params.getManifestDigest(), params.getUser(), -                    params.packageInstructionSetOverride, params.packageAbiOverride); +                    params.installerPackageName, params.getManifestDigest(), +                    params.getUser(), null /* instruction sets */, +                    params.packageAbiOverride, params.multiArch);          }          /** Existing install */ -        AsecInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath, -                String instructionSet, boolean isExternal, boolean isForwardLocked) { +        AsecInstallArgs(String fullCodePath, String[] instructionSets, +                        boolean isExternal, boolean isForwardLocked, boolean isMultiArch) {              super(null, false, null, (isExternal ? INSTALL_EXTERNAL : 0)                      | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, -                    instructionSet, null); +                    instructionSets, null, isMultiArch);              // Extract cid from fullCodePath              int eidx = fullCodePath.lastIndexOf("/");              String subStr1 = fullCodePath.substring(0, eidx); @@ -9312,20 +9458,21 @@ public class PackageManagerService extends IPackageManager.Stub {              setCachePath(subStr1);          } -        AsecInstallArgs(String cid, String instructionSet, boolean isForwardLocked) { +        AsecInstallArgs(String cid, String[] instructionSets, boolean isForwardLocked, +                        boolean isMultiArch) {              super(null, false, null, (isAsecExternal(cid) ? INSTALL_EXTERNAL : 0)                      | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, -                    instructionSet, null); +                    instructionSets, null, isMultiArch);              this.cid = cid;              setCachePath(PackageHelper.getSdDir(cid));          }          /** New install from existing */ -        AsecInstallArgs(File originPackageFile, String cid, String instructionSet, -                boolean isExternal, boolean isForwardLocked) { +        AsecInstallArgs(File originPackageFile, String cid, String[] instructionSets, +                boolean isExternal, boolean isForwardLocked, boolean isMultiArch) {              super(originPackageFile, false, null, (isExternal ? INSTALL_EXTERNAL : 0)                      | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, -                    instructionSet, null); +                    instructionSets, null, isMultiArch);              this.cid = cid;          } @@ -9376,8 +9523,8 @@ public class PackageManagerService extends IPackageManager.Stub {          }          @Override -        String getNativeLibraryPath() { -            return libraryPath; +        String getLegacyNativeLibraryPath() { +            return legacyNativeLibraryDir;          }          int doPreInstall(int status) { @@ -9452,14 +9599,16 @@ public class PackageManagerService extends IPackageManager.Stub {              pkg.applicationInfo.setResourcePath(getResourcePath());              pkg.applicationInfo.setBaseResourcePath(getResourcePath());              pkg.applicationInfo.setSplitResourcePaths(null); -            pkg.applicationInfo.nativeLibraryDir = getNativeLibraryPath(); +            // ASEC installs are considered "legacy" because we don't support +            // multiarch on them yet, and use the old style paths on them. +            pkg.applicationInfo.legacyNativeLibraryDir = legacyNativeLibraryDir;              return true;          }          private void setCachePath(String newCachePath) {              File cachePath = new File(newCachePath); -            libraryPath = new File(cachePath, LIB_DIR_NAME).getPath(); +            legacyNativeLibraryDir = new File(cachePath, LIB_DIR_NAME).getPath();              packagePath = new File(cachePath, RES_FILE_NAME).getPath();              if (isFwdLocked()) { @@ -9508,15 +9657,17 @@ public class PackageManagerService extends IPackageManager.Stub {          void cleanUpResourcesLI() {              String sourceFile = getCodePath();              // Remove dex file -            if (instructionSet == null) { +            if (instructionSets == null) {                  throw new IllegalStateException("instructionSet == null");              } -            int retCode = mInstaller.rmdex(sourceFile, instructionSet); -            if (retCode < 0) { -                Slog.w(TAG, "Couldn't remove dex file for package: " -                        + " at location " -                        + sourceFile.toString() + ", retcode=" + retCode); -                // we don't consider this to be a failure of the core package deletion +            for (String instructionSet : instructionSets) { +                int retCode = mInstaller.rmdex(sourceFile, instructionSet); +                if (retCode < 0) { +                    Slog.w(TAG, "Couldn't remove dex file for package: " +                            + " at location " +                            + sourceFile.toString() + ", retcode=" + retCode); +                    // we don't consider this to be a failure of the core package deletion +                }              }              cleanUp();          } @@ -9922,8 +10073,9 @@ public class PackageManagerService extends IPackageManager.Stub {                  res.removedInfo.args = createInstallArgsForExisting(0,                          deletedPackage.applicationInfo.getCodePath(),                          deletedPackage.applicationInfo.getResourcePath(), -                        deletedPackage.applicationInfo.nativeLibraryDir, -                        getAppInstructionSet(deletedPackage.applicationInfo)); +                        deletedPackage.applicationInfo.legacyNativeLibraryDir, +                        getAppDexInstructionSets(deletedPackage.applicationInfo), +                        isMultiArch(deletedPackage.applicationInfo));              } else {                  res.removedInfo.args = null;              } @@ -9983,10 +10135,11 @@ public class PackageManagerService extends IPackageManager.Stub {      private int moveDexFilesLI(String oldCodePath, PackageParser.Package newPackage) {          // TODO: extend to move split APK dex files          if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) { -            final String instructionSet = getAppInstructionSet(newPackage.applicationInfo); -            int retCode = mInstaller.movedex(oldCodePath, newPackage.baseCodePath, -                                             instructionSet); -            if (retCode != 0) { +            final String[] instructionSets = getAppDexInstructionSets(newPackage.applicationInfo); +            for (String instructionSet : instructionSets) { +                int retCode = mInstaller.movedex(oldCodePath, newPackage.baseCodePath, +                        instructionSet); +                if (retCode != 0) {                  /*                   * Programs may be lazily run through dexopt, so the                   * source may not exist. However, something seems to @@ -9995,9 +10148,10 @@ public class PackageManagerService extends IPackageManager.Stub {                   * remove the target to make sure there isn't a stale                   * file from a previous version of the package.                   */ -                newPackage.mDexOptNeeded = true; -                mInstaller.rmdex(oldCodePath, instructionSet); -                mInstaller.rmdex(newPackage.baseCodePath, instructionSet); +                    newPackage.mDexOptNeeded = true; +                    mInstaller.rmdex(oldCodePath, instructionSet); +                    mInstaller.rmdex(newPackage.baseCodePath, instructionSet); +                }              }          }          return PackageManager.INSTALL_SUCCEEDED; @@ -10234,6 +10388,14 @@ public class PackageManagerService extends IPackageManager.Stub {          return (ps.pkgFlags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0;      } +    private static boolean isMultiArch(PackageSetting ps) { +        return (ps.pkgFlags & ApplicationInfo.FLAG_MULTIARCH) != 0; +    } + +    private static boolean isMultiArch(ApplicationInfo info) { +        return (info.flags & ApplicationInfo.FLAG_MULTIARCH) != 0; +    } +      private static boolean isExternal(PackageParser.Package pkg) {          return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;      } @@ -10591,7 +10753,7 @@ public class PackageManagerService extends IPackageManager.Stub {              // Reinstate the old system package              mSettings.enableSystemPackageLPw(newPs.name);              // Remove any native libraries from the upgraded package. -            NativeLibraryHelper.removeNativeBinariesLI(newPs.nativeLibraryPathString); +            NativeLibraryHelper.removeNativeBinariesLI(newPs.legacyNativeLibraryPathString);          }          // Install the system package          if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs); @@ -10610,7 +10772,7 @@ public class PackageManagerService extends IPackageManager.Stub {          // writer          synchronized (mPackages) {              PackageSetting ps = mSettings.mPackages.get(newPkg.packageName); -            setInternalAppNativeLibraryPath(newPkg, ps); +            setBundledAppAbisAndRoots(newPkg, ps);              updatePermissionsLPw(newPkg.packageName, newPkg,                      UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG);              if (applyUserRestrictions) { @@ -10650,8 +10812,8 @@ public class PackageManagerService extends IPackageManager.Stub {          // Delete application code and resources          if (deleteCodeAndResources && (outInfo != null)) {              outInfo.args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps), -                    ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString, -                    getAppInstructionSetFromSettings(ps)); +                    ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString, +                    getAppDexInstructionSets(ps), isMultiArch(ps));          }          return true;      } @@ -11056,7 +11218,7 @@ public class PackageManagerService extends IPackageManager.Stub {          }          PackageParser.Package p;          boolean dataOnly = false; -        String libDirPath = null; +        String libDirRoot = null;          String asecPath = null;          PackageSetting ps = null;          synchronized (mPackages) { @@ -11071,7 +11233,7 @@ public class PackageManagerService extends IPackageManager.Stub {                  p = ps.pkg;              }              if (ps != null) { -                libDirPath = ps.nativeLibraryPathString; +                libDirRoot = ps.legacyNativeLibraryPathString;              }              if (p != null && (isExternal(p) || isForwardLocked(p))) {                  String secureContainerId = cidFromCodePath(p.applicationInfo.getBaseCodePath()); @@ -11092,8 +11254,12 @@ public class PackageManagerService extends IPackageManager.Stub {              }          }          // TODO: extend to measure size of split APKs -        int res = mInstaller.getSizeInfo(packageName, userHandle, p.baseCodePath, libDirPath, -                publicSrcDir, asecPath, getAppInstructionSetFromSettings(ps), +        // TODO(multiArch): Extend getSizeInfo to look at the full subdirectory tree, +        // not just the first level. +        // TODO(multiArch): Extend getSizeInfo to look at *all* instruction sets, not +        // just the primary. +        int res = mInstaller.getSizeInfo(packageName, userHandle, p.baseCodePath, libDirRoot, +                publicSrcDir, asecPath, getAppDexInstructionSets(ps),                  pStats);          if (res < 0) {              return false; @@ -12357,8 +12523,7 @@ public class PackageManagerService extends IPackageManager.Stub {                      }                      final AsecInstallArgs args = new AsecInstallArgs(cid, -                            getAppInstructionSetFromSettings(ps), -                            isForwardLocked(ps)); +                            getAppDexInstructionSets(ps), isForwardLocked(ps), isMultiArch(ps));                      // The package status is changed only if the code path                      // matches between settings and the container id.                      if (ps.codePathString != null && ps.codePathString.equals(args.getCodePath())) { @@ -12676,16 +12841,17 @@ public class PackageManagerService extends IPackageManager.Stub {               * anyway.               */              if (returnCode != PackageManager.MOVE_SUCCEEDED) { -                processPendingMove(new MoveParams(null, observer, 0, packageName, null, -1, user), +                processPendingMove(new MoveParams(null, observer, 0, packageName, null, -1, user, false),                          returnCode);              } else {                  Message msg = mHandler.obtainMessage(INIT_COPY); -                final String instructionSet = getAppInstructionSet(pkg.applicationInfo); +                final String[] instructionSets = getAppDexInstructionSets(pkg.applicationInfo); +                final boolean multiArch = isMultiArch(pkg.applicationInfo);                  InstallArgs srcArgs = createInstallArgsForExisting(currFlags,                          pkg.applicationInfo.getCodePath(), pkg.applicationInfo.getResourcePath(), -                        pkg.applicationInfo.nativeLibraryDir, instructionSet); +                        pkg.applicationInfo.legacyNativeLibraryDir, instructionSets, multiArch);                  MoveParams mp = new MoveParams(srcArgs, observer, newFlags, packageName, -                        instructionSet, pkg.applicationInfo.uid, user); +                        instructionSets, pkg.applicationInfo.uid, user, multiArch);                  msg.obj = mp;                  mHandler.sendMessage(msg);              } @@ -12747,12 +12913,15 @@ public class PackageManagerService extends IPackageManager.Stub {                                      final String oldCodePath = pkg.codePath;                                      final String newCodePath = mp.targetArgs.getCodePath();                                      final String newResPath = mp.targetArgs.getResourcePath(); -                                    final String newNativePath = mp.targetArgs -                                            .getNativeLibraryPath(); - -                                    final File newNativeDir = new File(newNativePath); +                                    // TODO: This assumes the new style of installation. +                                    // should we look at legacyNativeLibraryPath ? +                                    final String newNativeRoot = new File(pkg.codePath, LIB_DIR_NAME).getAbsolutePath(); +                                    final File newNativeDir = new File(newNativeRoot);                                      if (!isForwardLocked(pkg) && !isExternal(pkg)) { +                                        // TODO(multiArch): Fix this so that it looks at the existing +                                        // recorded CPU abis from the package. There's no need for a separate +                                        // round of ABI scanning here.                                          NativeLibraryHelper.Handle handle = null;                                          try {                                              handle = NativeLibraryHelper.Handle.create( @@ -12771,11 +12940,17 @@ public class PackageManagerService extends IPackageManager.Stub {                                              IoUtils.closeQuietly(handle);                                          }                                      } +                                      final int[] users = sUserManager.getUserIds();                                      if (returnCode == PackageManager.MOVE_SUCCEEDED) {                                          for (int user : users) { +                                            // TODO(multiArch): Fix this so that it links to the +                                            // correct directory. We're currently pointing to root. but we +                                            // must point to the arch specific subdirectory (if applicable). +                                            // +                                            // TODO(multiArch): Bogus reference to nativeLibraryDir.                                              if (mInstaller.linkNativeLibraryDirectory(pkg.packageName, -                                                    newNativePath, user) < 0) { +                                                    newNativeRoot, user) < 0) {                                                  returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;                                              }                                          } @@ -12801,15 +12976,21 @@ public class PackageManagerService extends IPackageManager.Stub {                                          pkg.applicationInfo.setResourcePath(newResPath);                                          pkg.applicationInfo.setBaseResourcePath(newResPath);                                          pkg.applicationInfo.setSplitResourcePaths(null); -                                        pkg.applicationInfo.nativeLibraryDir = newNativePath; +                                        // Null out the legacy nativeLibraryDir so that we stop using it and +                                        // always derive the codepath. +                                        pkg.applicationInfo.legacyNativeLibraryDir = null;                                          PackageSetting ps = (PackageSetting) pkg.mExtras;                                          ps.codePath = new File(pkg.applicationInfo.getCodePath());                                          ps.codePathString = ps.codePath.getPath(); -                                        ps.resourcePath = new File( -                                                pkg.applicationInfo.getResourcePath()); +                                        ps.resourcePath = new File(pkg.applicationInfo.getResourcePath());                                          ps.resourcePathString = ps.resourcePath.getPath(); -                                        ps.nativeLibraryPathString = newNativePath; + +                                        // Note that we don't have to recalculate the primary and secondary +                                        // CPU ABIs because they must already have been calculated during the +                                        // initial install of the app. +                                        ps.legacyNativeLibraryPathString = null; +                                          // Set the application info flag                                          // correctly.                                          if ((mp.flags & PackageManager.INSTALL_EXTERNAL) != 0) { diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index 284da99c9f2d..a6571cf7b1ee 100644 --- a/services/core/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java @@ -30,9 +30,10 @@ final class PackageSetting extends PackageSettingBase {      SharedUserSetting sharedUser;      PackageSetting(String name, String realName, File codePath, File resourcePath, -            String nativeLibraryPathString, String cpuAbiString, int pVersionCode, int pkgFlags) { -        super(name, realName, codePath, resourcePath, nativeLibraryPathString, cpuAbiString, pVersionCode, -                pkgFlags); +            String legacyNativeLibraryPathString, String primaryCpuAbiString, +            String secondaryCpuAbiString, int pVersionCode, int pkgFlags) { +        super(name, realName, codePath, resourcePath, legacyNativeLibraryPathString, +                primaryCpuAbiString, secondaryCpuAbiString, pVersionCode, pkgFlags);      }      /** diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java index f263e070ddb0..3390efe18610 100644 --- a/services/core/java/com/android/server/pm/PackageSettingBase.java +++ b/services/core/java/com/android/server/pm/PackageSettingBase.java @@ -55,8 +55,16 @@ class PackageSettingBase extends GrantedPermissions {      String codePathString;      File resourcePath;      String resourcePathString; -    String nativeLibraryPathString; -    String cpuAbiString; + +    /** +     * The path under which native libraries for legacy apps are unpacked. +     * Will be set to {@code null} for newer installs, where the path can be +     * derived from {@link #codePath} unambiguously. +     */ +    String legacyNativeLibraryPathString; + +    String primaryCpuAbiString; +    String secondaryCpuAbiString;      long timeStamp;      long firstInstallTime;      long lastUpdateTime; @@ -84,11 +92,13 @@ class PackageSettingBase extends GrantedPermissions {      /* package name of the app that installed this package */      String installerPackageName;      PackageSettingBase(String name, String realName, File codePath, File resourcePath, -            String nativeLibraryPathString, String cpuAbiString, int pVersionCode, int pkgFlags) { +            String legacyNativeLibraryPathString, String primaryCpuAbiString, +            String secondaryCpuAbiString, int pVersionCode, int pkgFlags) {          super(pkgFlags);          this.name = name;          this.realName = realName; -        init(codePath, resourcePath, nativeLibraryPathString, cpuAbiString, pVersionCode); +        init(codePath, resourcePath, legacyNativeLibraryPathString, primaryCpuAbiString, +                secondaryCpuAbiString, pVersionCode);      }      /** @@ -104,8 +114,9 @@ class PackageSettingBase extends GrantedPermissions {          codePathString = base.codePathString;          resourcePath = base.resourcePath;          resourcePathString = base.resourcePathString; -        nativeLibraryPathString = base.nativeLibraryPathString; -        cpuAbiString = base.cpuAbiString; +        legacyNativeLibraryPathString = base.legacyNativeLibraryPathString; +        primaryCpuAbiString = base.primaryCpuAbiString; +        secondaryCpuAbiString = base.secondaryCpuAbiString;          timeStamp = base.timeStamp;          firstInstallTime = base.firstInstallTime;          lastUpdateTime = base.lastUpdateTime; @@ -132,14 +143,15 @@ class PackageSettingBase extends GrantedPermissions {      } -    void init(File codePath, File resourcePath, String nativeLibraryPathString, -            String requiredCpuAbiString, int pVersionCode) { +    void init(File codePath, File resourcePath, String legacyNativeLibraryPathString, +              String primaryCpuAbiString, String secondaryCpuAbiString, int pVersionCode) {          this.codePath = codePath;          this.codePathString = codePath.toString();          this.resourcePath = resourcePath;          this.resourcePathString = resourcePath.toString(); -        this.nativeLibraryPathString = nativeLibraryPathString; -        this.cpuAbiString = requiredCpuAbiString; +        this.legacyNativeLibraryPathString = legacyNativeLibraryPathString; +        this.primaryCpuAbiString = primaryCpuAbiString; +        this.secondaryCpuAbiString = secondaryCpuAbiString;          this.versionCode = pVersionCode;      } @@ -170,7 +182,8 @@ class PackageSettingBase extends GrantedPermissions {          grantedPermissions = base.grantedPermissions;          gids = base.gids; -        cpuAbiString = base.cpuAbiString; +        primaryCpuAbiString = base.primaryCpuAbiString; +        secondaryCpuAbiString = base.secondaryCpuAbiString;          timeStamp = base.timeStamp;          firstInstallTime = base.firstInstallTime;          lastUpdateTime = base.lastUpdateTime; diff --git a/services/core/java/com/android/server/pm/PendingPackage.java b/services/core/java/com/android/server/pm/PendingPackage.java index 36c3a349d824..85be6513cb2e 100644 --- a/services/core/java/com/android/server/pm/PendingPackage.java +++ b/services/core/java/com/android/server/pm/PendingPackage.java @@ -22,9 +22,10 @@ final class PendingPackage extends PackageSettingBase {      final int sharedId;      PendingPackage(String name, String realName, File codePath, File resourcePath, -            String nativeLibraryPathString, String requiredCpuAbiString, int sharedId, int pVersionCode, int pkgFlags) { -        super(name, realName, codePath, resourcePath, nativeLibraryPathString, requiredCpuAbiString, pVersionCode, -                pkgFlags); +            String nativeLibrary32PathString, String nativeLibrary64PathString, +            String requiredCpuAbiString, int sharedId, int pVersionCode, int pkgFlags) { +        super(name, realName, codePath, resourcePath, nativeLibrary32PathString, nativeLibrary64PathString, +                requiredCpuAbiString, pVersionCode, pkgFlags);          this.sharedId = sharedId;      }  } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 81ea72ca9b82..71b89746551a 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -29,7 +29,13 @@ import android.content.IntentFilter;  import android.content.pm.ActivityInfo;  import android.content.pm.ResolveInfo;  import android.net.Uri; +import android.os.Binder; +import android.os.Environment; +import android.os.FileUtils;  import android.os.PatternMatcher; +import android.os.Process; +import android.os.UserHandle; +import android.os.UserManager;  import android.util.LogPrinter;  import com.android.internal.util.FastXmlSerializer; @@ -56,12 +62,6 @@ import android.content.pm.Signature;  import android.content.pm.UserInfo;  import android.content.pm.PackageUserState;  import android.content.pm.VerifierDeviceIdentity; -import android.os.Binder; -import android.os.Environment; -import android.os.FileUtils; -import android.os.Process; -import android.os.UserHandle; -import android.os.UserManager;  import android.util.Log;  import android.util.Slog;  import android.util.SparseArray; @@ -317,11 +317,12 @@ final class Settings {      PackageSetting getPackageLPw(PackageParser.Package pkg, PackageSetting origPackage,              String realName, SharedUserSetting sharedUser, File codePath, File resourcePath, -            String nativeLibraryPathString, String cpuAbiString, int pkgFlags, UserHandle user, boolean add) { +            String nativeLibraryRoot, String primaryCpuAbi, String secondaryCpuAbi, int pkgFlags, +            UserHandle user, boolean add) {          final String name = pkg.packageName;          PackageSetting p = getPackageLPw(name, origPackage, realName, sharedUser, codePath, -                resourcePath, nativeLibraryPathString, cpuAbiString, pkg.mVersionCode, pkgFlags, -                user, add, true /* allowInstall */); +                resourcePath, nativeLibraryRoot, primaryCpuAbi, secondaryCpuAbi, +                pkg.mVersionCode, pkgFlags, user, add, true /* allowInstall */);          return p;      } @@ -407,7 +408,8 @@ final class Settings {              p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;          }          PackageSetting ret = addPackageLPw(name, p.realName, p.codePath, p.resourcePath, -                p.nativeLibraryPathString, p.cpuAbiString, p.appId, p.versionCode, p.pkgFlags); +                p.legacyNativeLibraryPathString, p.primaryCpuAbiString, +                p.secondaryCpuAbiString, p.appId, p.versionCode, p.pkgFlags);          mDisabledSysPackages.remove(name);          return ret;      } @@ -421,7 +423,8 @@ final class Settings {      }      PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath, -            String nativeLibraryPathString, String cpuAbiString, int uid, int vc, int pkgFlags) { +            String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString, +            int uid, int vc, int pkgFlags) {          PackageSetting p = mPackages.get(name);          if (p != null) {              if (p.appId == uid) { @@ -431,8 +434,8 @@ final class Settings {                      "Adding duplicate package, keeping first: " + name);              return null;          } -        p = new PackageSetting(name, realName, codePath, resourcePath, nativeLibraryPathString, cpuAbiString, -                vc, pkgFlags); +        p = new PackageSetting(name, realName, codePath, resourcePath, +                legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString, vc, pkgFlags);          p.appId = uid;          if (addUserIdLPw(uid, p, name)) {              mPackages.put(name, p); @@ -500,11 +503,12 @@ final class Settings {      private PackageSetting getPackageLPw(String name, PackageSetting origPackage,              String realName, SharedUserSetting sharedUser, File codePath, File resourcePath, -            String nativeLibraryPathString, String cpuAbiString, int vc, int pkgFlags, -            UserHandle installUser, boolean add, boolean allowInstall) { +            String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString, +            int vc, int pkgFlags, UserHandle installUser, boolean add, boolean allowInstall) {          PackageSetting p = mPackages.get(name);          if (p != null) { -            p.cpuAbiString = cpuAbiString; +            p.primaryCpuAbiString = primaryCpuAbiString; +            p.secondaryCpuAbiString = secondaryCpuAbiString;              if (!p.codePath.equals(codePath)) {                  // Check to see if its a disabled system app                  if ((p.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) { @@ -524,7 +528,7 @@ final class Settings {                       * package settings since we might have moved from                       * internal to external storage or vice versa.                       */ -                    p.nativeLibraryPathString = nativeLibraryPathString; +                    p.legacyNativeLibraryPathString = legacyNativeLibraryPathString;                  }              }              if (p.sharedUser != sharedUser) { @@ -548,7 +552,7 @@ final class Settings {              if (origPackage != null) {                  // We are consuming the data from an existing package.                  p = new PackageSetting(origPackage.name, name, codePath, resourcePath, -                        nativeLibraryPathString, cpuAbiString, vc, pkgFlags); +                        legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString, vc, pkgFlags);                  if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package "                          + name + " is adopting original package " + origPackage.name);                  // Note that we will retain the new package's signature so @@ -565,7 +569,7 @@ final class Settings {                  p.setTimeStamp(codePath.lastModified());              } else {                  p = new PackageSetting(name, realName, codePath, resourcePath, -                        nativeLibraryPathString, cpuAbiString, vc, pkgFlags); +                        legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString, vc, pkgFlags);                  p.setTimeStamp(codePath.lastModified());                  p.sharedUser = sharedUser;                  // If this is not a system app, it starts out stopped. @@ -699,14 +703,15 @@ final class Settings {              p.resourcePath = new File(resourcePath);              p.resourcePathString = resourcePath;          } -        // Update the native library path if needed -        final String nativeLibraryPath = pkg.applicationInfo.nativeLibraryDir; -        if (nativeLibraryPath != null -                && !nativeLibraryPath.equalsIgnoreCase(p.nativeLibraryPathString)) { -            p.nativeLibraryPathString = nativeLibraryPath; +        // Update the native library paths if needed +        final String nativeLibraryRoot = pkg.applicationInfo.legacyNativeLibraryDir; +        if (nativeLibraryRoot != null && !nativeLibraryRoot.equalsIgnoreCase(p.legacyNativeLibraryPathString)) { +            p.legacyNativeLibraryPathString = nativeLibraryRoot;          } +          // Update the required Cpu Abi -        p.cpuAbiString = pkg.applicationInfo.cpuAbi; +        p.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi; +        p.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;          // Update version code if needed          if (pkg.mVersionCode != p.versionCode) {              p.versionCode = pkg.mVersionCode; @@ -1861,12 +1866,16 @@ final class Settings {          if (!pkg.resourcePathString.equals(pkg.codePathString)) {              serializer.attribute(null, "resourcePath", pkg.resourcePathString);          } -        if (pkg.nativeLibraryPathString != null) { -            serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString); +        if (pkg.legacyNativeLibraryPathString != null) { +            serializer.attribute(null, "nativeLibraryPath", pkg.legacyNativeLibraryPathString);          } -        if (pkg.cpuAbiString != null) { -           serializer.attribute(null, "requiredCpuAbi", pkg.cpuAbiString); +        if (pkg.primaryCpuAbiString != null) { +           serializer.attribute(null, "primaryCpuAbi", pkg.primaryCpuAbiString);          } +        if (pkg.secondaryCpuAbiString != null) { +            serializer.attribute(null, "secondaryCpuAbi", pkg.secondaryCpuAbiString); +        } +          if (pkg.sharedUser == null) {              serializer.attribute(null, "userId", Integer.toString(pkg.appId));          } else { @@ -1906,12 +1915,17 @@ final class Settings {          if (!pkg.resourcePathString.equals(pkg.codePathString)) {              serializer.attribute(null, "resourcePath", pkg.resourcePathString);          } -        if (pkg.nativeLibraryPathString != null) { -            serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString); + +        if (pkg.legacyNativeLibraryPathString != null) { +            serializer.attribute(null, "nativeLibraryPath", pkg.legacyNativeLibraryPathString); +        } +        if (pkg.primaryCpuAbiString != null) { +            serializer.attribute(null, "primaryCpuAbi", pkg.primaryCpuAbiString);          } -        if (pkg.cpuAbiString != null) { -           serializer.attribute(null, "requiredCpuAbi", pkg.cpuAbiString); +        if (pkg.secondaryCpuAbiString != null) { +            serializer.attribute(null, "secondaryCpuAbi", pkg.secondaryCpuAbiString);          } +          serializer.attribute(null, "flags", Integer.toString(pkg.pkgFlags));          serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp));          serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime)); @@ -2219,7 +2233,8 @@ final class Settings {              if (idObj != null && idObj instanceof SharedUserSetting) {                  PackageSetting p = getPackageLPw(pp.name, null, pp.realName,                          (SharedUserSetting) idObj, pp.codePath, pp.resourcePath, -                        pp.nativeLibraryPathString, pp.cpuAbiString, pp.versionCode, pp.pkgFlags, +                        pp.legacyNativeLibraryPathString, pp.primaryCpuAbiString, +                        pp.secondaryCpuAbiString, pp.versionCode, pp.pkgFlags,                          null, true /* add */, false /* allowInstall */);                  if (p == null) {                      PackageManagerService.reportSettingsProblem(Log.WARN, @@ -2638,8 +2653,16 @@ final class Settings {          String realName = parser.getAttributeValue(null, "realName");          String codePathStr = parser.getAttributeValue(null, "codePath");          String resourcePathStr = parser.getAttributeValue(null, "resourcePath"); -        String nativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath"); -        String cpuAbiString = parser.getAttributeValue(null, "requiredCpuAbi"); + +        String legacyCpuAbiStr = parser.getAttributeValue(null, "requiredCpuAbi"); +        String legacyNativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath"); + +        String primaryCpuAbiStr = parser.getAttributeValue(null, "primaryCpuAbi"); +        String secondaryCpuAbiStr = parser.getAttributeValue(null, "secondaryCpuAbi"); + +        if (primaryCpuAbiStr == null && legacyCpuAbiStr != null) { +            primaryCpuAbiStr = legacyCpuAbiStr; +        }          if (resourcePathStr == null) {              resourcePathStr = codePathStr; @@ -2660,7 +2683,8 @@ final class Settings {              pkgFlags |= ApplicationInfo.FLAG_PRIVILEGED;          }          PackageSetting ps = new PackageSetting(name, realName, codePathFile, -                new File(resourcePathStr), nativeLibraryPathStr, cpuAbiString, versionCode, pkgFlags); +                new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiStr, +                secondaryCpuAbiStr, versionCode, pkgFlags);          String timeStampStr = parser.getAttributeValue(null, "ft");          if (timeStampStr != null) {              try { @@ -2726,8 +2750,10 @@ final class Settings {          String sharedIdStr = null;          String codePathStr = null;          String resourcePathStr = null; -        String nativeLibraryPathStr = null; -        String cpuAbiString = null; +        String legacyCpuAbiString = null; +        String legacyNativeLibraryPathStr = null; +        String primaryCpuAbiString = null; +        String secondaryCpuAbiString = null;          String systemStr = null;          String installerPackageName = null;          String uidError = null; @@ -2746,9 +2772,17 @@ final class Settings {              sharedIdStr = parser.getAttributeValue(null, "sharedUserId");              codePathStr = parser.getAttributeValue(null, "codePath");              resourcePathStr = parser.getAttributeValue(null, "resourcePath"); -            nativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath"); -            cpuAbiString = parser.getAttributeValue(null, "requiredCpuAbi"); +            legacyCpuAbiString = parser.getAttributeValue(null, "requiredCpuAbi"); + +            legacyNativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath"); +            primaryCpuAbiString = parser.getAttributeValue(null, "primaryCpuAbi"); +            secondaryCpuAbiString = parser.getAttributeValue(null, "secondaryCpuAbi"); + +            if (primaryCpuAbiString == null && legacyCpuAbiString != null) { +                primaryCpuAbiString = legacyCpuAbiString; +            } +;              version = parser.getAttributeValue(null, "version");              if (version != null) {                  try { @@ -2825,8 +2859,8 @@ final class Settings {                                  + parser.getPositionDescription());              } else if (userId > 0) {                  packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr), -                        new File(resourcePathStr), nativeLibraryPathStr, cpuAbiString, userId, versionCode, -                        pkgFlags); +                        new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiString, +                        secondaryCpuAbiString, userId, versionCode, pkgFlags);                  if (PackageManagerService.DEBUG_SETTINGS)                      Log.i(PackageManagerService.TAG, "Reading package " + name + ": userId="                              + userId + " pkg=" + packageSetting); @@ -2843,8 +2877,8 @@ final class Settings {                  userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;                  if (userId > 0) {                      packageSetting = new PendingPackage(name.intern(), realName, new File( -                            codePathStr), new File(resourcePathStr), nativeLibraryPathStr, cpuAbiString, userId, -                            versionCode, pkgFlags); +                            codePathStr), new File(resourcePathStr), legacyNativeLibraryPathStr, +                            primaryCpuAbiString, legacyCpuAbiString, userId, versionCode, pkgFlags);                      packageSetting.setTimeStamp(timeStamp);                      packageSetting.firstInstallTime = firstInstallTime;                      packageSetting.lastUpdateTime = lastUpdateTime; @@ -2871,8 +2905,9 @@ final class Settings {          if (packageSetting != null) {              packageSetting.uidError = "true".equals(uidError);              packageSetting.installerPackageName = installerPackageName; -            packageSetting.nativeLibraryPathString = nativeLibraryPathStr; -            packageSetting.cpuAbiString = cpuAbiString; +            packageSetting.legacyNativeLibraryPathString = legacyNativeLibraryPathStr; +            packageSetting.primaryCpuAbiString = primaryCpuAbiString; +            packageSetting.secondaryCpuAbiString = secondaryCpuAbiString;              // Handle legacy string here for single-user mode              final String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED);              if (enabledStr != null) { @@ -3417,8 +3452,9 @@ final class Settings {          pw.print(prefix); pw.print("  pkg="); pw.println(ps.pkg);          pw.print(prefix); pw.print("  codePath="); pw.println(ps.codePathString);          pw.print(prefix); pw.print("  resourcePath="); pw.println(ps.resourcePathString); -        pw.print(prefix); pw.print("  nativeLibraryPath="); pw.println(ps.nativeLibraryPathString); -        pw.print(prefix); pw.print("  requiredCpuAbi="); pw.println(ps.cpuAbiString); +        pw.print(prefix); pw.print("  legacyNativeLibraryDir="); pw.println(ps.legacyNativeLibraryPathString); +        pw.print(prefix); pw.print("  primaryCpuAbi="); pw.println(ps.primaryCpuAbiString); +        pw.print(prefix); pw.print("  secondaryCpuAbi="); pw.println(ps.secondaryCpuAbiString);          pw.print(prefix); pw.print("  versionCode="); pw.print(ps.versionCode);          if (ps.pkg != null) {              pw.print(" targetSdk="); pw.print(ps.pkg.applicationInfo.targetSdkVersion); |