summaryrefslogtreecommitdiffstats
path: root/tools/signapk
diff options
context:
space:
mode:
authorDoug Zongker <dougz@google.com>2014-05-15 09:54:26 -0700
committerDoug Zongker <dougz@google.com>2014-05-15 09:54:26 -0700
commit1d67eec191b76e299acfa54d95f3897e25536174 (patch)
tree444a6555ac75ce33186280bdce9d36993c741b7d /tools/signapk
parent944a38104a553d84c44fa87b2378ebee66a12349 (diff)
downloadbuild-1d67eec191b76e299acfa54d95f3897e25536174.zip
build-1d67eec191b76e299acfa54d95f3897e25536174.tar.gz
build-1d67eec191b76e299acfa54d95f3897e25536174.tar.bz2
make SignApk do zip alignment
When signing an APK, make the SignApk tool align the stored entries to (by default) 4-byte boundaries. This obviates the need to run the separate zipalign tool, which currently does this job. The alignment byte count can be specified with the -a option. OTA package signing (with -w) never does alignment. The order of files in the output APK is changed so that all stored files come first in the output, followed by all non-stored files. This is not expected to have any impact in practice. Change-Id: Iaeef89b2a7283e25fadb99c0a0f0641f682d76b8
Diffstat (limited to 'tools/signapk')
-rw-r--r--tools/signapk/SignApk.java76
1 files changed, 66 insertions, 10 deletions
diff --git a/tools/signapk/SignApk.java b/tools/signapk/SignApk.java
index b247072..e661e50 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();
}