From baa9f50cb26ffb4be7391ec91b894fce7355b573 Mon Sep 17 00:00:00 2001
From: Vic Yang <victoryang@google.com>
Date: Tue, 9 Jul 2019 10:09:35 -0700
Subject: [PATCH 1/1] Implement range-based pin list

This extends the original pin list generation to support specifying a
range within a file.  If any part of a file is pinned, its local file
header in the APK file is pinned as well.

Test: Build cuttlefish.
Bug: 136040313
Bug: 135953430
Change-Id: I6de8c2b4c2f35c6bf257f61414c6bce761233e51
---
 .../src/com/android/signapk/SignApk.java      | 66 +++++++++++++------
 1 file changed, 46 insertions(+), 20 deletions(-)

diff --git a/tools/signapk/src/com/android/signapk/SignApk.java b/tools/signapk/src/com/android/signapk/SignApk.java
index 57973ec044..9809ed406b 100644
--- a/tools/signapk/src/com/android/signapk/SignApk.java
+++ b/tools/signapk/src/com/android/signapk/SignApk.java
@@ -381,9 +381,8 @@ class SignApk {
         byte[] buffer = new byte[4096];
         int num;
 
-        List<Pattern> pinPatterns = extractPinPatterns(in);
+        List<Hints.PatternWithRange> pinPatterns = extractPinPatterns(in);
         ArrayList<Hints.ByteRange> pinByteRanges = pinPatterns == null ? null : new ArrayList<>();
-        HashSet<String> namesToPin = new HashSet<>();
 
         ArrayList<String> names = new ArrayList<String>();
         for (Enumeration<JarEntry> e = in.entries(); e.hasMoreElements();) {
@@ -399,13 +398,6 @@ class SignApk {
             if (Hints.PIN_BYTE_RANGE_ZIP_ENTRY_NAME.equals(entryName)) {
                 continue;  // We regenerate it below.
             }
-            if (pinPatterns != null) {
-                for (Pattern pinPattern : pinPatterns) {
-                    if (pinPattern.matcher(entryName).matches()) {
-                        namesToPin.add(entryName);
-                    }
-                }
-            }
             names.add(entryName);
         }
         Collections.sort(names);
@@ -485,6 +477,7 @@ class SignApk {
             DataSink entryDataSink =
                     (inspectEntryRequest != null) ? inspectEntryRequest.getDataSink() : null;
 
+            long entryDataStart = outCounter.getWrittenBytes();
             try (InputStream data = in.getInputStream(inEntry)) {
                 while ((num = data.read(buffer)) > 0) {
                     out.write(buffer, 0, num);
@@ -500,11 +493,27 @@ class SignApk {
                 inspectEntryRequest.done();
             }
 
-            if (namesToPin.contains(name)) {
-                pinByteRanges.add(
-                    new Hints.ByteRange(
-                        entryHeaderStart,
-                        outCounter.getWrittenBytes()));
+            if (pinPatterns != null) {
+                boolean pinFileHeader = false;
+                for (Hints.PatternWithRange pinPattern : pinPatterns) {
+                    if (!pinPattern.matcher(name).matches()) {
+                        continue;
+                    }
+                    Hints.ByteRange dataRange =
+                        new Hints.ByteRange(
+                            entryDataStart,
+                            outCounter.getWrittenBytes());
+                    Hints.ByteRange pinRange =
+                        pinPattern.ClampToAbsoluteByteRange(dataRange);
+                    if (pinRange != null) {
+                        pinFileHeader = true;
+                        pinByteRanges.add(pinRange);
+                    }
+                }
+                if (pinFileHeader) {
+                    pinByteRanges.add(new Hints.ByteRange(entryHeaderStart,
+                                                          entryDataStart));
+                }
             }
         }
 
@@ -528,6 +537,7 @@ class SignApk {
             DataSink entryDataSink =
                     (inspectEntryRequest != null) ? inspectEntryRequest.getDataSink() : null;
 
+            long entryDataStart = outCounter.getWrittenBytes();
             InputStream data = in.getInputStream(inEntry);
             while ((num = data.read(buffer)) > 0) {
                 out.write(buffer, 0, num);
@@ -541,11 +551,27 @@ class SignApk {
                 inspectEntryRequest.done();
             }
 
-            if (namesToPin.contains(name)) {
-                pinByteRanges.add(
-                    new Hints.ByteRange(
-                        entryHeaderStart,
-                        outCounter.getWrittenBytes()));
+            if (pinPatterns != null) {
+                boolean pinFileHeader = false;
+                for (Hints.PatternWithRange pinPattern : pinPatterns) {
+                    if (!pinPattern.matcher(name).matches()) {
+                        continue;
+                    }
+                    Hints.ByteRange dataRange =
+                        new Hints.ByteRange(
+                            entryDataStart,
+                            outCounter.getWrittenBytes());
+                    Hints.ByteRange pinRange =
+                        pinPattern.ClampToAbsoluteByteRange(dataRange);
+                    if (pinRange != null) {
+                        pinFileHeader = true;
+                        pinByteRanges.add(pinRange);
+                    }
+                }
+                if (pinFileHeader) {
+                    pinByteRanges.add(new Hints.ByteRange(entryHeaderStart,
+                                                          entryDataStart));
+                }
             }
         }
 
@@ -558,7 +584,7 @@ class SignApk {
         }
     }
 
-    private static List<Pattern> extractPinPatterns(JarFile in) throws IOException {
+    private static List<Hints.PatternWithRange> extractPinPatterns(JarFile in) throws IOException {
         ZipEntry pinMetaEntry = in.getEntry(Hints.PIN_HINT_ASSET_ZIP_ENTRY_NAME);
         if (pinMetaEntry == null) {
             return null;
-- 
2.20.1

