Merge "Remove SignApk output limitation of 2GiB" into main am: 605346e5c8

Original change: https://android-review.googlesource.com/c/platform/build/+/3001144

Change-Id: Icd506dcc05860338b034d8ce1a289c3147ce8b92
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Treehugger Robot
2024-03-15 02:46:17 +00:00
committed by Automerger Merge Worker

View File

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