add storage java reader

Test: atest aconfig_storage_read_api.test.java
Bug: 349874828
Change-Id: I4b1d5ccf4d48622a88712b6e8940ffe18e980927
diff --git a/tools/aconfig/aconfig_storage_read_api/Android.bp b/tools/aconfig/aconfig_storage_read_api/Android.bp
index 5e9eb54..c2f4c18 100644
--- a/tools/aconfig/aconfig_storage_read_api/Android.bp
+++ b/tools/aconfig/aconfig_storage_read_api/Android.bp
@@ -154,7 +154,9 @@
 java_library {
     name: "libaconfig_storage_read_api_java",
     srcs: [
-        "srcs/**/*.java",
+        "srcs/android/aconfig/storage/AconfigStorageReadAPI.java",
+        "srcs/android/aconfig/storage/FlagReadContext.java",
+        "srcs/android/aconfig/storage/PackageReadContext.java",
     ],
     required: ["libaconfig_storage_read_api_rust_jni"],
     min_sdk_version: "UpsideDownCake",
@@ -163,3 +165,14 @@
         "//apex_available:platform",
     ],
 }
+
+java_library {
+    name: "aconfig_storage_reader_java",
+    srcs: [
+        "srcs/android/aconfig/storage/StorageInternalReader.java",
+    ],
+    static_libs: [
+        "aconfig_storage_file_java",
+    ],
+    sdk_version: "core_current",
+}
diff --git a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/StorageInternalReader.java b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/StorageInternalReader.java
new file mode 100644
index 0000000..5f31017
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/StorageInternalReader.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.aconfig.storage;
+
+import java.io.FileInputStream;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+
+public class StorageInternalReader {
+
+    private static final String MAP_PATH = "/metadata/aconfig/maps/";
+    private static final String BOOT_PATH = "/metadata/aconfig/boot/";
+
+    private PackageTable mPackageTable;
+    private FlagValueList mFlagValueList;
+
+    private int mPackageBooleanStartOffset;
+
+    public StorageInternalReader(String container, String packageName) {
+        this(packageName, MAP_PATH + container + ".package.map", BOOT_PATH + container + ".val");
+    }
+
+    public StorageInternalReader(String packageName, String packageMapFile, String flagValueFile) {
+        mPackageTable = PackageTable.fromBytes(mapStorageFile(packageMapFile));
+        mFlagValueList = FlagValueList.fromBytes(mapStorageFile(flagValueFile));
+        mPackageBooleanStartOffset = getPackageBooleanStartOffset(packageName);
+    }
+
+    public boolean getBooleanFlagValue(int index) {
+        index += mPackageBooleanStartOffset;
+        if (index >= mFlagValueList.size()) {
+            throw new AconfigStorageException("Fail to get boolean flag value");
+        }
+        return mFlagValueList.get(index);
+    }
+
+    private int getPackageBooleanStartOffset(String packageName) {
+        PackageTable.Node pNode = mPackageTable.get(packageName);
+        if (pNode == null) {
+            PackageTable.Header header = mPackageTable.getHeader();
+            throw new AconfigStorageException(
+                    String.format(
+                            "Fail to get package %s from container %s",
+                            packageName, header.getContainer()));
+        }
+        return pNode.getBooleanStartIndex();
+    }
+
+    // Map a storage file given file path
+    private static MappedByteBuffer mapStorageFile(String file) {
+        try {
+            FileInputStream stream = new FileInputStream(file);
+            FileChannel channel = stream.getChannel();
+            return channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
+        } catch (Exception e) {
+            throw new AconfigStorageException(
+                    String.format("Fail to mmap storage file %s", file), e);
+        }
+    }
+}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/Android.bp b/tools/aconfig/aconfig_storage_read_api/tests/java/Android.bp
index d94b2b4..11b3824 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/Android.bp
+++ b/tools/aconfig/aconfig_storage_read_api/tests/java/Android.bp
@@ -1,7 +1,8 @@
 android_test {
     name: "aconfig_storage_read_api.test.java",
-    srcs: ["AconfigStorageReadAPITest.java"],
+    srcs: ["./**/*.java"],
     static_libs: [
+        "aconfig_storage_reader_java",
         "androidx.test.rules",
         "libaconfig_storage_read_api_java",
         "junit",
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/StorageInternalReaderTest.java b/tools/aconfig/aconfig_storage_read_api/tests/java/StorageInternalReaderTest.java
new file mode 100644
index 0000000..3a1bba0
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/tests/java/StorageInternalReaderTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.aconfig.storage.test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.aconfig.storage.StorageInternalReader;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class StorageInternalReaderTest {
+
+    private String mStorageDir = "/data/local/tmp/aconfig_java_api_test";
+
+    @Test
+    public void testStorageInternalReader_getFlag() {
+
+        String packageMapFile = mStorageDir + "/maps/mockup.package.map";
+        String flagValueFile = mStorageDir + "/boot/mockup.val";
+
+        StorageInternalReader reader =
+                new StorageInternalReader(
+                        "com.android.aconfig.storage.test_1", packageMapFile, flagValueFile);
+        assertFalse(reader.getBooleanFlagValue(0));
+        assertTrue(reader.getBooleanFlagValue(1));
+    }
+}