// Not safe to execute multiple times. @Override public Collection<File> execute() throws IOException { ClasspathTraverser classpathTraverser = new DefaultClasspathTraverser(); // Compute the total size of the inputs so that we can figure out whether its safe // to begin putting non-essential entries into the primary zip. // TODO(devjasta): There's a more compact way of doing this by writing the primary zip during // this first-pass step then assigning it as the "currentSecondaryOut" to complete the second // pass. We're already tracking unique entries so we would not end up adding those primary // entries twice. classpathTraverser.traverse( new ClasspathTraversal(inFiles) { @Override public void visit(FileLike entry) { long entrySize = entry.getSize(); if (entrySize > 0) { remainingSize += entrySize; } } }); primaryOut = newZipOutput(outPrimary); secondaryDexWriter.reset(); try { for (File inFile : inFiles) { classpathTraverser.traverse( new ClasspathTraversal(ImmutableSet.of(inFile)) { @Override public void visit(FileLike entry) throws IOException { processEntry(entry); } }); // The soft limit was tripped (and not the hard limit). Flag that the next non-zero length // entry should create a new zip. DefaultZipOutputStreamHelper currentSecondaryOut = secondaryDexWriter.getCurrentOutput(); if (currentSecondaryOut != null && currentSecondaryOut.getCurrentSize() >= zipSizeSoftLimit) { secondaryDexWriter.finishCurrentZipFile(); } } } finally { primaryOut.close(); secondaryDexWriter.close(); } return secondaryDexWriter.getFiles(); }
private void processEntry(FileLike entry) throws IOException { long entrySize = entry.getSize(); if (entrySize <= 0) { return; } if (entrySize > zipSizeHardLimit) { throw new IllegalArgumentException("Single entry larger than limit: " + entry); } DefaultZipOutputStreamHelper targetOut; // An entry is placed in the primary zip if either of the following is true: // // (1) The entry must appear in the first zip according to the EntryProcessor predicate. // (2) All of the remaining zip entries fit in the remaining space in the primary zip and // we're trying to maximize the size of the primary zip. // // Otherwise, the entry will be added to the secondary zip. boolean canFitAllRemaining = remainingSize + primaryOut.getCurrentSize() <= zipSizeHardLimit; if ((canFitAllRemaining && dexSplitStrategy == ZipSplitter.DexSplitStrategy.MAXIMIZE_PRIMARY_DEX_SIZE) || requiredInPrimaryZip.apply(entry.getRelativePath()) // File must be in primary ) { // Going to write this entry to the primary zip. if (!primaryOut.canPutEntry(entry)) { throw new IllegalArgumentException("Unable to fit all required files in primary zip."); } targetOut = primaryOut; } else { targetOut = secondaryDexWriter.getOutputToWriteTo(entry); } targetOut.putEntry(entry); remainingSize -= entrySize; }