summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/pm/PackageDexOptimizer.java108
1 files changed, 85 insertions, 23 deletions
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 8413491aaef8..254bc2ac0e8b 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -28,6 +28,7 @@ import android.os.UserHandle;
import android.os.WorkSource;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
@@ -141,7 +142,7 @@ public class PackageDexOptimizer {
final String[] instructionSets = targetInstructionSets != null ?
targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
- final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
+ final List<String> paths = pkg.getAllCodePaths();
final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
final String compilerFilter = getRealCompilerFilter(pkg.applicationInfo,
@@ -149,18 +150,32 @@ public class PackageDexOptimizer {
final boolean profileUpdated = checkForProfileUpdates &&
isProfileUpdated(pkg, sharedGid, compilerFilter);
- String sharedLibrariesPath = getSharedLibrariesPath(sharedLibraries);
+ final String sharedLibrariesPath = getSharedLibrariesPath(sharedLibraries);
// Get the dexopt flags after getRealCompilerFilter to make sure we get the correct flags.
final int dexoptFlags = getDexFlags(pkg, compilerFilter);
+ // Get the dependencies of each split in the package. For each code path in the package,
+ // this array contains the relative paths of each split it depends on, separated by colons.
+ String[] splitDependencies = getSplitDependencies(pkg);
int result = DEX_OPT_SKIPPED;
- // TODO: Iterate based on dependency hierarchy (currently alphabetically by name)
- // (b/37480811).
- String basePathCheck = null;
- for (String path : paths) {
+ for (int i = 0; i < paths.size(); i++) {
+ // Skip paths that have no code.
+ if ((i == 0 && (pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) == 0) ||
+ (i != 0 && (pkg.splitFlags[i - 1] & ApplicationInfo.FLAG_HAS_CODE) == 0)) {
+ continue;
+ }
+ // Append shared libraries with split dependencies for this split.
+ String path = paths.get(i);
+ String sharedLibrariesPathWithSplits;
+ if (sharedLibrariesPath != null && splitDependencies[i] != null) {
+ sharedLibrariesPathWithSplits = sharedLibrariesPath + ":" + splitDependencies[i];
+ } else {
+ sharedLibrariesPathWithSplits =
+ splitDependencies[i] != null ? splitDependencies[i] : sharedLibrariesPath;
+ }
for (String dexCodeIsa : dexCodeInstructionSets) {
int newResult = dexOptPath(pkg, path, dexCodeIsa, compilerFilter, profileUpdated,
- sharedLibrariesPath, dexoptFlags, sharedGid, packageStats);
+ sharedLibrariesPathWithSplits, dexoptFlags, sharedGid, packageStats);
// The end result is:
// - FAILED if any path failed,
// - PERFORMED if at least one path needed compilation,
@@ -168,22 +183,6 @@ public class PackageDexOptimizer {
if ((result != DEX_OPT_FAILED) && (newResult != DEX_OPT_SKIPPED)) {
result = newResult;
}
- // Add the relative path of code we just compiled to the shared libraries.
- int slashIndex = path.lastIndexOf('/') + 1;
- String relativePath = path.substring(slashIndex);
- if (sharedLibrariesPath == null) {
- sharedLibrariesPath = relativePath;
- } else {
- sharedLibrariesPath += ":" + relativePath;
- }
- // Sanity check that the base paths are all the same.
- String basePath = path.substring(0, slashIndex);
- if (basePathCheck == null) {
- basePathCheck = basePath;
- } else if (!basePath.equals(basePathCheck)) {
- Slog.wtf(TAG, "Split paths have different base paths: " + basePath + " and " +
- basePathCheck);
- }
}
}
return result;
@@ -437,6 +436,69 @@ public class PackageDexOptimizer {
}
/**
+ * Walks dependency tree and gathers the dependencies for each split in a split apk.
+ * The split paths are stored as relative paths, separated by colons.
+ */
+ private String[] getSplitDependencies(PackageParser.Package pkg) {
+ // Convert all the code paths to relative paths.
+ String baseCodePath = new File(pkg.baseCodePath).getParent();
+ List<String> paths = pkg.getAllCodePaths();
+ String[] splitDependencies = new String[paths.size()];
+ for (int i = 0; i < paths.size(); i++) {
+ File pathFile = new File(paths.get(i));
+ String fileName = pathFile.getName();
+ paths.set(i, fileName);
+
+ // Sanity check that the base paths of the splits are all the same.
+ String basePath = pathFile.getParent();
+ if (!basePath.equals(baseCodePath)) {
+ Slog.wtf(TAG, "Split paths have different base paths: " + basePath + " and " +
+ baseCodePath);
+ }
+ }
+
+ // If there are no other dependencies, fill in the implicit dependency on the base apk.
+ SparseArray<int[]> dependencies = pkg.applicationInfo.splitDependencies;
+ if (dependencies == null) {
+ for (int i = 1; i < paths.size(); i++) {
+ splitDependencies[i] = paths.get(0);
+ }
+ return splitDependencies;
+ }
+
+ // Fill in the dependencies, skipping the base apk which has no dependencies.
+ for (int i = 1; i < dependencies.size(); i++) {
+ getParentDependencies(dependencies.keyAt(i), paths, dependencies, splitDependencies);
+ }
+
+ return splitDependencies;
+ }
+
+ /**
+ * Recursive method to generate dependencies for a particular split.
+ * The index is a key from the package's splitDependencies.
+ */
+ private String getParentDependencies(int index, List<String> paths,
+ SparseArray<int[]> dependencies, String[] splitDependencies) {
+ // The base apk is always first, and has no dependencies.
+ if (index == 0) {
+ return null;
+ }
+ // Return the result if we've computed the dependencies for this index already.
+ if (splitDependencies[index] != null) {
+ return splitDependencies[index];
+ }
+ // Get the dependencies for the parent of this index and append its path to it.
+ int parent = dependencies.get(index)[0];
+ String parentDependencies =
+ getParentDependencies(parent, paths, dependencies, splitDependencies);
+ String path = parentDependencies == null ? paths.get(parent) :
+ parentDependencies + ":" + paths.get(parent);
+ splitDependencies[index] = path;
+ return path;
+ }
+
+ /**
* Checks if there is an update on the profile information of the {@code pkg}.
* If the compiler filter is not profile guided the method returns false.
*