Loading services/core/java/com/android/server/pm/PackageDexOptimizer.java +85 −23 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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, Loading @@ -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, Loading @@ -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; Loading Loading @@ -436,6 +435,69 @@ public class PackageDexOptimizer { return sb.toString(); } /** * 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. Loading Loading
services/core/java/com/android/server/pm/PackageDexOptimizer.java +85 −23 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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, Loading @@ -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, Loading @@ -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; Loading Loading @@ -436,6 +435,69 @@ public class PackageDexOptimizer { return sb.toString(); } /** * 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. Loading