Support bigger shared data

Bug: 337147425
Test: s2storage_tests geotz_s2storage_tests SatelliteS2StorageTests SatelliteToolsTests
SatelliteManagerTestOnMockService
Manual test with Skylo demo and real mode

Change-Id: Id9603a32265dfc88c8bcb5503cc48e9a1da25a81
diff --git a/s2storage/src/readonly/java/com/android/storage/block/read/BlockData.java b/s2storage/src/readonly/java/com/android/storage/block/read/BlockData.java
index f9ce802..4fe5bc4 100644
--- a/s2storage/src/readonly/java/com/android/storage/block/read/BlockData.java
+++ b/s2storage/src/readonly/java/com/android/storage/block/read/BlockData.java
@@ -84,6 +84,15 @@
     }
 
     /**
+     * Returns an array of signed bytes starting at the specified position, where the 4-byte length
+     * is encoded in the data.
+     */
+    public byte[] getByteArray(int byteOffset) {
+        int size = getInt(byteOffset);
+        return getBytes(byteOffset + Integer.BYTES, size);
+    }
+
+    /**
      * Returns an array of signed bytes starting at the specified position.
      */
     public byte[] getBytes(int byteOffset, int byteCount) {
diff --git a/s2storage/src/readonly/java/com/android/storage/table/packed/read/BaseTypedPackedTable.java b/s2storage/src/readonly/java/com/android/storage/table/packed/read/BaseTypedPackedTable.java
index b2aa2dc..9a61c3c 100644
--- a/s2storage/src/readonly/java/com/android/storage/table/packed/read/BaseTypedPackedTable.java
+++ b/s2storage/src/readonly/java/com/android/storage/table/packed/read/BaseTypedPackedTable.java
@@ -33,7 +33,11 @@
     protected final PackedTableReader mTableReader;
 
     BaseTypedPackedTable(BlockData blockData, int maxValueTypeBits) {
-        mTableReader = new PackedTableReader(blockData);
+        this(blockData, maxValueTypeBits, false);
+    }
+
+    BaseTypedPackedTable(BlockData blockData, int maxValueTypeBits, boolean useBigSharedData) {
+        mTableReader = new PackedTableReader(blockData, useBigSharedData);
         if (mTableReader.getValueSizeBits() > maxValueTypeBits) {
             throw new IllegalArgumentException(
                     "The supplied packed table block can hold values greater than "
diff --git a/s2storage/src/readonly/java/com/android/storage/table/packed/read/IntValueTypedPackedTable.java b/s2storage/src/readonly/java/com/android/storage/table/packed/read/IntValueTypedPackedTable.java
index b2be795..b09046a 100644
--- a/s2storage/src/readonly/java/com/android/storage/table/packed/read/IntValueTypedPackedTable.java
+++ b/s2storage/src/readonly/java/com/android/storage/table/packed/read/IntValueTypedPackedTable.java
@@ -30,7 +30,11 @@
         implements IntValueTable {
 
     public IntValueTypedPackedTable(BlockData blockData) {
-        super(blockData, Integer.SIZE);
+        this(blockData, false);
+    }
+
+    public IntValueTypedPackedTable(BlockData blockData, boolean useBigSharedData) {
+        super(blockData, Integer.SIZE, useBigSharedData);
         boolean signedValue = mTableReader.isValueSigned();
         if (mTableReader.getValueSizeBits() == Integer.SIZE && !signedValue) {
             throw new IllegalArgumentException(
diff --git a/s2storage/src/readonly/java/com/android/storage/table/packed/read/PackedTableReader.java b/s2storage/src/readonly/java/com/android/storage/table/packed/read/PackedTableReader.java
index c6f9623..d4354d1 100644
--- a/s2storage/src/readonly/java/com/android/storage/table/packed/read/PackedTableReader.java
+++ b/s2storage/src/readonly/java/com/android/storage/table/packed/read/PackedTableReader.java
@@ -73,12 +73,21 @@
     private final boolean mIntValueSupported;
 
     public PackedTableReader(BlockData blockData) {
+        this(blockData, false);
+    }
+
+    public PackedTableReader(BlockData blockData, boolean useBigSharedData) {
         mBlockData = Objects.requireNonNull(blockData);
 
         int offset = 0;
 
-        mSharedData = blockData.getTinyByteArray(offset);
-        offset += Byte.BYTES + mSharedData.length;
+        if (useBigSharedData) {
+            mSharedData = blockData.getByteArray(offset);
+            offset += Integer.BYTES + mSharedData.length;
+        } else {
+            mSharedData = blockData.getTinyByteArray(offset);
+            offset += Byte.BYTES + mSharedData.length;
+        }
 
         // Boolean properties are extracted from a 32-bit bit field.
         int bitField = blockData.getUnsignedByte(offset);
diff --git a/s2storage/src/test/java/com/android/storage/table/packed/IntValuePackedTableTest.java b/s2storage/src/test/java/com/android/storage/table/packed/IntValuePackedTableTest.java
index 3935151..77ccfc2 100644
--- a/s2storage/src/test/java/com/android/storage/table/packed/IntValuePackedTableTest.java
+++ b/s2storage/src/test/java/com/android/storage/table/packed/IntValuePackedTableTest.java
@@ -126,14 +126,21 @@
 
     @Test
     public void getSharedData() throws IOException {
+        getSharedData(true);
+        getSharedData(false);
+    }
+
+    private void getSharedData(boolean useBigSharedData) throws IOException {
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         byte[] sharedData = "Shared data".getBytes(StandardCharsets.UTF_8);
         boolean signedValue = false;
-        PackedTableWriter writer = PackedTableWriter.create(baos, 2, 4, signedValue, sharedData);
+        PackedTableWriter writer =
+                PackedTableWriter.create(baos, 2, 4, signedValue, sharedData, useBigSharedData);
         writer.close();
 
         BlockData blockData = new BlockData(createByteBuffer(baos.toByteArray()));
-        IntValueTypedPackedTable intValuePackedTable = new IntValueTypedPackedTable(blockData);
+        IntValueTypedPackedTable intValuePackedTable =
+                new IntValueTypedPackedTable(blockData, useBigSharedData);
         assertArrayEquals(sharedData, intValuePackedTable.getSharedData());
     }
 
diff --git a/s2storage/src/test/java/com/android/storage/table/packed/PackedTableReaderWriterTest.java b/s2storage/src/test/java/com/android/storage/table/packed/PackedTableReaderWriterTest.java
index f4c339e..ab51f36 100644
--- a/s2storage/src/test/java/com/android/storage/table/packed/PackedTableReaderWriterTest.java
+++ b/s2storage/src/test/java/com/android/storage/table/packed/PackedTableReaderWriterTest.java
@@ -214,14 +214,20 @@
 
     @Test
     public void getSharedData() throws IOException {
+        getSharedData(true);
+        getSharedData(false);
+    }
+
+    private void getSharedData(boolean useBigSharedData) throws IOException {
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        byte[] sharedData = "Shared data".getBytes(StandardCharsets.UTF_8);
+        byte[] sharedData = createPopulatedByteArray(useBigSharedData ? 1500 : 100);
         boolean signedValue = false;
-        PackedTableWriter writer = PackedTableWriter.create(baos, 2, 4, signedValue, sharedData);
+        PackedTableWriter writer =
+                PackedTableWriter.create(baos, 2, 4, signedValue, sharedData, useBigSharedData);
         writer.close();
 
         BlockData blockData = new BlockData(createByteBuffer(baos.toByteArray()));
-        PackedTableReader tableReader = new PackedTableReader(blockData);
+        PackedTableReader tableReader = new PackedTableReader(blockData, useBigSharedData);
         assertArrayEquals(sharedData, tableReader.getSharedData());
     }
 
@@ -541,4 +547,13 @@
     private static ByteBuffer createByteBuffer(byte[] bytes) {
         return ByteBuffer.wrap(bytes).asReadOnlyBuffer();
     }
+
+    private static byte[] createPopulatedByteArray(int size) {
+        byte[] byteArray = new byte[size];
+        char ch = 'A';
+        for (int i = 0; i < size; i++) {
+            byteArray[i] = (byte) (ch + (i % 27));
+        }
+        return byteArray;
+    }
 }
diff --git a/s2storage/src/write/java/com/android/storage/io/write/TypedOutputStream.java b/s2storage/src/write/java/com/android/storage/io/write/TypedOutputStream.java
index 4e46e9e..c5269ad 100644
--- a/s2storage/src/write/java/com/android/storage/io/write/TypedOutputStream.java
+++ b/s2storage/src/write/java/com/android/storage/io/write/TypedOutputStream.java
@@ -109,6 +109,14 @@
     }
 
     /**
+     * Writes a byte array as an integer (length) followed by the bytes.
+     */
+    public void writeByteArray(byte[] bytes) throws IOException {
+        writeInt(bytes.length);
+        mDataOutputStream.write(bytes);
+    }
+
+    /**
      * Writes a tiny (<= 255 entry) char array as an unsigned byte (length) followed by the chars.
      */
     public void writeTinyCharArray(char[] chars) throws IOException {
diff --git a/s2storage/src/write/java/com/android/storage/table/packed/write/PackedTableWriter.java b/s2storage/src/write/java/com/android/storage/table/packed/write/PackedTableWriter.java
index 617430c..8c162d8 100644
--- a/s2storage/src/write/java/com/android/storage/table/packed/write/PackedTableWriter.java
+++ b/s2storage/src/write/java/com/android/storage/table/packed/write/PackedTableWriter.java
@@ -72,7 +72,10 @@
 
     /**
      * Creates a {@link PackedTableWriter} to write to the specified stream with the specified
-     * parameters. Entries must be added in key order via {@link #addEntry(int, long)}.
+     * parameters. Entries must be added in key order via {@link #addEntry(int, long)}. Using this
+     * factory method, the maximum size of {@code sharedData} is 255 bytes. If the size of
+     * {@code sharedData} is more than 255 bytes, the method
+     * {@link #create(OutputStream, int, int, boolean, byte[], boolean)} should be used.
      *
      * @param outputStream the stream to write to
      * @param entrySizeBytes the number of bytes per entry
@@ -85,17 +88,43 @@
      */
     public static PackedTableWriter create(OutputStream outputStream, int entrySizeBytes,
             int keyBits, boolean signedValue, byte[] sharedData) throws IOException {
+        return create(outputStream, entrySizeBytes, keyBits, signedValue, sharedData, false);
+    }
+
+    /**
+     * Creates a {@link PackedTableWriter} to write to the specified stream with the specified
+     * parameters. Entries must be added in key order via {@link #addEntry(int, long)}.
+     *
+     * @param outputStream the stream to write to
+     * @param entrySizeBytes the number of bytes per entry
+     * @param keyBits the number of bits in the key
+     * @param signedValue true if the values written via {@link #addEntry(int, long)} should be
+     * sign extended
+     * @param sharedData data to write into the table's header, i.e. that applies to all entries in
+     * the table
+     * @param useBigSharedData {@code true} means an integer will be used for storing the length of
+     * the shared data; {@code false} means an unsigned byte will be used. Specifying {@code false}
+     * uses less space per table, but limits the shared data to 255 bytes per table.
+     * @throws IllegalArgumentException if the parameters are invalid
+     */
+    public static PackedTableWriter create(OutputStream outputStream, int entrySizeBytes,
+            int keyBits, boolean signedValue, byte[] sharedData, boolean useBigSharedData)
+            throws IOException {
         PackedTableWriter packedTableWriter =
                 new PackedTableWriter(outputStream, entrySizeBytes, keyBits, signedValue);
-        packedTableWriter.writeHeader(sharedData);
+        packedTableWriter.writeHeader(sharedData, useBigSharedData);
         return packedTableWriter;
     }
 
-    private void writeHeader(byte[] sharedData) throws IOException {
+    private void writeHeader(byte[] sharedData, boolean useBigSharedData) throws IOException {
         if (sharedData == null) {
             sharedData = EMPTY_BYTE_ARRAY;
         }
-        mBlockDataOutputStream.writeTinyByteArray(sharedData);
+        if (useBigSharedData) {
+            mBlockDataOutputStream.writeByteArray(sharedData);
+        } else {
+            mBlockDataOutputStream.writeTinyByteArray(sharedData);
+        }
 
         int bitField = 0;
         if (mSignedValue) {