Merge "Remove SignApk output limitation of 2GiB" into main
diff --git a/tools/signapk/src/com/android/signapk/SignApk.java b/tools/signapk/src/com/android/signapk/SignApk.java
index 6a9a5d3..6b2341b 100644
--- a/tools/signapk/src/com/android/signapk/SignApk.java
+++ b/tools/signapk/src/com/android/signapk/SignApk.java
@@ -987,6 +987,9 @@
private static class ZipSections {
DataSource beforeCentralDir;
+
+ // The following fields are still valid after closing the backing DataSource.
+ long beforeCentralDirSize;
ByteBuffer centralDir;
ByteBuffer eocd;
}
@@ -1006,7 +1009,9 @@
}
ZipSections result = new ZipSections();
+
result.beforeCentralDir = apk.slice(0, centralDirStartOffset);
+ result.beforeCentralDirSize = result.beforeCentralDir.size();
long centralDirSize = centralDirEndOffset - centralDirStartOffset;
if (centralDirSize >= Integer.MAX_VALUE) throw new IndexOutOfBoundsException();
@@ -1270,11 +1275,8 @@
// signatures)
apkSigner.inputApkSigningBlock(null);
- // Build the output APK in memory, by copying input APK's ZIP entries across
- // and then signing the output APK.
- ByteArrayOutputStream v1SignedApkBuf = new ByteArrayOutputStream();
CountingOutputStream outputJarCounter =
- new CountingOutputStream(v1SignedApkBuf);
+ new CountingOutputStream(outputFile);
JarOutputStream outputJar = new JarOutputStream(outputJarCounter);
// Use maximum compression for compressed entries because the APK lives forever
// on the system partition.
@@ -1287,10 +1289,13 @@
addV1Signature(apkSigner, addV1SignatureRequest, outputJar, timestamp);
addV1SignatureRequest.done();
}
+
+ // close output and switch to input mode
outputJar.close();
- ByteBuffer v1SignedApk = ByteBuffer.wrap(v1SignedApkBuf.toByteArray());
- v1SignedApkBuf.reset();
- ByteBuffer[] outputChunks = new ByteBuffer[] {v1SignedApk};
+ outputJar = null;
+ outputJarCounter = null;
+ outputFile = null;
+ RandomAccessFile v1SignedApk = new RandomAccessFile(outputFilename, "r");
ZipSections zipSections = findMainZipSections(DataSources.asDataSource(
v1SignedApk));
@@ -1299,6 +1304,9 @@
eocd.put(zipSections.eocd);
eocd.flip();
eocd.order(ByteOrder.LITTLE_ENDIAN);
+
+ ByteBuffer[] outputChunks = new ByteBuffer[] {};
+
// This loop is supposed to be iterated twice at most.
// The second pass is to align the file size after amending EOCD comments
// with assumption that re-generated signing block would be the same size.
@@ -1325,13 +1333,8 @@
modifiedEocd,
zipSections.beforeCentralDir.size() + padding +
apkSigningBlock.length);
- if (zipSections.beforeCentralDir.size() >= Integer.MAX_VALUE) {
- throw new IndexOutOfBoundsException();
- }
outputChunks =
new ByteBuffer[] {
- zipSections.beforeCentralDir.getByteBuffer(0,
- (int)zipSections.beforeCentralDir.size()),
ByteBuffer.allocate(padding),
ByteBuffer.wrap(apkSigningBlock),
zipSections.centralDir,
@@ -1345,7 +1348,7 @@
// Calculate the file size
eocd = modifiedEocd;
- int fileSize = 0;
+ long fileSize = zipSections.beforeCentralDirSize;
for (ByteBuffer buf : outputChunks) {
fileSize += buf.remaining();
}
@@ -1354,7 +1357,7 @@
break;
}
// Pad EOCD comment to align the file size.
- int commentLen = alignment - fileSize % alignment;
+ int commentLen = alignment - (int)(fileSize % alignment);
modifiedEocd = ByteBuffer.allocate(eocd.remaining() + commentLen);
modifiedEocd.put(eocd);
modifiedEocd.rewind();
@@ -1365,6 +1368,12 @@
eocd = modifiedEocd;
}
+ // close input and switch back to output mode
+ v1SignedApk.close();
+ v1SignedApk = null;
+ outputFile = new FileOutputStream(outputFilename, true);
+ outputFile.getChannel().truncate(zipSections.beforeCentralDirSize);
+
// This assumes outputChunks are array-backed. To avoid this assumption, the
// code could be rewritten to use FileChannel.
for (ByteBuffer outputChunk : outputChunks) {