Support to pass <uses-library> option through to dex2oat.

This change takes an app's shared libraries specified by <uses-library>
and passes it through to dex2oat to be used during compilation.

Part of a multi-project change.

Bug: 26880306

(cherry-picked from 7b331b6a8ae8d9f10482b292439457de98abd32a)

Change-Id: I523b1b74775e7ed27072498509e743f1f10b1164
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 3050ac8..bb2cc95 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -356,14 +356,18 @@
             if (instrumentationSplitAppDirs != null) {
                 Collections.addAll(outZipPaths, instrumentationSplitAppDirs);
             }
-            outZipPaths.add(instrumentedAppDir);
-            if (instrumentedSplitAppDirs != null) {
-                Collections.addAll(outZipPaths, instrumentedSplitAppDirs);
+            if (!instrumentationAppDir.equals(instrumentedAppDir)) {
+                outZipPaths.add(instrumentedAppDir);
+                if (instrumentedSplitAppDirs != null) {
+                    Collections.addAll(outZipPaths, instrumentedSplitAppDirs);
+                }
             }
 
             if (outLibPaths != null) {
                 outLibPaths.add(instrumentationLibDir);
-                outLibPaths.add(instrumentedLibDir);
+                if (!instrumentationLibDir.equals(instrumentedLibDir)) {
+                    outLibPaths.add(instrumentedLibDir);
+                }
             }
 
             if (!instrumentedAppDir.equals(instrumentationAppDir)) {
diff --git a/core/java/com/android/internal/os/InstallerConnection.java b/core/java/com/android/internal/os/InstallerConnection.java
index 47f2c70..a7a3cb5 100644
--- a/core/java/com/android/internal/os/InstallerConnection.java
+++ b/core/java/com/android/internal/os/InstallerConnection.java
@@ -135,14 +135,15 @@
     }
 
     public void dexopt(String apkPath, int uid, String instructionSet, int dexoptNeeded,
-            int dexFlags, String compilerFilter, String volumeUuid) throws InstallerException {
-        dexopt(apkPath, uid, "*", instructionSet, dexoptNeeded,
-                null /*outputPath*/, dexFlags, compilerFilter, volumeUuid);
+            int dexFlags, String compilerFilter, String volumeUuid, String sharedLibraries)
+            throws InstallerException {
+        dexopt(apkPath, uid, "*", instructionSet, dexoptNeeded, null /*outputPath*/, dexFlags,
+                compilerFilter, volumeUuid, sharedLibraries);
     }
 
     public void dexopt(String apkPath, int uid, String pkgName, String instructionSet,
             int dexoptNeeded, String outputPath, int dexFlags, String compilerFilter,
-            String volumeUuid) throws InstallerException {
+            String volumeUuid, String sharedLibraries) throws InstallerException {
         execute("dexopt",
                 apkPath,
                 uid,
@@ -152,7 +153,8 @@
                 outputPath,
                 dexFlags,
                 compilerFilter,
-                volumeUuid);
+                volumeUuid,
+                sharedLibraries);
     }
 
     public boolean mergeProfiles(int uid, String pkgName) throws InstallerException {
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 78b5d61..9c09782 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -499,6 +499,7 @@
         final String instructionSet = VMRuntime.getRuntime().vmInstructionSet();
 
         try {
+            String sharedLibraries = "";
             for (String classPathElement : classPathElements) {
                 // System server is fully AOTed and never profiled
                 // for profile guided compilation.
@@ -508,9 +509,13 @@
                         false /* newProfile */);
                 if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
                     installer.dexopt(classPathElement, Process.SYSTEM_UID, instructionSet,
-                            dexoptNeeded, 0 /*dexFlags*/, "speed",
-                            null /*volumeUuid*/);
+                            dexoptNeeded, 0 /*dexFlags*/, "speed", null /*volumeUuid*/,
+                            sharedLibraries);
                 }
+                if (!sharedLibraries.isEmpty()) {
+                    sharedLibraries += ":";
+                }
+                sharedLibraries += classPathElement;
             }
         } catch (IOException | InstallerException e) {
             throw new RuntimeException("Error starting system_server", e);
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 66c1a53..913c824 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -133,19 +133,20 @@
     }
 
     public void dexopt(String apkPath, int uid, String instructionSet, int dexoptNeeded,
-            int dexFlags, String compilerFilter, String volumeUuid) throws InstallerException {
+            int dexFlags, String compilerFilter, String volumeUuid, String sharedLibraries)
+            throws InstallerException {
         assertValidInstructionSet(instructionSet);
         mInstaller.dexopt(apkPath, uid, instructionSet, dexoptNeeded, dexFlags,
-                compilerFilter, volumeUuid);
+                compilerFilter, volumeUuid, sharedLibraries);
     }
 
     public void dexopt(String apkPath, int uid, String pkgName, String instructionSet,
             int dexoptNeeded, @Nullable String outputPath, int dexFlags,
-            String compilerFilter, String volumeUuid)
-                    throws InstallerException {
+            String compilerFilter, String volumeUuid, String sharedLibraries)
+            throws InstallerException {
         assertValidInstructionSet(instructionSet);
         mInstaller.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded,
-                outputPath, dexFlags, compilerFilter, volumeUuid);
+                outputPath, dexFlags, compilerFilter, volumeUuid, sharedLibraries);
     }
 
     public boolean mergeProfiles(int uid, String pkgName) throws InstallerException {
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index c3a9226..50b8670 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -22,7 +22,9 @@
 import static com.android.server.pm.PackageManagerServiceCompilerMapping.getCompilerFilterForReason;
 
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.IOtaDexopt;
+import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
 import android.os.Environment;
 import android.os.RemoteException;
@@ -142,7 +144,8 @@
             return;
         }
 
-        mPackageDexOptimizer.performDexOpt(nextPackage, null /* ISAs */, false /* useProfiles */,
+        mPackageDexOptimizer.performDexOpt(nextPackage, nextPackage.usesLibraryFiles,
+                null /* ISAs */, false /* checkProfiles */,
                 getCompilerFilterForReason(PackageManagerService.REASON_AB_OTA));
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index f620274..f134e40 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -88,8 +88,8 @@
      * <p>Calls to {@link com.android.server.pm.Installer#dexopt} on {@link #mInstaller} are
      * synchronized on {@link #mInstallLock}.
      */
-    int performDexOpt(PackageParser.Package pkg, String[] instructionSets, boolean checkProfiles,
-            String targetCompilationFilter) {
+    int performDexOpt(PackageParser.Package pkg, String[] sharedLibraries,
+            String[] instructionSets, boolean checkProfiles, String targetCompilationFilter) {
         synchronized (mInstallLock) {
             final boolean useLock = mSystemReady;
             if (useLock) {
@@ -97,7 +97,7 @@
                 mDexoptWakeLock.acquire();
             }
             try {
-                return performDexOptLI(pkg, instructionSets, checkProfiles,
+                return performDexOptLI(pkg, sharedLibraries, instructionSets, checkProfiles,
                         targetCompilationFilter);
             } finally {
                 if (useLock) {
@@ -122,8 +122,8 @@
         return dexoptFlags;
     }
 
-    private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets,
-            boolean checkProfiles, String targetCompilerFilter) {
+    private int performDexOptLI(PackageParser.Package pkg, String[] sharedLibraries,
+            String[] targetInstructionSets, boolean checkProfiles, String targetCompilerFilter) {
         final String[] instructionSets = targetInstructionSets != null ?
                 targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
 
@@ -200,10 +200,22 @@
                         throw new IllegalStateException("Invalid dexopt:" + dexoptNeeded);
                 }
 
+                String sharedLibrariesPath = null;
+                if (sharedLibraries != null && sharedLibraries.length != 0) {
+                    StringBuilder sb = new StringBuilder();
+                    for (String lib : sharedLibraries) {
+                        if (sb.length() != 0) {
+                            sb.append(":");
+                        }
+                        sb.append(lib);
+                    }
+                    sharedLibrariesPath = sb.toString();
+                }
                 Log.i(TAG, "Running dexopt (" + dexoptType + ") on: " + path + " pkg="
                         + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
                         + " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable
-                        + " target-filter=" + targetCompilerFilter + " oatDir = " + oatDir);
+                        + " target-filter=" + targetCompilerFilter + " oatDir = " + oatDir
+                        + " sharedLibraries=" + sharedLibrariesPath);
                 // Profile guide compiled oat files should not be public.
                 final boolean isPublic = !pkg.isForwardLocked() && !isProfileGuidedFilter;
                 final int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0;
@@ -216,7 +228,8 @@
 
                 try {
                     mInstaller.dexopt(path, sharedGid, pkg.packageName, dexCodeInstructionSet,
-                            dexoptNeeded, oatDir, dexFlags, targetCompilerFilter, pkg.volumeUuid);
+                            dexoptNeeded, oatDir, dexFlags, targetCompilerFilter, pkg.volumeUuid,
+                            sharedLibrariesPath);
                     performedDexOpt = true;
                 } catch (InstallerException e) {
                     Slog.w(TAG, "Failed to dexopt", e);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a128877..4b0eeed 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -498,6 +498,9 @@
 
     public static final int REASON_LAST = REASON_FORCED_DEXOPT;
 
+    // Special String to skip shared libraries check during compilation.
+    private static final String SPECIAL_SHARED_LIBRARY = "&";
+
     final ServiceThread mHandlerThread;
 
     final PackageHandler mHandler;
@@ -2332,7 +2335,8 @@
                                 mInstaller.dexopt(lib, Process.SYSTEM_UID, dexCodeInstructionSet,
                                         dexoptNeeded, DEXOPT_PUBLIC /*dexFlags*/,
                                         getCompilerFilterForReason(REASON_SHARED_APK),
-                                        StorageManager.UUID_PRIVATE_INTERNAL);
+                                        StorageManager.UUID_PRIVATE_INTERNAL,
+                                        SPECIAL_SHARED_LIBRARY);
                             }
                         } catch (FileNotFoundException e) {
                             Slog.w(TAG, "Library not found: " + lib);
@@ -7298,12 +7302,14 @@
             for (PackageParser.Package depPackage : deps) {
                 // TODO: Analyze and investigate if we (should) profile libraries.
                 // Currently this will do a full compilation of the library by default.
-                pdo.performDexOpt(depPackage, instructionSets, false /* checkProfiles */,
+                pdo.performDexOpt(depPackage, null /* sharedLibraries */, instructionSets,
+                        false /* checkProfiles */,
                         getCompilerFilterForReason(REASON_NON_SYSTEM_LIBRARY));
             }
         }
 
-        return pdo.performDexOpt(p, instructionSets, checkProfiles, targetCompilerFilter);
+        return pdo.performDexOpt(p, p.usesLibraryFiles, instructionSets, checkProfiles,
+                targetCompilerFilter);
     }
 
     Collection<PackageParser.Package> findSharedNonSystemLibraries(PackageParser.Package p) {
@@ -14709,11 +14715,20 @@
                 return;
             }
 
+            // Shared libraries for the package need to be updated.
+            synchronized (mPackages) {
+                try {
+                    updateSharedLibrariesLPw(pkg, null);
+                } catch (PackageManagerException e) {
+                    Slog.e(TAG, "updateSharedLibrariesLPw failed: " + e.getMessage());
+                }
+            }
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
             // Do not run PackageDexOptimizer through the local performDexOpt
             // method because `pkg` is not in `mPackages` yet.
-            int result = mPackageDexOptimizer.performDexOpt(pkg, null /* instructionSets */,
-                    false /* checkProfiles */, getCompilerFilterForReason(REASON_INSTALL));
+            int result = mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
+                    null /* instructionSets */, false /* checkProfiles */,
+                    getCompilerFilterForReason(REASON_INSTALL));
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
             if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
                 String msg = "Extracting package failed for " + pkgName;