Fix fs-verity per fs-verity spec change

- Reorder and adjust fields per fs-verity format change.
- Since header + tree is no longer full page size, pass the length with
  shared memory (which is full pages).
- Fix offset and padding of patch extension.
- It is now required to issue the measure ioctl (via
  assertFsverityRootHashMatches) right after fs-verity is enabled.

Test: adb install a new priv app, saw fs-verity log in dmesg. Read the
      whole file successfully.
Bug: 30972906
Change-Id: I480ae2b5debaf76ef24dadf2d79d1903c7967f03
diff --git a/core/java/android/util/apk/ApkVerityBuilder.java b/core/java/android/util/apk/ApkVerityBuilder.java
index 3b8fc5c..f15e1a1 100644
--- a/core/java/android/util/apk/ApkVerityBuilder.java
+++ b/core/java/android/util/apk/ApkVerityBuilder.java
@@ -72,22 +72,31 @@
                 signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset;
         long dataSize = apk.length() - signingBlockSize;
         int[] levelOffset = calculateVerityLevelOffset(dataSize);
+        int merkleTreeSize = levelOffset[levelOffset.length - 1];
 
         ByteBuffer output = bufferFactory.create(
-                CHUNK_SIZE_BYTES +  // fsverity header + extensions + padding
-                levelOffset[levelOffset.length - 1]);  // Merkle tree size
+                merkleTreeSize
+                + CHUNK_SIZE_BYTES);  // maximum size of fsverity metadata
         output.order(ByteOrder.LITTLE_ENDIAN);
 
-        ByteBuffer header = slice(output, 0, FSVERITY_HEADER_SIZE_BYTES);
-        ByteBuffer extensions = slice(output, FSVERITY_HEADER_SIZE_BYTES, CHUNK_SIZE_BYTES);
-        ByteBuffer tree = slice(output, CHUNK_SIZE_BYTES, output.limit());
+        ByteBuffer tree = slice(output, 0, merkleTreeSize);
+        ByteBuffer header = slice(output, merkleTreeSize,
+                merkleTreeSize + FSVERITY_HEADER_SIZE_BYTES);
+        ByteBuffer extensions = slice(output, merkleTreeSize + FSVERITY_HEADER_SIZE_BYTES,
+                merkleTreeSize + CHUNK_SIZE_BYTES);
         byte[] apkDigestBytes = new byte[DIGEST_SIZE_BYTES];
         ByteBuffer apkDigest = ByteBuffer.wrap(apkDigestBytes);
         apkDigest.order(ByteOrder.LITTLE_ENDIAN);
 
+        // NB: Buffer limit is set inside once finished.
         calculateFsveritySignatureInternal(apk, signatureInfo, tree, apkDigest, header, extensions);
 
-        output.rewind();
+        // Put the reverse offset to fs-verity header at the end.
+        output.position(merkleTreeSize + FSVERITY_HEADER_SIZE_BYTES + extensions.limit());
+        output.putInt(FSVERITY_HEADER_SIZE_BYTES + extensions.limit()
+                + 4);  // size of this integer right before EOF
+        output.flip();
+
         return new ApkVerityResult(output, apkDigestBytes);
     }
 
@@ -101,7 +110,8 @@
         ByteBuffer verityBlock = ByteBuffer.allocate(CHUNK_SIZE_BYTES)
                 .order(ByteOrder.LITTLE_ENDIAN);
         ByteBuffer header = slice(verityBlock, 0, FSVERITY_HEADER_SIZE_BYTES);
-        ByteBuffer extensions = slice(verityBlock, FSVERITY_HEADER_SIZE_BYTES, CHUNK_SIZE_BYTES);
+        ByteBuffer extensions = slice(verityBlock, FSVERITY_HEADER_SIZE_BYTES,
+                CHUNK_SIZE_BYTES - FSVERITY_HEADER_SIZE_BYTES);
 
         calculateFsveritySignatureInternal(apk, signatureInfo, null, null, header, extensions);
 
@@ -328,10 +338,10 @@
         buffer.put((byte) 12);              // log2(block-size): log2(4096)
         buffer.put((byte) 7);               // log2(leaves-per-node): log2(4096 / 32)
 
-        buffer.putShort((short) 1);         // meta algorithm, SHA256_MODE == 1
-        buffer.putShort((short) 1);         // data algorithm, SHA256_MODE == 1
+        buffer.putShort((short) 1);         // meta algorithm, SHA256 == 1
+        buffer.putShort((short) 1);         // data algorithm, SHA256 == 1
 
-        buffer.putInt(0x0);                 // flags
+        buffer.putInt(0);                   // flags
         buffer.putInt(0);                   // reserved
 
         buffer.putLong(fileSize);           // original file size
@@ -362,12 +372,11 @@
         //
         // struct fsverity_extension_patch {
         //   __le64 offset;
-        //   u8 length;
-        //   u8 reserved[7];
         //   u8 databytes[];
         // };
 
         final int kSizeOfFsverityExtensionHeader = 8;
+        final int kExtensionSizeAlignment = 8;
 
         {
             // struct fsverity_extension #1
@@ -385,24 +394,25 @@
 
         {
             // struct fsverity_extension #2
-            final int kSizeOfFsverityPatchExtension =
-                    8 +  // offset size
-                    1 +  // size of length from offset (up to 255)
-                    7 +  // reserved
-                    ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE;
-            final int kPadding = (int) divideRoundup(kSizeOfFsverityPatchExtension % 8, 8);
+            final int kTotalSize = kSizeOfFsverityExtensionHeader
+                    + 8 // offset size
+                    + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE;
 
-            buffer.putShort((short)  // total size of extension, padded to 64-bit alignment
-                    (kSizeOfFsverityExtensionHeader + kSizeOfFsverityPatchExtension + kPadding));
+            buffer.putShort((short) kTotalSize);
             buffer.put((byte) 1);    // ID of patch extension
             skip(buffer, 5);         // reserved
 
             // struct fsverity_extension_patch
-            buffer.putLong(eocdOffset);                                 // offset
-            buffer.put((byte) ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE);  // length
-            skip(buffer, 7);                                            // reserved
-            buffer.putInt(Math.toIntExact(signingBlockOffset));         // databytes
-            skip(buffer, kPadding);                                     // padding
+            buffer.putLong(eocdOffset + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_OFFSET);  // offset
+            buffer.putInt(Math.toIntExact(signingBlockOffset));  // databytes
+
+            // The extension needs to be 0-padded at the end, since the length may not be multiple
+            // of 8.
+            int kPadding = kExtensionSizeAlignment - kTotalSize % kExtensionSizeAlignment;
+            if (kPadding == kExtensionSizeAlignment) {
+                kPadding = 0;
+            }
+            skip(buffer, kPadding);                              // padding
         }
 
         buffer.flip();