Run 32-bit app in multiArch APK.

Bug: 26874366

Change-Id: I2c1fd1d036efe72b28b5fe996416df69a583959f
diff --git a/api/system-current.txt b/api/system-current.txt
index 1091ff1..3038520 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -293,6 +293,7 @@
 
   public static final class R.attr {
     ctor public R.attr();
+    field public static final int abiOverride = 16844054; // 0x1010516
     field public static final int absListViewStyle = 16842858; // 0x101006a
     field public static final int accessibilityEventTypes = 16843648; // 0x1010380
     field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 220fb607..c071162 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -326,8 +326,7 @@
                 // This is a temporary hack. Callers must use
                 // createPackageContext(packageName).getApplicationInfo() to
                 // get the right paths.
-                maybeAdjustApplicationInfo(ai);
-                return ai;
+                return maybeAdjustApplicationInfo(ai);
             }
         } catch (RemoteException e) {
             throw new RuntimeException("Package manager has died", e);
@@ -336,7 +335,7 @@
         throw new NameNotFoundException(packageName);
     }
 
-    private static void maybeAdjustApplicationInfo(ApplicationInfo info) {
+    private static ApplicationInfo maybeAdjustApplicationInfo(ApplicationInfo info) {
         // If we're dealing with a multi-arch application that has both
         // 32 and 64 bit shared libraries, we might need to choose the secondary
         // depending on what the current runtime's instruction set is.
@@ -353,9 +352,12 @@
             // Everything will be set up correctly because info.nativeLibraryDir will
             // correspond to the right ISA.
             if (runtimeIsa.equals(secondaryIsa)) {
-                info.nativeLibraryDir = info.secondaryNativeLibraryDir;
+                ApplicationInfo modified = new ApplicationInfo(info);
+                modified.nativeLibraryDir = info.secondaryNativeLibraryDir;
+                return modified;
             }
         }
+        return info;
     }
 
     @Override
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 44cd003..73b5b69 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -290,6 +290,7 @@
 
         public final boolean coreApp;
         public final boolean multiArch;
+        public final String abiOverride;
         public final boolean extractNativeLibs;
 
         public PackageLite(String codePath, ApkLite baseApk, String[] splitNames,
@@ -306,6 +307,7 @@
             this.splitRevisionCodes = splitRevisionCodes;
             this.coreApp = baseApk.coreApp;
             this.multiArch = baseApk.multiArch;
+            this.abiOverride = baseApk.abiOverride;
             this.extractNativeLibs = baseApk.extractNativeLibs;
         }
 
@@ -333,11 +335,12 @@
         public final Signature[] signatures;
         public final boolean coreApp;
         public final boolean multiArch;
+        public final String abiOverride;
         public final boolean extractNativeLibs;
 
         public ApkLite(String codePath, String packageName, String splitName, int versionCode,
                 int revisionCode, int installLocation, List<VerifierInfo> verifiers,
-                Signature[] signatures, boolean coreApp, boolean multiArch,
+                Signature[] signatures, boolean coreApp, boolean multiArch, String abiOverride,
                 boolean extractNativeLibs) {
             this.codePath = codePath;
             this.packageName = packageName;
@@ -349,6 +352,7 @@
             this.signatures = signatures;
             this.coreApp = coreApp;
             this.multiArch = multiArch;
+            this.abiOverride = abiOverride;
             this.extractNativeLibs = extractNativeLibs;
         }
     }
@@ -792,6 +796,7 @@
             }
 
             pkg.codePath = packageDir.getAbsolutePath();
+            pkg.cpuAbiOverride = lite.abiOverride;
             return pkg;
         } finally {
             IoUtils.closeQuietly(assets);
@@ -810,8 +815,8 @@
      */
     @Deprecated
     public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
+        final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
         if (mOnlyCoreApps) {
-            final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
             if (!lite.coreApp) {
                 throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
                         "Not a coreApp: " + apkFile);
@@ -822,6 +827,7 @@
         try {
             final Package pkg = parseBaseApk(apkFile, assets, flags);
             pkg.codePath = apkFile.getAbsolutePath();
+            pkg.cpuAbiOverride = lite.abiOverride;
             return pkg;
         } finally {
             IoUtils.closeQuietly(assets);
@@ -1315,6 +1321,7 @@
         int revisionCode = 0;
         boolean coreApp = false;
         boolean multiArch = false;
+        String abiOverride = null;
         boolean extractNativeLibs = true;
 
         for (int i = 0; i < attrs.getAttributeCount(); i++) {
@@ -1355,6 +1362,9 @@
                     if ("multiArch".equals(attr)) {
                         multiArch = attrs.getAttributeBooleanValue(i, false);
                     }
+                    if ("abiOverride".equals(attr)) {
+                        abiOverride = attrs.getAttributeValue(i);
+                    }
                     if ("extractNativeLibs".equals(attr)) {
                         extractNativeLibs = attrs.getAttributeBooleanValue(i, true);
                     }
@@ -1364,7 +1374,7 @@
 
         return new ApkLite(codePath, packageSplit.first, packageSplit.second, versionCode,
                 revisionCode, installLocation, verifiers, signatures, coreApp, multiArch,
-                extractNativeLibs);
+                abiOverride, extractNativeLibs);
     }
 
     /**
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 6eba78a..c45715d 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -429,6 +429,12 @@
          sets. -->
     <attr name="multiArch" format ="boolean" />
 
+    <!-- Specify abiOverride for multiArch application.
+         @hide
+         @SystemApi
+     -->
+    <attr name="abiOverride" />
+
     <!-- Specify whether a component is allowed to have multiple instances
          of itself running in different processes.  Use with the activity
          and provider tags.
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index a2ad09b..02b07d1 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2696,6 +2696,7 @@
     <public type="attr" name="endX" />
     <public type="attr" name="endY" />
     <public type="attr" name="offset" />
+    <public type="attr" name="abiOverride" />
 
     <public type="style" name="Theme.Material.Light.DialogWhenLarge.DarkActionBar" />
     <public type="style" name="Widget.Material.SeekBar.Discrete" />
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 1c4176a..58e9d9e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -7972,6 +7972,11 @@
                         pkg.applicationInfo.primaryCpuAbi = abi;
                     }
                 }
+                if (cpuAbiOverride != null &&
+                        cpuAbiOverride.equals(pkg.applicationInfo.secondaryCpuAbi)) {
+                    pkg.applicationInfo.secondaryCpuAbi = pkg.applicationInfo.primaryCpuAbi;
+                    pkg.applicationInfo.primaryCpuAbi = cpuAbiOverride;
+                }
             } else {
                 String[] abiList = (cpuAbiOverride != null) ?
                         new String[] { cpuAbiOverride } : Build.SUPPORTED_ABIS;
@@ -12828,8 +12833,11 @@
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
 
-        // Mark that we have an install time CPU ABI override.
-        pkg.cpuAbiOverride = args.abiOverride;
+        // If package doesn't declare API override, mark that we have an install
+        // time CPU ABI override.
+        if (TextUtils.isEmpty(pkg.cpuAbiOverride)) {
+            pkg.cpuAbiOverride = args.abiOverride;
+        }
 
         String pkgName = res.name = pkg.packageName;
         if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
@@ -13002,7 +13010,9 @@
             scanFlags |= SCAN_NO_DEX;
 
             try {
-                derivePackageAbi(pkg, new File(pkg.codePath), args.abiOverride,
+                String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
+                    args.abiOverride : pkg.cpuAbiOverride);
+                derivePackageAbi(pkg, new File(pkg.codePath), abiOverride,
                         true /* extract libs */);
             } catch (PackageManagerException pme) {
                 Slog.e(TAG, "Error deriving application ABI", pme);