diff options
author | Doug Zongker <dougz@google.com> | 2014-05-16 15:56:37 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2014-05-16 15:56:37 +0000 |
commit | c0f10644bf877fae44e8aa5ebfff41f0e27af197 (patch) | |
tree | 0e5ac0ad096d42ade28b86f637bbf8e82fcb53b5 | |
parent | 4ec7007f4eac30703cf14b7beaff01a1a07f7eb1 (diff) | |
parent | 1d67eec191b76e299acfa54d95f3897e25536174 (diff) | |
download | build-c0f10644bf877fae44e8aa5ebfff41f0e27af197.tar.gz |
Merge "make SignApk do zip alignment"
-rw-r--r-- | tools/signapk/SignApk.java | 76 |
1 files changed, 66 insertions, 10 deletions
diff --git a/tools/signapk/SignApk.java b/tools/signapk/SignApk.java index b2470722c8..e661e506f4 100644 --- a/tools/signapk/SignApk.java +++ b/tools/signapk/SignApk.java @@ -461,24 +461,75 @@ class SignApk { * reduce variation in the output file and make incremental OTAs * more efficient. */ - private static void copyFiles(Manifest manifest, - JarFile in, JarOutputStream out, long timestamp) throws IOException { + private static void copyFiles(Manifest manifest, JarFile in, JarOutputStream out, + long timestamp, int alignment) throws IOException { byte[] buffer = new byte[4096]; int num; Map<String, Attributes> entries = manifest.getEntries(); ArrayList<String> names = new ArrayList<String>(entries.keySet()); 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) { JarEntry inEntry = in.getJarEntry(name); JarEntry outEntry = null; - if (inEntry.getMethod() == JarEntry.STORED) { - // Preserve the STORED method of the input entry. - outEntry = new JarEntry(inEntry); - } else { - // Create a new entry so that the compressed len is recomputed. - outEntry = new JarEntry(name); + if (inEntry.getMethod() != JarEntry.STORED) continue; + // Preserve the STORED method of the input entry. + outEntry = new JarEntry(inEntry); + outEntry.setTime(timestamp); + + // '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); out.putNextEntry(outEntry); @@ -589,7 +640,7 @@ class SignApk { long timestamp = publicKey.getNotBefore().getTime() + 3600L * 1000; Manifest manifest = addDigestsToManifest(inputJar, hash); - copyFiles(manifest, inputJar, outputJar, timestamp); + copyFiles(manifest, inputJar, outputJar, timestamp, 0); addOtacert(outputJar, publicKeyFile, timestamp, manifest, hash); signFile(manifest, inputJar, @@ -778,6 +829,7 @@ class SignApk { private static void usage() { System.err.println("Usage: signapk [-w] " + + "[-a <alignment>] " + "[-providerClass <className>] " + "publickey.x509[.pem] privatekey.pk8 " + "[publickey2.x509[.pem] privatekey2.pk8 ...] " + @@ -794,6 +846,7 @@ class SignApk { boolean signWholeFile = false; String providerClass = null; String providerArg = null; + int alignment = 4; int argstart = 0; while (argstart < args.length && args[argstart].startsWith("-")) { @@ -806,6 +859,9 @@ class SignApk { } providerClass = args[++argstart]; ++argstart; + } else if ("-a".equals(args[argstart])) { + alignment = Integer.parseInt(args[++argstart]); + ++argstart; } else { usage(); } @@ -872,7 +928,7 @@ class SignApk { outputJar.setLevel(9); Manifest manifest = addDigestsToManifest(inputJar, hashes); - copyFiles(manifest, inputJar, outputJar, timestamp); + copyFiles(manifest, inputJar, outputJar, timestamp, alignment); signFile(manifest, inputJar, publicKey, privateKey, outputJar); outputJar.close(); } |