Merge "make SignApk do zip alignment"

This commit is contained in:
Doug Zongker 2014-05-16 15:56:37 +00:00 committed by Gerrit Code Review
commit c0f10644bf
1 changed files with 66 additions and 10 deletions

View File

@ -461,24 +461,75 @@ class SignApk {
* reduce variation in the output file and make incremental OTAs * reduce variation in the output file and make incremental OTAs
* more efficient. * more efficient.
*/ */
private static void copyFiles(Manifest manifest, private static void copyFiles(Manifest manifest, JarFile in, JarOutputStream out,
JarFile in, JarOutputStream out, long timestamp) throws IOException { long timestamp, int alignment) throws IOException {
byte[] buffer = new byte[4096]; byte[] buffer = new byte[4096];
int num; int num;
Map<String, Attributes> entries = manifest.getEntries(); Map<String, Attributes> entries = manifest.getEntries();
ArrayList<String> names = new ArrayList<String>(entries.keySet()); ArrayList<String> names = new ArrayList<String>(entries.keySet());
Collections.sort(names); Collections.sort(names);
boolean firstEntry = true;
long offset = 0L;
// We do the copy in two passes -- first copying all the
// entries that are STORED, then copying all the entries that
// have any other compression flag (which in practice means
// DEFLATED). This groups all the stored entries together at
// the start of the file and makes it easier to do alignment
// on them (since only stored entries are aligned).
for (String name : names) { for (String name : names) {
JarEntry inEntry = in.getJarEntry(name); JarEntry inEntry = in.getJarEntry(name);
JarEntry outEntry = null; JarEntry outEntry = null;
if (inEntry.getMethod() == JarEntry.STORED) { if (inEntry.getMethod() != JarEntry.STORED) continue;
// Preserve the STORED method of the input entry. // Preserve the STORED method of the input entry.
outEntry = new JarEntry(inEntry); outEntry = new JarEntry(inEntry);
} else { outEntry.setTime(timestamp);
// Create a new entry so that the compressed len is recomputed.
outEntry = new JarEntry(name); // 'offset' is the offset into the file at which we expect
// the file data to begin. This is the value we need to
// make a multiple of 'alignement'.
offset += JarFile.LOCHDR + outEntry.getName().length();
if (firstEntry) {
// The first entry in a jar file has an extra field of
// four bytes that you can't get rid of; any extra
// data you specify in the JarEntry is appended to
// these forced four bytes. This is JAR_MAGIC in
// JarOutputStream; the bytes are 0xfeca0000.
offset += 4;
firstEntry = false;
} }
if (alignment > 0 && (offset % alignment != 0)) {
// Set the "extra data" of the entry to between 1 and
// alignment-1 bytes, to make the file data begin at
// an aligned offset.
int needed = alignment - (int)(offset % alignment);
outEntry.setExtra(new byte[needed]);
offset += needed;
}
out.putNextEntry(outEntry);
InputStream data = in.getInputStream(inEntry);
while ((num = data.read(buffer)) > 0) {
out.write(buffer, 0, num);
offset += num;
}
out.flush();
}
// Copy all the non-STORED entries. We don't attempt to
// maintain the 'offset' variable past this point; we don't do
// alignment on these entries.
for (String name : names) {
JarEntry inEntry = in.getJarEntry(name);
JarEntry outEntry = null;
if (inEntry.getMethod() == JarEntry.STORED) continue;
// Create a new entry so that the compressed len is recomputed.
outEntry = new JarEntry(name);
outEntry.setTime(timestamp); outEntry.setTime(timestamp);
out.putNextEntry(outEntry); out.putNextEntry(outEntry);
@ -589,7 +640,7 @@ class SignApk {
long timestamp = publicKey.getNotBefore().getTime() + 3600L * 1000; long timestamp = publicKey.getNotBefore().getTime() + 3600L * 1000;
Manifest manifest = addDigestsToManifest(inputJar, hash); Manifest manifest = addDigestsToManifest(inputJar, hash);
copyFiles(manifest, inputJar, outputJar, timestamp); copyFiles(manifest, inputJar, outputJar, timestamp, 0);
addOtacert(outputJar, publicKeyFile, timestamp, manifest, hash); addOtacert(outputJar, publicKeyFile, timestamp, manifest, hash);
signFile(manifest, inputJar, signFile(manifest, inputJar,
@ -778,6 +829,7 @@ class SignApk {
private static void usage() { private static void usage() {
System.err.println("Usage: signapk [-w] " + System.err.println("Usage: signapk [-w] " +
"[-a <alignment>] " +
"[-providerClass <className>] " + "[-providerClass <className>] " +
"publickey.x509[.pem] privatekey.pk8 " + "publickey.x509[.pem] privatekey.pk8 " +
"[publickey2.x509[.pem] privatekey2.pk8 ...] " + "[publickey2.x509[.pem] privatekey2.pk8 ...] " +
@ -794,6 +846,7 @@ class SignApk {
boolean signWholeFile = false; boolean signWholeFile = false;
String providerClass = null; String providerClass = null;
String providerArg = null; String providerArg = null;
int alignment = 4;
int argstart = 0; int argstart = 0;
while (argstart < args.length && args[argstart].startsWith("-")) { while (argstart < args.length && args[argstart].startsWith("-")) {
@ -806,6 +859,9 @@ class SignApk {
} }
providerClass = args[++argstart]; providerClass = args[++argstart];
++argstart; ++argstart;
} else if ("-a".equals(args[argstart])) {
alignment = Integer.parseInt(args[++argstart]);
++argstart;
} else { } else {
usage(); usage();
} }
@ -872,7 +928,7 @@ class SignApk {
outputJar.setLevel(9); outputJar.setLevel(9);
Manifest manifest = addDigestsToManifest(inputJar, hashes); Manifest manifest = addDigestsToManifest(inputJar, hashes);
copyFiles(manifest, inputJar, outputJar, timestamp); copyFiles(manifest, inputJar, outputJar, timestamp, alignment);
signFile(manifest, inputJar, publicKey, privateKey, outputJar); signFile(manifest, inputJar, publicKey, privateKey, outputJar);
outputJar.close(); outputJar.close();
} }