Use native ISA for dex code (in case there's a NativeBridge)

In the presence of a native bridge it is more efficient to compile the
dex directly to the native ISA than to use the shared library ISA as a
reference.

This can be achieve by configuring the readonly system properties to map
between the .so ISA and the desired dex code .ISA (e.g.
ro.dalvik.vm.isa.ISA1=ISA2).

Bug: 16185267

(cherry picked from commit I50baa7b37e1465b9adf72d6f6b96f526a08d59c7)
(cherry picked from commit I8fe453a800812e382e8f41b5f7922997aa9c18a9)

Change-Id: I6c9684149691285310c961189b58af8c7f47aff4
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 4bf6636..8b16346 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1402,7 +1402,9 @@
 
             boolean didDexOptLibraryOrTool = false;
 
-            final List<String> instructionSets = getAllInstructionSets();
+            final List<String> allInstructionSets = getAllInstructionSets();
+            final String[] dexCodeInstructionSets =
+                getDexCodeInstructionSets(allInstructionSets.toArray(new String[allInstructionSets.size()]));
 
             /**
              * Ensure all external libraries have had dexopt run on them.
@@ -1412,7 +1414,7 @@
                 // (and framework jars) into all available architectures. It's possible
                 // to compile them only when we come across an app that uses them (there's
                 // already logic for that in scanPackageLI) but that adds some complexity.
-                for (String instructionSet : instructionSets) {
+                for (String dexCodeInstructionSet : dexCodeInstructionSets) {
                     for (SharedLibraryEntry libEntry : mSharedLibraries.values()) {
                         final String lib = libEntry.path;
                         if (lib == null) {
@@ -1421,16 +1423,16 @@
 
                         try {
                             byte dexoptRequired = DexFile.isDexOptNeededInternal(lib, null,
-                                                                                 instructionSet,
+                                                                                 dexCodeInstructionSet,
                                                                                  false);
                             if (dexoptRequired != DexFile.UP_TO_DATE) {
                                 alreadyDexOpted.add(lib);
 
                                 // The list of "shared libraries" we have at this point is
                                 if (dexoptRequired == DexFile.DEXOPT_NEEDED) {
-                                    mInstaller.dexopt(lib, Process.SYSTEM_UID, true, instructionSet);
+                                    mInstaller.dexopt(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet);
                                 } else {
-                                    mInstaller.patchoat(lib, Process.SYSTEM_UID, true, instructionSet);
+                                    mInstaller.patchoat(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet);
                                 }
                                 didDexOptLibraryOrTool = true;
                             }
@@ -1465,7 +1467,7 @@
                 // TODO: We could compile these only for the most preferred ABI. We should
                 // first double check that the dex files for these commands are not referenced
                 // by other system apps.
-                for (String instructionSet : instructionSets) {
+                for (String dexCodeInstructionSet : dexCodeInstructionSets) {
                     for (int i=0; i<frameworkFiles.length; i++) {
                         File libPath = new File(frameworkDir, frameworkFiles[i]);
                         String path = libPath.getPath();
@@ -1479,13 +1481,13 @@
                         }
                         try {
                             byte dexoptRequired = DexFile.isDexOptNeededInternal(path, null,
-                                                                                 instructionSet,
+                                                                                 dexCodeInstructionSet,
                                                                                  false);
                             if (dexoptRequired == DexFile.DEXOPT_NEEDED) {
-                                mInstaller.dexopt(path, Process.SYSTEM_UID, true, instructionSet);
+                                mInstaller.dexopt(path, Process.SYSTEM_UID, true, dexCodeInstructionSet);
                                 didDexOptLibraryOrTool = true;
                             } else if (dexoptRequired == DexFile.PATCHOAT_NEEDED) {
-                                mInstaller.patchoat(path, Process.SYSTEM_UID, true, instructionSet);
+                                mInstaller.patchoat(path, Process.SYSTEM_UID, true, dexCodeInstructionSet);
                                 didDexOptLibraryOrTool = true;
                             }
                         } catch (FileNotFoundException e) {
@@ -1509,8 +1511,8 @@
                 // small maintenance release update that the library and tool
                 // jars may be unchanged but APK could be removed resulting in
                 // unused dalvik-cache files.
-                for (String instructionSet : instructionSets) {
-                    mInstaller.pruneDexCache(instructionSet);
+                for (String dexCodeInstructionSet : dexCodeInstructionSets) {
+                    mInstaller.pruneDexCache(dexCodeInstructionSet);
                 }
 
                 // Additionally, delete all dex files from the root directory
@@ -4631,9 +4633,10 @@
         // 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
+        final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
         for (String path : paths) {
-            for (String instructionSet : instructionSets) {
-                if (!forceDex && pkg.mDexOptPerformed.contains(instructionSet)) {
+            for (String dexCodeInstructionSet : dexCodeInstructionSets) {
+                if (!forceDex && pkg.mDexOptPerformed.contains(dexCodeInstructionSet)) {
                     continue;
                 }
 
@@ -4644,13 +4647,13 @@
                     // odex file and it matches the checksum of the image but not its base address,
                     // meaning we need to move it.
                     final byte isDexOptNeeded = DexFile.isDexOptNeededInternal(path,
-                            pkg.packageName, instructionSet, defer);
+                            pkg.packageName, dexCodeInstructionSet, defer);
                     if (forceDex || (!defer && isDexOptNeeded == DexFile.DEXOPT_NEEDED)) {
                         Log.i(TAG, "Running dexopt on: " + path + " pkg="
-                                + pkg.applicationInfo.packageName + " isa=" + instructionSet);
+                                + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet);
                         final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
                         final int ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg),
-                                pkg.packageName, instructionSet);
+                                pkg.packageName, dexCodeInstructionSet);
 
                         if (ret < 0) {
                             // Don't bother running dexopt again if we failed, it will probably
@@ -4659,13 +4662,13 @@
                             return DEX_OPT_FAILED;
                         } else {
                             performedDexOpt = true;
-                            pkg.mDexOptPerformed.add(instructionSet);
+                            pkg.mDexOptPerformed.add(dexCodeInstructionSet);
                         }
                     } else if (!defer && isDexOptNeeded == DexFile.PATCHOAT_NEEDED) {
                         Log.i(TAG, "Running patchoat on: " + pkg.applicationInfo.packageName);
                         final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
                         final int ret = mInstaller.patchoat(path, sharedGid, !isForwardLocked(pkg),
-                                pkg.packageName, instructionSet);
+                                pkg.packageName, dexCodeInstructionSet);
 
                         if (ret < 0) {
                             // Don't bother running patchoat again if we failed, it will probably
@@ -4674,7 +4677,7 @@
                             return DEX_OPT_FAILED;
                         } else {
                             performedDexOpt = true;
-                            pkg.mDexOptPerformed.add(instructionSet);
+                            pkg.mDexOptPerformed.add(dexCodeInstructionSet);
                         }
                     }
 
@@ -4763,6 +4766,23 @@
         return allInstructionSets;
     }
 
+    /**
+     * Returns the instruction set that should be used to compile dex code. In the presence of
+     * a native bridge this might be different than the one shared libraries use.
+     */
+    private static String getDexCodeInstructionSet(String sharedLibraryIsa) {
+        String dexCodeIsa = SystemProperties.get("ro.dalvik.vm.isa." + sharedLibraryIsa);
+        return (dexCodeIsa.isEmpty() ? sharedLibraryIsa : dexCodeIsa);
+    }
+
+    private static String[] getDexCodeInstructionSets(String[] instructionSets) {
+        HashSet<String> dexCodeInstructionSets = new HashSet<String>(instructionSets.length);
+        for (String instructionSet : instructionSets) {
+            dexCodeInstructionSets.add(getDexCodeInstructionSet(instructionSet));
+        }
+        return dexCodeInstructionSets.toArray(new String[dexCodeInstructionSets.size()]);
+    }
+
     @Override
     public void forceDexOpt(String packageName) {
         enforceSystemOrRoot("forceDexOpt");
@@ -6182,7 +6202,8 @@
                             ps.pkg.applicationInfo.primaryCpuAbi = null;
                             return;
                         } else {
-                            mInstaller.rmdex(ps.codePathString, getPreferredInstructionSet());
+                            mInstaller.rmdex(ps.codePathString,
+                                             getDexCodeInstructionSet(getPreferredInstructionSet()));
                         }
                     }
                 }
@@ -9411,10 +9432,10 @@
                 if (instructionSets == null) {
                     throw new IllegalStateException("instructionSet == null");
                 }
-
+                String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
                 for (String codePath : allCodePaths) {
-                    for (String instructionSet : instructionSets) {
-                        int retCode = mInstaller.rmdex(codePath, instructionSet);
+                    for (String dexCodeInstructionSet : dexCodeInstructionSets) {
+                        int retCode = mInstaller.rmdex(codePath, dexCodeInstructionSet);
                         if (retCode < 0) {
                             Slog.w(TAG, "Couldn't remove dex file for package: "
                                     + " at location " + codePath + ", retcode=" + retCode);
@@ -9694,8 +9715,9 @@
             if (instructionSets == null) {
                 throw new IllegalStateException("instructionSet == null");
             }
-            for (String instructionSet : instructionSets) {
-                int retCode = mInstaller.rmdex(sourceFile, instructionSet);
+            String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
+            for (String dexCodeInstructionSet : dexCodeInstructionSets) {
+                int retCode = mInstaller.rmdex(sourceFile, dexCodeInstructionSet);
                 if (retCode < 0) {
                     Slog.w(TAG, "Couldn't remove dex file for package: "
                             + " at location "
@@ -10198,9 +10220,10 @@
         // TODO: extend to move split APK dex files
         if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
             final String[] instructionSets = getAppDexInstructionSets(newPackage.applicationInfo);
-            for (String instructionSet : instructionSets) {
+            String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
+            for (String dexCodeInstructionSet : dexCodeInstructionSets) {
                 int retCode = mInstaller.movedex(oldCodePath, newPackage.baseCodePath,
-                        instructionSet);
+                        dexCodeInstructionSet);
                 if (retCode != 0) {
                 /*
                  * Programs may be lazily run through dexopt, so the
@@ -10211,8 +10234,8 @@
                  * file from a previous version of the package.
                  */
                     newPackage.mDexOptPerformed.clear();
-                    mInstaller.rmdex(oldCodePath, instructionSet);
-                    mInstaller.rmdex(newPackage.baseCodePath, instructionSet);
+                    mInstaller.rmdex(oldCodePath, dexCodeInstructionSet);
+                    mInstaller.rmdex(newPackage.baseCodePath, dexCodeInstructionSet);
                 }
             }
         }
@@ -11359,9 +11382,9 @@
         // not just the first level.
         // TODO(multiArch): Extend getSizeInfo to look at *all* instruction sets, not
         // just the primary.
+        String[] dexCodeInstructionSets = getDexCodeInstructionSets(getAppDexInstructionSets(ps));
         int res = mInstaller.getSizeInfo(packageName, userHandle, p.baseCodePath, libDirRoot,
-                publicSrcDir, asecPath, getAppDexInstructionSets(ps),
-                pStats);
+                publicSrcDir, asecPath, dexCodeInstructionSets, pStats);
         if (res < 0) {
             return false;
         }