Merge "Gather shared libs for split apks based on dependencies."

This commit is contained in:
TreeHugger Robot
2017-04-24 17:26:53 +00:00
committed by Android (Google) Code Review

View File

@@ -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;
@@ -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.