in src/com/facebook/buck/android/dalvik/DalvikAwareZipSplitter.java [168:305]
public ImmutableMultimap<APKModule, Path> execute() throws IOException {
ClasspathTraverser classpathTraverser = new DefaultClasspathTraverser();
Set<String> secondaryTail = new HashSet<String>();
// Start out by writing the primary zip and recording which entries were added to it.
primaryOut = newZipOutput(outPrimary);
secondaryDexWriter.reset();
ImmutableMap.Builder<String, FileLike> entriesBuilder = ImmutableMap.builder();
List<String> additionalDexStoreEntries = new ArrayList<>();
// Iterate over all of the inFiles and add all entries that match the requiredInPrimaryZip
// predicate.
LOG.verbose("Traversing classpath for primary zip");
classpathTraverser.traverse(
new ClasspathTraversal(inFiles, filesystem) {
@Override
public void visit(FileLike entry) throws IOException {
LOG.verbose("Visiting " + entry.getRelativePath());
String relativePath = entry.getRelativePath();
if (!relativePath.endsWith(".class")) {
// We don't need resources in dex jars, so just drop them.
return;
}
String classPath = relativePath.replaceAll("\\.class$", "");
Objects.requireNonNull(primaryOut);
Objects.requireNonNull(classPathToDexStore);
if (requiredInPrimaryZip.test(relativePath)) {
primaryOut.putEntry(entry);
} else if (wantedInPrimaryZip.contains(relativePath)
|| (secondaryHeadSet != null && secondaryHeadSet.contains(relativePath))) {
entriesBuilder.put(relativePath, new BufferedFileLike(entry));
} else if (secondaryTailSet != null && secondaryTailSet.contains(relativePath)) {
entriesBuilder.put(relativePath, new BufferedFileLike(entry));
secondaryTail.add(relativePath);
} else {
ImmutableCollection<APKModule> containingModule = classPathToDexStore.get(classPath);
if (!containingModule.isEmpty()) {
if (containingModule.size() > 1) {
throw new IllegalStateException(
String.format(
"classpath %s is contained in multiple dex stores: %s",
classPath, classPathToDexStore.get(classPath).asList().toString()));
}
APKModule dexStore = containingModule.iterator().next();
if (!dexStore.equals(rootModule)) {
MySecondaryDexHelper dexHelper = additionalDexWriters.get(dexStore);
Objects.requireNonNull(dexHelper);
dexHelper.getOutputToWriteTo(entry).putEntry(entry);
additionalDexStoreEntries.add(relativePath);
}
}
}
}
});
// Put as many of the items wanted in the primary dex as we can into the primary dex.
ImmutableMap<String, FileLike> entries = entriesBuilder.build();
for (String wanted : wantedInPrimaryZip) {
FileLike entry = entries.get(wanted);
if ((entry != null) && !primaryOut.containsEntry(entry) && primaryOut.canPutEntry(entry)) {
primaryOut.putEntry(entry);
}
}
if (secondaryHeadSet != null) {
for (String head : secondaryHeadSet) {
FileLike headEntry = entries.get(head);
if ((headEntry != null) && !primaryOut.containsEntry(headEntry)) {
secondaryDexWriter.getOutputToWriteTo(headEntry).putEntry(headEntry);
}
}
}
LOG.verbose("Traversing classpath for secondary zip");
// Now that all of the required entries have been added to the primary zip, fill the rest of
// the zip up with the remaining entries.
classpathTraverser.traverse(
new ClasspathTraversal(inFiles, filesystem) {
@Override
public void visit(FileLike entry) throws IOException {
Objects.requireNonNull(primaryOut);
String relativePath = entry.getRelativePath();
// skip if it is the primary dex, is part of a modular dex store, or is not a class file
if (primaryOut.containsEntry(entry)
|| additionalDexStoreEntries.contains(relativePath)) {
return;
}
LOG.verbose("Visiting " + entry.getRelativePath());
// Even if we have started writing a secondary dex, we still check if there is any
// leftover
// room in the primary dex for the current entry in the traversal.
if (dexSplitStrategy == DexSplitStrategy.MAXIMIZE_PRIMARY_DEX_SIZE
&& primaryOut.canPutEntry(entry)) {
primaryOut.putEntry(entry);
} else {
if (secondaryHeadSet != null && secondaryHeadSet.contains(relativePath)) {
return;
}
if (secondaryTail.contains(relativePath)) {
return;
}
secondaryDexWriter.getOutputToWriteTo(entry).putEntry(entry);
}
}
});
if (secondaryTailSet != null) {
for (String tail : secondaryTailSet) {
FileLike tailEntry = entries.get(tail);
if ((tailEntry != null)
&& !primaryOut.containsEntry(tailEntry)
&& secondaryTail.contains(tail)) {
secondaryDexWriter.getOutputToWriteTo(tailEntry).putEntry(tailEntry);
}
}
}
primaryOut.close();
secondaryDexWriter.close();
ImmutableMultimap.Builder<APKModule, Path> outputFilesBuilder = ImmutableMultimap.builder();
APKModule secondaryDexStore = rootModule;
outputFilesBuilder.putAll(secondaryDexStore, secondaryDexWriter.getFiles());
for (Map.Entry<APKModule, MySecondaryDexHelper> entry : additionalDexWriters.entrySet()) {
if (!entry.getKey().equals(secondaryDexStore)) {
entry.getValue().close();
outputFilesBuilder.putAll(entry.getKey(), entry.getValue().getFiles());
}
}
return outputFilesBuilder.build();
}