[Geofence] Write/read entry value byte count and version number to/from the header block
Bug: 351054257
Flag: EXEMPT refactor
Test: atest SatelliteAccessControllerTest HeaderBlockTest SatS2RangeFileFormatTest SuffixTableRangeTest SuffixTableSharedDataTest Sa2S2RangeFileReaderTest SuffixTableBlockTest S2RangeSatelliteOnDeviceAccessControllerTest
manually test e2e Skylo in live network
Change-Id: I27ddb76740ef6ed8c8fd3df9d3c1863d06b14919
diff --git a/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/HeaderBlock.java b/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/HeaderBlock.java
index 9895d1a..9592e1e 100644
--- a/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/HeaderBlock.java
+++ b/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/HeaderBlock.java
@@ -40,10 +40,26 @@
int suffixBitCount = blockData.getUnsignedByte(offset++);
int suffixRecordBitCount = blockData.getUnsignedByte(offset++);
int suffixTableBlockIdOffset = blockData.getUnsignedByte(offset++);
- boolean isAllowedList = (blockData.getUnsignedByte(offset) == TRUE);
- mFileFormat = new SatS2RangeFileFormat(
- dataS2Level, prefixBitCount, suffixBitCount, suffixTableBlockIdOffset,
- suffixRecordBitCount, isAllowedList);
+ boolean isAllowedList = (blockData.getUnsignedByte(offset++) == TRUE);
+
+
+ // Check if the block is in the original format or the enhanced format.
+ // If the offset is equal to the block data size, this block is in the original format.
+ // If the offset is less than the block data size, this block is an enhanced block, which
+ // has additional fields:
+ // - the size of an entry value in bytes
+ // - version number of header block
+ if (offset < blockData.getSize()) {
+ int entryValueSizeInBytes = blockData.getUnsignedByte(offset++);
+ int versionNumber = blockData.getInt(offset);
+ mFileFormat = new SatS2RangeFileFormat(
+ dataS2Level, prefixBitCount, suffixBitCount, suffixTableBlockIdOffset,
+ suffixRecordBitCount, isAllowedList, entryValueSizeInBytes, versionNumber);
+ } else {
+ mFileFormat = new SatS2RangeFileFormat(
+ dataS2Level, prefixBitCount, suffixBitCount, suffixTableBlockIdOffset,
+ suffixRecordBitCount, isAllowedList);
+ }
}
/** Creates a {@link HeaderBlock} from low-level block data from a block file. */
diff --git a/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SatS2RangeFileFormat.java b/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SatS2RangeFileFormat.java
index 39507aa..a335766 100644
--- a/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SatS2RangeFileFormat.java
+++ b/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SatS2RangeFileFormat.java
@@ -53,6 +53,10 @@
/** The format version of the satellite S2 data file, read and written. */
public static final int VERSION = 1;
+ private static final int DEFAULT_ENTRY_VALUE_SIZE_IN_BYTES = 0;
+ private static final int DEFAULT_VERSION_NUMBER = 0;
+ private static final int MAX_ENTRY_BYTE_COUNT = 4;
+
private final int mDataS2Level;
private final int mPrefixBitCount;
@@ -87,11 +91,28 @@
private final boolean mIsAllowedList;
/**
+ * Entry value size in bytes
+ */
+ private final int mEntryValueSizeInBytes;
+
+ /**
+ * Version number
+ */
+ private final int mVersionNumber;
+
+ public SatS2RangeFileFormat(int s2Level, int prefixBitCount, int suffixBitCount,
+ int suffixTableBlockIdOffset, int tableEntryBitCount, boolean isAllowedList) {
+ this(s2Level, prefixBitCount, suffixBitCount, suffixTableBlockIdOffset, tableEntryBitCount,
+ isAllowedList, DEFAULT_ENTRY_VALUE_SIZE_IN_BYTES, DEFAULT_VERSION_NUMBER);
+ }
+
+ /**
* Creates a new file format. This constructor validates the values against various hard-coded
* constraints and will throw an {@link IllegalArgumentException} if they are not satisfied.
*/
public SatS2RangeFileFormat(int s2Level, int prefixBitCount, int suffixBitCount,
- int suffixTableBlockIdOffset, int tableEntryBitCount, boolean isAllowedList) {
+ int suffixTableBlockIdOffset, int tableEntryBitCount, boolean isAllowedList,
+ int entryValueSizeInBytes, int versionNumber) {
Conditions.checkArgInRange("s2Level", s2Level, 0, MAX_S2_LEVEL);
@@ -180,6 +201,12 @@
mSuffixTableBlockIdOffset = suffixTableBlockIdOffset;
mIsAllowedList = isAllowedList;
+
+ Conditions.checkArgInRange("entryValueSizeInBytes", entryValueSizeInBytes, 0,
+ MAX_ENTRY_BYTE_COUNT);
+ mEntryValueSizeInBytes = entryValueSizeInBytes;
+
+ mVersionNumber = versionNumber;
}
/** Returns the S2 level of all geo data stored in the file. */
@@ -345,6 +372,18 @@
+ "}";
}
+ /**
+ * Returns the length of entry value in Bytes.
+ * @return the length of entry value
+ */
+ public int getEntryValueSizeInBytes() {
+ return mEntryValueSizeInBytes;
+ }
+
+ public int getVersionNumber() {
+ return mVersionNumber;
+ }
+
@Override
public String toString() {
return "SatS2RangeFileFormat{"
@@ -359,6 +398,8 @@
+ ", mSuffixTableBlockIdOffset=" + mSuffixTableBlockIdOffset
+ ", mUnusedCellIdBitCount=" + mUnusedCellIdBitCount
+ ", mIsAllowedList=" + mIsAllowedList
+ + ", mEntryValueSizeInBytes=" + mEntryValueSizeInBytes
+ + ", mVersionNumber=" + mVersionNumber
+ '}';
}
@@ -381,7 +422,9 @@
&& mTableEntryMaxRangeLengthValue == that.mTableEntryMaxRangeLengthValue
&& mSuffixTableBlockIdOffset == that.mSuffixTableBlockIdOffset
&& mIsAllowedList == that.mIsAllowedList
- && mUnusedCellIdBitCount == that.mUnusedCellIdBitCount;
+ && mUnusedCellIdBitCount == that.mUnusedCellIdBitCount
+ && mEntryValueSizeInBytes == that.mEntryValueSizeInBytes
+ && mVersionNumber == that.mVersionNumber;
}
@Override
@@ -389,7 +432,7 @@
return Objects.hash(mDataS2Level, mPrefixBitCount, mMaxPrefixValue, mSuffixBitCount,
mMaxSuffixValue, mTableEntryBitCount, mTableEntryRangeLengthBitCount,
mTableEntryMaxRangeLengthValue, mSuffixTableBlockIdOffset, mIsAllowedList,
- mUnusedCellIdBitCount);
+ mUnusedCellIdBitCount, mEntryValueSizeInBytes, mVersionNumber);
}
private void checkS2Level(String name, long cellId) {
diff --git a/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SuffixTableRange.java b/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SuffixTableRange.java
index 88f1b2e..8c1466f 100644
--- a/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SuffixTableRange.java
+++ b/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SuffixTableRange.java
@@ -23,12 +23,12 @@
import java.util.Objects;
public final class SuffixTableRange extends S2LevelRange {
- private static final int DEAFAULT_ENTRY_VALUE = -1;
+ private static final int DEFAULT_ENTRY_VALUE = -1;
private final int mEntryValue;
// For backward compatibility
public SuffixTableRange(long startCellId, long endCellId) {
- this(startCellId, endCellId, DEAFAULT_ENTRY_VALUE);
+ this(startCellId, endCellId, DEFAULT_ENTRY_VALUE);
}
public SuffixTableRange(long startCellId, long endCellId, int entryValue) {
diff --git a/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SuffixTableSharedData.java b/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SuffixTableSharedData.java
index 2221b2c..14cb92f 100644
--- a/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SuffixTableSharedData.java
+++ b/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SuffixTableSharedData.java
@@ -16,11 +16,13 @@
package com.android.telephony.sats2range.read;
+import com.android.storage.block.read.TypedData;
import com.android.storage.io.read.TypedInputStream;
import com.android.storage.table.reader.Table;
import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.util.List;
import java.util.Objects;
/**
@@ -28,14 +30,98 @@
* entries in the table and is required when interpreting the table's block data.
*/
public final class SuffixTableSharedData {
-
+ public static final int INVALID_ENTRY_VALUE = -1;
private final int mTablePrefix;
+ private final int mEntryValueSizeInBytes;
+ private final int mNumberOfEntryValues;
+ private final int mHeaderByteOffsetToRead;
+ private List<Integer> mEntryValuesToWrite = List.of(); // This is used for write path
+ private final TypedData mSharedDataToRead; // This is used for read path
/**
* Creates a {@link SuffixTableSharedData}. See also {@link #fromBytes(byte[])}.
*/
public SuffixTableSharedData(int tablePrefix) {
mTablePrefix = tablePrefix;
+ mEntryValueSizeInBytes = 0;
+ mNumberOfEntryValues = 0;
+ mHeaderByteOffsetToRead = 0;
+ mSharedDataToRead = null;
+ }
+
+ /**
+ * This constructor is used for write path
+ */
+ public SuffixTableSharedData(int tablePrefix, List<Integer> entryValues,
+ SatS2RangeFileFormat fileFormat) {
+ mSharedDataToRead = null;
+ mTablePrefix = tablePrefix;
+ mNumberOfEntryValues = entryValues.size();
+ mEntryValuesToWrite = entryValues;
+ mEntryValueSizeInBytes = fileFormat.getEntryValueSizeInBytes();
+ mHeaderByteOffsetToRead = 0;
+ }
+
+ /**
+ * This constructor is used for read path
+ */
+ public SuffixTableSharedData(TypedData sharedDataToRead, SatS2RangeFileFormat fileFormat) {
+ mSharedDataToRead = Objects.requireNonNull(sharedDataToRead);
+ int offset = 0;
+ // extract prefix value
+ mTablePrefix = mSharedDataToRead.getInt(offset);
+ offset += Integer.BYTES;
+
+ // If the size of shared data is greater than the offset, extract the number of entry
+ // values.
+ if ((offset + Integer.BYTES) < mSharedDataToRead.getSize()) {
+ mNumberOfEntryValues = mSharedDataToRead.getInt(offset);
+ mHeaderByteOffsetToRead = offset + Integer.BYTES;
+ mEntryValueSizeInBytes = fileFormat.getEntryValueSizeInBytes();
+ } else {
+ mNumberOfEntryValues = 0;
+ mHeaderByteOffsetToRead = offset;
+ mEntryValueSizeInBytes = 0;
+ }
+ }
+
+ /**
+ * This is used for read path
+ */
+ public static SuffixTableSharedData fromTypedData(TypedData sharedData,
+ SatS2RangeFileFormat fileFormat) {
+ return new SuffixTableSharedData(sharedData, fileFormat);
+ }
+
+ /**
+ * Reads the entry value at a specific position in the byte buffer and returns it.
+ *
+ * @param entryIndex The index of entry to be read.
+ * @return entry value (integer) read from the byte buffer.
+ */
+ public int getEntryValue(int entryIndex) {
+ if (mSharedDataToRead == null || entryIndex < 0 || mNumberOfEntryValues == 0) {
+ return INVALID_ENTRY_VALUE;
+ }
+
+ if (mNumberOfEntryValues == 1) {
+ entryIndex = 0;
+ }
+
+ int offset;
+ if (entryIndex < mNumberOfEntryValues) {
+ // offset = table prefix(4) + entry value count(4) + size of entry * entry index
+ offset = mHeaderByteOffsetToRead + (mEntryValueSizeInBytes * entryIndex);
+ } else {
+ return INVALID_ENTRY_VALUE;
+ }
+
+ return getValueInternal(mSharedDataToRead, mEntryValueSizeInBytes, offset);
+ }
+
+ // Entry lists to be written to a byte buffer.
+ public List<Integer> getEntryValuesToWrite() {
+ return mEntryValuesToWrite;
}
/**
@@ -46,6 +132,20 @@
return mTablePrefix;
}
+ /**
+ * Returns the number of entry values.
+ */
+ public int getNumberOfEntryValues() {
+ return mNumberOfEntryValues;
+ }
+
+ /**
+ * Returns the size of entry value in Bytes.
+ */
+ public int getEntryValueSizeInBytes() {
+ return mEntryValueSizeInBytes;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) {
@@ -55,18 +155,22 @@
return false;
}
SuffixTableSharedData that = (SuffixTableSharedData) o;
- return mTablePrefix == that.mTablePrefix;
+ return mTablePrefix == that.mTablePrefix
+ && mNumberOfEntryValues == that.mNumberOfEntryValues
+ && mEntryValuesToWrite.equals(that.mEntryValuesToWrite);
}
@Override
public int hashCode() {
- return Objects.hash(mTablePrefix);
+ return Objects.hash(mTablePrefix, mNumberOfEntryValues, mEntryValuesToWrite);
}
@Override
public String toString() {
return "SuffixTableSharedData{"
+ "mTablePrefix=" + mTablePrefix
+ + "mNumberOfEntries=" + mNumberOfEntryValues
+ + "mEntryValuesToWrite=" + mEntryValuesToWrite
+ '}';
}
@@ -82,4 +186,21 @@
throw new RuntimeException(e);
}
}
+
+ private int getValueInternal(TypedData buffer, int valueSizeBytes, int byteOffset) {
+ if (byteOffset < 0) {
+ throw new IllegalArgumentException(
+ "byteOffset=" + byteOffset + " must not be negative");
+ }
+
+ // High bytes read first.
+ int value = 0;
+ int bytesRead = 0;
+ while (bytesRead++ < valueSizeBytes) {
+ value <<= Byte.SIZE;
+ value |= buffer.getUnsignedByte(byteOffset++);
+ }
+
+ return value;
+ }
}
diff --git a/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SatS2RangeFileFormatTest.java b/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SatS2RangeFileFormatTest.java
index 80ef467..65da1e4 100644
--- a/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SatS2RangeFileFormatTest.java
+++ b/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SatS2RangeFileFormatTest.java
@@ -67,10 +67,12 @@
int suffixBitCount = 16;
int suffixTableBlockIdOffset = 5;
int suffixTableEntryBitCount = 24;
+ int suffixTableEntryValueSizeInBytes = 4;
+ int versionNumber = 2;
boolean isAllowedList = false;
SatS2RangeFileFormat satS2RangeFileFormat = new SatS2RangeFileFormat(s2Level,
prefixBitCount, suffixBitCount, suffixTableBlockIdOffset, suffixTableEntryBitCount,
- isAllowedList);
+ isAllowedList, suffixTableEntryValueSizeInBytes, versionNumber);
assertEquals(2, satS2RangeFileFormat.calculateRangeLength(
cellId(s2Level, 0, 0), cellId(s2Level, 0, 2)));
@@ -92,9 +94,11 @@
int suffixTableBlockIdOffset = 5;
int suffixTableEntryBitCount = 24;
boolean isAllowedList = true;
+ int suffixTableEntryValueSizeInBytes = 4;
+ int versionNumber = 2;
SatS2RangeFileFormat satS2RangeFileFormat = new SatS2RangeFileFormat(s2Level,
prefixBitCount, suffixBitCount, suffixTableBlockIdOffset, suffixTableEntryBitCount,
- isAllowedList);
+ isAllowedList, suffixTableEntryValueSizeInBytes, versionNumber);
// Too many bits for prefixValue
assertThrows(IllegalArgumentException.class,
@@ -127,9 +131,11 @@
int suffixTableBlockIdOffset = 5;
int suffixTableEntryBitCount = 24;
boolean isAllowedList = true;
+ int suffixTableEntryValueSizeInBytes = 4;
+ int versionNumber = 2;
SatS2RangeFileFormat satS2RangeFileFormat = new SatS2RangeFileFormat(s2Level,
prefixBitCount, suffixBitCount, suffixTableBlockIdOffset, suffixTableEntryBitCount,
- isAllowedList);
+ isAllowedList, suffixTableEntryValueSizeInBytes, versionNumber);
assertEquals(0, satS2RangeFileFormat.extractFaceIdFromPrefix(0b00000000000));
assertEquals(5, satS2RangeFileFormat.extractFaceIdFromPrefix(0b10100000000));
@@ -147,9 +153,11 @@
int suffixTableBlockIdOffset = 5;
int suffixTableEntryBitCount = 24;
boolean isAllowedList = true;
+ int suffixTableEntryValueSizeInBytes = 4;
+ int versionNumber = 2;
SatS2RangeFileFormat satS2RangeFileFormat = new SatS2RangeFileFormat(s2Level,
prefixBitCount, suffixBitCount, suffixTableBlockIdOffset, suffixTableEntryBitCount,
- isAllowedList);
+ isAllowedList, suffixTableEntryValueSizeInBytes, versionNumber);
// Too many bits for rangeLength
assertThrows(IllegalArgumentException.class,
@@ -161,6 +169,33 @@
assertTrue(satS2RangeFileFormat.isAllowedList());
}
+ @Test
+ public void extractEntryValueByteCount() {
+ int s2Level = 12;
+ int prefixBitCount = 11;
+ int suffixBitCount = 16;
+ int suffixTableBlockIdOffset = 5;
+ int suffixTableEntryBitCount = 24;
+ boolean isAllowedList = true;
+ final int[] suffixTableEntryValueSizeInBytes = {5};
+ int versionNumber = 1;
+
+ // Table entry byte count exceeds BYTE range.
+ assertThrows(IllegalArgumentException.class,
+ () -> new SatS2RangeFileFormat(s2Level, prefixBitCount, suffixBitCount,
+ suffixTableBlockIdOffset, suffixTableEntryBitCount, isAllowedList,
+ suffixTableEntryValueSizeInBytes[0], versionNumber));
+
+ suffixTableEntryValueSizeInBytes[0] = 1;
+ SatS2RangeFileFormat satS2RangeFileFormat = new SatS2RangeFileFormat(s2Level,
+ prefixBitCount, suffixBitCount, suffixTableBlockIdOffset, suffixTableEntryBitCount,
+ isAllowedList, suffixTableEntryValueSizeInBytes[0], versionNumber);
+
+ assertEquals(suffixTableEntryValueSizeInBytes[0],
+ satS2RangeFileFormat.getEntryValueSizeInBytes());
+ assertEquals(versionNumber, satS2RangeFileFormat.getVersionNumber());
+ }
+
private static int maxValForBits(int bits) {
return intPow2(bits) - 1;
}
diff --git a/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SuffixTableSharedDataTest.java b/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SuffixTableSharedDataTest.java
index 2baefa9..ee21626 100644
--- a/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SuffixTableSharedDataTest.java
+++ b/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SuffixTableSharedDataTest.java
@@ -18,11 +18,18 @@
import static org.junit.Assert.assertEquals;
+import com.android.storage.block.read.BlockData;
+import com.android.telephony.sats2range.read.SatS2RangeFileFormat;
import com.android.telephony.sats2range.read.SuffixTableSharedData;
import com.android.telephony.sats2range.write.SuffixTableSharedDataWriter;
import org.junit.Test;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
/** Tests for {@link SuffixTableSharedData} and {@link SuffixTableSharedDataWriter}. */
public class SuffixTableSharedDataTest {
@Test
@@ -33,5 +40,106 @@
assertEquals(sharedData, SuffixTableSharedData.fromBytes(bytes));
}
-}
+ @Test
+ public void testSuffixTableSharedDataWithEntryValues() {
+ int prefix = 321;
+ int entryValueSizeInBytes = 1;
+ List<Integer> entryValues = new ArrayList<>(Arrays.asList(0x01, 0x7F, 0xFF));
+ int versionNumber = 1;
+
+ // Verify whether fromTypedData returns correct SuffixTableSharedData when entryByte is 1
+ verifySharedData(prefix, entryValueSizeInBytes, entryValues.size(), entryValues,
+ versionNumber);
+
+ // Verify when entryValueSizeInBytes is 2
+ entryValueSizeInBytes = 2;
+ entryValues = new ArrayList<>(Arrays.asList(0x001, 0x5FFF, 0xAFFF, 0xFFFF));
+ verifySharedData(prefix, entryValueSizeInBytes, entryValues.size(), entryValues,
+ versionNumber);
+
+ // Verify when entryValueSizeInBytes is 3
+ entryValueSizeInBytes = 3;
+ entryValues = new ArrayList<>(
+ Arrays.asList(0x000001, 0x4FFFFF, 0x8FFFFF, 0xBFFFFF, 0xFFFFFF));
+ verifySharedData(prefix, entryValueSizeInBytes, entryValues.size(), entryValues,
+ versionNumber);
+
+ // Verify when entryValueSizeInBytes is 4, max int value is 0x7FFFFFFF.
+ // ConfigID is supported up to 0x7FFFFFFF for now.
+ entryValueSizeInBytes = 4;
+ entryValues = new ArrayList<>(
+ Arrays.asList(0x00000001, 0x2FFFFFFF, 0x3FFFFFFF, 0x4FFFFFFF, 0x5FFFFFFF,
+ 0x6FFFFFFF, 0x7FFFFFFF));
+ verifySharedData(prefix, entryValueSizeInBytes, entryValues.size(), entryValues,
+ versionNumber);
+
+ // Verify when every entry has same value.
+ entryValues = new ArrayList<>(
+ Arrays.asList(0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF,
+ 0x3FFFFFFF, 0x3FFFFFFF));
+ verifySharedData(prefix, entryValueSizeInBytes, entryValues.size(), entryValues,
+ versionNumber);
+
+ // Verify when entry is empty
+ // entryValueSizeInBytes is set as 4, but there is no entry list
+ entryValues = new ArrayList<>(List.of());
+ verifySharedData(prefix, entryValueSizeInBytes, entryValues.size(), entryValues,
+ versionNumber);
+ // entryValueSizeInBytes is 0, no entry list
+ entryValueSizeInBytes = 0;
+ verifySharedData(prefix, entryValueSizeInBytes, entryValues.size(), entryValues,
+ versionNumber);
+ }
+
+ private BlockData createBlockedDataFromByteBuffer(int prefix,
+ List<Integer> entryValues, SatS2RangeFileFormat fileFormat) {
+ SuffixTableSharedData sharedDataToWrite = new SuffixTableSharedData(prefix, entryValues,
+ fileFormat);
+ ByteBuffer byteBuffer = ByteBuffer.wrap(
+ SuffixTableSharedDataWriter.toBytes(sharedDataToWrite));
+ return new BlockData(byteBuffer.asReadOnlyBuffer());
+ }
+
+ private void verifySharedData(int expectedTablePrefix, int expectedEntryValueSizeInBytes,
+ int expectedNumberOfEntryValues, List<Integer> expectedEntryValues, int versionNumber) {
+ SatS2RangeFileFormat fileFormat = createSatS2RangeFileFormat(expectedEntryValueSizeInBytes,
+ versionNumber);
+ BlockData blockData = createBlockedDataFromByteBuffer(
+ expectedTablePrefix, expectedEntryValues, fileFormat);
+ SuffixTableSharedData sharedData = SuffixTableSharedData.fromTypedData(blockData,
+ fileFormat);
+
+ assertEquals(expectedTablePrefix, sharedData.getTablePrefix());
+ if (!expectedEntryValues.isEmpty()) {
+ assertEquals(expectedEntryValueSizeInBytes, sharedData.getEntryValueSizeInBytes());
+ } else {
+ assertEquals(0, sharedData.getEntryValueSizeInBytes());
+ }
+
+ // If every entry has same value, block data contains only 1 entry info
+ if (expectedEntryValues.stream().distinct().count() == 1) {
+ assertEquals(3 * Integer.BYTES, blockData.getSize());
+ // Verify whether the entry value count has been set to 1.
+ assertEquals(1, sharedData.getNumberOfEntryValues());
+ } else {
+ assertEquals(expectedNumberOfEntryValues, sharedData.getNumberOfEntryValues());
+ }
+ for (int i = 0; i < expectedNumberOfEntryValues; i++) {
+ assertEquals((int) expectedEntryValues.get(i), sharedData.getEntryValue(i));
+ }
+ }
+
+ private SatS2RangeFileFormat createSatS2RangeFileFormat(int entryByteCount, int versionNumber) {
+ int s2Level = 12;
+ int prefixBitCount = 11;
+ int suffixBitCount = 16;
+ int suffixTableBlockIdOffset = 5;
+ int suffixTableEntryBitCount = 24;
+ boolean isAllowedList = true;
+
+ return new SatS2RangeFileFormat(s2Level,
+ prefixBitCount, suffixBitCount, suffixTableBlockIdOffset, suffixTableEntryBitCount,
+ isAllowedList, entryByteCount, versionNumber);
+ }
+}
diff --git a/utils/satellite/s2storage/src/write/java/com/android/telephony/sats2range/write/HeaderBlockWriter.java b/utils/satellite/s2storage/src/write/java/com/android/telephony/sats2range/write/HeaderBlockWriter.java
index d4e9310..0435922 100644
--- a/utils/satellite/s2storage/src/write/java/com/android/telephony/sats2range/write/HeaderBlockWriter.java
+++ b/utils/satellite/s2storage/src/write/java/com/android/telephony/sats2range/write/HeaderBlockWriter.java
@@ -63,6 +63,8 @@
tos.writeUnsignedByte(mFileFormat.getSuffixTableBlockIdOffset());
tos.writeUnsignedByte(mFileFormat.isAllowedList()
? HeaderBlock.TRUE : HeaderBlock.FALSE);
+ tos.writeUnsignedByte(mFileFormat.getEntryValueSizeInBytes());
+ tos.writeInt(mFileFormat.getVersionNumber());
}
FileChannel fileChannel = FileChannel.open(mFile.toPath(), StandardOpenOption.READ);
diff --git a/utils/satellite/s2storage/src/write/java/com/android/telephony/sats2range/write/SuffixTableSharedDataWriter.java b/utils/satellite/s2storage/src/write/java/com/android/telephony/sats2range/write/SuffixTableSharedDataWriter.java
index 5499148..a739e5e 100644
--- a/utils/satellite/s2storage/src/write/java/com/android/telephony/sats2range/write/SuffixTableSharedDataWriter.java
+++ b/utils/satellite/s2storage/src/write/java/com/android/telephony/sats2range/write/SuffixTableSharedDataWriter.java
@@ -21,21 +21,37 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.util.List;
/**
* Converts a {@link SuffixTableSharedData} to a byte[] for writing.
* See also {@link SuffixTableSharedData#fromBytes(byte[])}.
*/
public final class SuffixTableSharedDataWriter {
-
+ private static final int BUFFER_SIZE = (int) Math.pow(2, 20);
private SuffixTableSharedDataWriter() {
}
/** Returns the byte[] for the supplied {@link SuffixTableSharedData} */
public static byte[] toBytes(SuffixTableSharedData suffixTableSharedData) {
+ int entryValueSizeInBytes = suffixTableSharedData.getEntryValueSizeInBytes();
+ List<Integer> entryValues = suffixTableSharedData.getEntryValuesToWrite();
+ // If every entry has same value, compress to save memory
+ int numberOfEntryValues =
+ entryValues.stream().distinct().count() == 1 ? 1 : entryValues.size();
+
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
- TypedOutputStream tos = new TypedOutputStream(baos)) {
+ TypedOutputStream tos = new TypedOutputStream(baos, BUFFER_SIZE)) {
tos.writeInt(suffixTableSharedData.getTablePrefix());
+
+ if (entryValueSizeInBytes > 0 && !entryValues.isEmpty()) {
+ tos.writeInt(numberOfEntryValues);
+ for (int i = 0; i < numberOfEntryValues; i++) {
+ // ConfigId is supported up to 0x7FFFFFFF
+ tos.writeVarByteValue(entryValueSizeInBytes, entryValues.get(i));
+ }
+ }
+
tos.flush();
return baos.toByteArray();
} catch (IOException e) {