Merge "add PlatformAconfigPackageInternal" into main am: 7b4c46e493
Original change: https://android-review.googlesource.com/c/platform/build/+/3357058
Change-Id: I31e806437e260303b7d4e0c18e5a6f25add5954f
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/AconfigStorageException.java b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/AconfigStorageException.java
index b1c7ee7..324c55d 100644
--- a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/AconfigStorageException.java
+++ b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/AconfigStorageException.java
@@ -39,6 +39,8 @@
/** Error code indicating that there was an error reading the Aconfig Storage file. */
public static final int ERROR_CANNOT_READ_STORAGE_FILE = 4;
+ public static final int ERROR_FILE_FINGERPRINT_MISMATCH = 5;
+
private final int mErrorCode;
/**
@@ -126,6 +128,8 @@
return "ERROR_CONTAINER_NOT_FOUND";
case ERROR_CANNOT_READ_STORAGE_FILE:
return "ERROR_CANNOT_READ_STORAGE_FILE";
+ case ERROR_FILE_FINGERPRINT_MISMATCH:
+ return "ERROR_FILE_FINGERPRINT_MISMATCH";
default:
return "<Unknown error code " + mErrorCode + ">";
}
diff --git a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/FileType.java b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/FileType.java
index b0b1b9b..c354873 100644
--- a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/FileType.java
+++ b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/FileType.java
@@ -42,4 +42,20 @@
return null;
}
}
+
+ @Override
+ public String toString() {
+ switch (type) {
+ case 0:
+ return "PACKAGE_MAP";
+ case 1:
+ return "FLAG_MAP";
+ case 2:
+ return "FLAG_VAL";
+ case 3:
+ return "FLAG_INFO";
+ default:
+ return "unrecognized type";
+ }
+ }
}
diff --git a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/StorageFileProvider.java b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/StorageFileProvider.java
index 8306cc6..f1a4e26 100644
--- a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/StorageFileProvider.java
+++ b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/StorageFileProvider.java
@@ -26,7 +26,10 @@
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/** @hide */
public class StorageFileProvider {
@@ -52,13 +55,20 @@
}
/** @hide */
- public List<Path> listPackageMapFiles() {
- List<Path> result = new ArrayList<>();
+ public List<String> listContainers(String[] excludes) {
+ List<String> result = new ArrayList<>();
+ Set<String> set = new HashSet<>(Arrays.asList(excludes));
+
try {
DirectoryStream<Path> stream =
Files.newDirectoryStream(Paths.get(mMapPath), "*" + PMAP_FILE_EXT);
for (Path entry : stream) {
- result.add(entry);
+ String fileName = entry.getFileName().toString();
+ String container =
+ fileName.substring(0, fileName.length() - PMAP_FILE_EXT.length());
+ if (!set.contains(container)) {
+ result.add(container);
+ }
}
} catch (NoSuchFileException e) {
return result;
@@ -77,22 +87,23 @@
/** @hide */
public FlagTable getFlagTable(String container) {
- return FlagTable.fromBytes(mapStorageFile(Paths.get(mMapPath, container + FMAP_FILE_EXT)));
+ return FlagTable.fromBytes(
+ mapStorageFile(Paths.get(mMapPath, container + FMAP_FILE_EXT), FileType.FLAG_MAP));
}
/** @hide */
public FlagValueList getFlagValueList(String container) {
return FlagValueList.fromBytes(
- mapStorageFile(Paths.get(mBootPath, container + VAL_FILE_EXT)));
+ mapStorageFile(Paths.get(mBootPath, container + VAL_FILE_EXT), FileType.FLAG_VAL));
}
/** @hide */
public static PackageTable getPackageTable(Path path) {
- return PackageTable.fromBytes(mapStorageFile(path));
+ return PackageTable.fromBytes(mapStorageFile(path, FileType.PACKAGE_MAP));
}
// Map a storage file given file path
- private static MappedByteBuffer mapStorageFile(Path file) {
+ private static MappedByteBuffer mapStorageFile(Path file, FileType type) {
FileChannel channel = null;
try {
channel = FileChannel.open(file, StandardOpenOption.READ);
@@ -100,7 +111,7 @@
} catch (Exception e) {
throw new AconfigStorageException(
AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
- String.format("Fail to mmap storage file %s", file),
+ String.format("Fail to mmap storage %s file %s", type.toString(), file),
e);
} finally {
quietlyDispose(channel);
diff --git a/tools/aconfig/aconfig_storage_file/tests/srcs/StorageFileProviderTest.java b/tools/aconfig/aconfig_storage_file/tests/srcs/StorageFileProviderTest.java
index 4e90e6c..a820970 100644
--- a/tools/aconfig/aconfig_storage_file/tests/srcs/StorageFileProviderTest.java
+++ b/tools/aconfig/aconfig_storage_file/tests/srcs/StorageFileProviderTest.java
@@ -29,7 +29,6 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
@@ -37,15 +36,20 @@
public class StorageFileProviderTest {
@Test
- public void testListpackageMapFiles() throws Exception {
+ public void testlistContainers() throws Exception {
StorageFileProvider p =
new StorageFileProvider(TestDataUtils.TESTDATA_PATH, TestDataUtils.TESTDATA_PATH);
- List<Path> file = p.listPackageMapFiles();
- assertEquals(2, file.size());
+ String[] excludes = {};
+ List<String> containers = p.listContainers(excludes);
+ assertEquals(2, containers.size());
+
+ excludes = new String[] {"mock.v1"};
+ containers = p.listContainers(excludes);
+ assertEquals(1, containers.size());
p = new StorageFileProvider("fake/path/", "fake/path/");
- file = p.listPackageMapFiles();
- assertTrue(file.isEmpty());
+ containers = p.listContainers(excludes);
+ assertTrue(containers.isEmpty());
}
@Test
@@ -56,8 +60,7 @@
assertNotNull(pt);
pt =
StorageFileProvider.getPackageTable(
- Paths.get(
- TestDataUtils.TESTDATA_PATH, "mock.v1.package.map"));
+ Paths.get(TestDataUtils.TESTDATA_PATH, "mock.v1.package.map"));
assertNotNull(pt);
FlagTable f = p.getFlagTable("mock.v1");
assertNotNull(f);
diff --git a/tools/aconfig/aconfig_storage_read_api/Android.bp b/tools/aconfig/aconfig_storage_read_api/Android.bp
index 3238d79..09daeea 100644
--- a/tools/aconfig/aconfig_storage_read_api/Android.bp
+++ b/tools/aconfig/aconfig_storage_read_api/Android.bp
@@ -154,12 +154,13 @@
java_library {
name: "aconfig_storage_reader_java",
srcs: [
- "srcs/android/aconfig/storage/AconfigPackageImpl.java",
"srcs/android/aconfig/storage/StorageInternalReader.java",
+ "srcs/android/os/flagging/PlatformAconfigPackageInternal.java",
],
libs: [
"unsupportedappusage",
"strict_mode_stub",
+ "aconfig_storage_stub",
],
static_libs: [
"aconfig_storage_file_java",
@@ -176,8 +177,8 @@
java_library {
name: "aconfig_storage_reader_java_none",
srcs: [
- "srcs/android/aconfig/storage/AconfigPackageImpl.java",
"srcs/android/aconfig/storage/StorageInternalReader.java",
+ "srcs/android/os/flagging/PlatformAconfigPackageInternal.java",
],
libs: [
"unsupportedappusage-sdk-none",
diff --git a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/AconfigPackageImpl.java b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/AconfigPackageImpl.java
deleted file mode 100644
index 6bf4e05..0000000
--- a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/AconfigPackageImpl.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * 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 android.os.StrictMode;
-
-import java.nio.file.Path;
-
-/** @hide */
-public class AconfigPackageImpl {
- private FlagTable mFlagTable;
- private FlagValueList mFlagValueList;
- private PackageTable.Node mPNode;
- private final int mPackageId;
- private final int mBooleanStartIndex;
-
- private AconfigPackageImpl(
- FlagTable flagTable,
- FlagValueList flagValueList,
- int packageId,
- int booleanStartIndex) {
- this.mFlagTable = flagTable;
- this.mFlagValueList = flagValueList;
- this.mPackageId = packageId;
- this.mBooleanStartIndex = booleanStartIndex;
- }
-
- public static AconfigPackageImpl load(String packageName, StorageFileProvider fileProvider) {
- StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
- PackageTable.Node pNode = null;
- try {
- // First try to find the package in the "system" container.
- pNode = fileProvider.getPackageTable("system").get(packageName);
- } catch (Exception e) {
- //
- }
- try {
- if (pNode != null) {
- return new AconfigPackageImpl(
- fileProvider.getFlagTable("system"),
- fileProvider.getFlagValueList("system"),
- pNode.getPackageId(),
- pNode.getBooleanStartIndex());
- }
-
- // If not found in "system", search all package map files.
- for (Path p : fileProvider.listPackageMapFiles()) {
- PackageTable pTable = fileProvider.getPackageTable(p);
- pNode = pTable.get(packageName);
- if (pNode != null) {
- return new AconfigPackageImpl(
- fileProvider.getFlagTable(pTable.getHeader().getContainer()),
- fileProvider.getFlagValueList(pTable.getHeader().getContainer()),
- pNode.getPackageId(),
- pNode.getBooleanStartIndex());
- }
- }
- } catch (AconfigStorageException e) {
- // Consider logging the exception.
- throw e;
- } finally {
- StrictMode.setThreadPolicy(oldPolicy);
- }
- // Package not found.
- throw new AconfigStorageException(
- AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
- "Package " + packageName + " not found.");
- }
-
- public static AconfigPackageImpl load(
- String container, String packageName, StorageFileProvider fileProvider) {
-
- StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
- try {
- PackageTable.Node pNode = fileProvider.getPackageTable(container).get(packageName);
- if (pNode != null) {
- return new AconfigPackageImpl(
- fileProvider.getFlagTable(container),
- fileProvider.getFlagValueList(container),
- pNode.getPackageId(),
- pNode.getBooleanStartIndex());
- }
- } catch (AconfigStorageException e) {
- // Consider logging the exception.
- throw e;
- } finally {
- StrictMode.setThreadPolicy(oldPolicy);
- }
-
- throw new AconfigStorageException(
- AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
- "package "
- + packageName
- + " in container "
- + container
- + " cannot be found on the device");
- }
-
- public boolean getBooleanFlagValue(String flagName, boolean defaultValue) {
- FlagTable.Node fNode = mFlagTable.get(mPackageId, flagName);
- if (fNode == null) return defaultValue;
- return mFlagValueList.getBoolean(fNode.getFlagIndex() + mBooleanStartIndex);
- }
-
- public boolean getBooleanFlagValue(int index) {
- return mFlagValueList.getBoolean(index + mBooleanStartIndex);
- }
-}
diff --git a/tools/aconfig/aconfig_storage_read_api/srcs/android/os/flagging/PlatformAconfigPackageInternal.java b/tools/aconfig/aconfig_storage_read_api/srcs/android/os/flagging/PlatformAconfigPackageInternal.java
new file mode 100644
index 0000000..83310be
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/srcs/android/os/flagging/PlatformAconfigPackageInternal.java
@@ -0,0 +1,264 @@
+/*
+ * 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.os.flagging;
+
+import android.aconfig.storage.AconfigStorageException;
+import android.aconfig.storage.FlagTable;
+import android.aconfig.storage.FlagValueList;
+import android.aconfig.storage.PackageTable;
+import android.aconfig.storage.StorageFileProvider;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.os.StrictMode;
+
+/**
+ * An {@code aconfig} package containing the enabled state of its flags.
+ *
+ * <p><strong>Note: this is intended only to be used by generated code. To determine if a given flag
+ * is enabled in app code, the generated android flags should be used.</strong>
+ *
+ * <p>This class is not part of the public API and should be used by Acnofig Flag internally </b> It
+ * is intended for internal use only and will be changed or removed without notice.
+ *
+ * <p>This class is used to read the flag from Aconfig Package.Each instance of this class will
+ * cache information related to one package. To read flags from a different package, a new instance
+ * of this class should be {@link #load loaded}.
+ *
+ * @hide
+ */
+public class PlatformAconfigPackageInternal {
+
+ private final FlagTable mFlagTable;
+ private final FlagValueList mFlagValueList;
+ private final int mPackageId;
+ private final int mPackageBooleanStartOffset;
+ private final AconfigStorageException mException;
+
+ private PlatformAconfigPackageInternal(
+ FlagValueList flagValueList,
+ FlagTable flagTable,
+ int packageBooleanStartOffset,
+ int packageId,
+ AconfigStorageException exception) {
+ this.mFlagValueList = flagValueList;
+ this.mFlagTable = flagTable;
+ this.mPackageBooleanStartOffset = packageBooleanStartOffset;
+ this.mPackageId = packageId;
+ this.mException = exception;
+ }
+
+ /**
+ * Loads an Aconfig Package from platform Aconfig Storage.
+ *
+ * <p>This method is intended for internal use only and may be changed or removed without
+ * notice.
+ *
+ * <p>This method loads the specified Aconfig Package from the given container.
+ *
+ * <p>AconfigStorageException will be stored if there is an error reading from Aconfig Storage.
+ * The specific error code can be got using {@link #getException()}.
+ *
+ * @param container The name of the container.
+ * @param packageName The name of the Aconfig package to load.
+ * @return An instance of {@link PlatformAconfigPackageInternal}
+ * @hide
+ */
+ @UnsupportedAppUsage
+ public static PlatformAconfigPackageInternal load(String container, String packageName) {
+ return load(container, packageName, StorageFileProvider.getDefaultProvider());
+ }
+
+ /** @hide */
+ public static PlatformAconfigPackageInternal load(
+ String container, String packageName, StorageFileProvider fileProvider) {
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+ try {
+ PackageTable.Node pNode = fileProvider.getPackageTable(container).get(packageName);
+
+ if (pNode == null) {
+ return createExceptionInstance(
+ AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
+ "package "
+ + packageName
+ + " in container "
+ + container
+ + " cannot be found on the device");
+ }
+
+ return new PlatformAconfigPackageInternal(
+ fileProvider.getFlagValueList(container),
+ fileProvider.getFlagTable(container),
+ pNode.getBooleanStartIndex(),
+ pNode.getPackageId(),
+ null);
+
+ } catch (AconfigStorageException e) {
+ return createExceptionInstance(e.getErrorCode(), e.getMessage());
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
+ }
+ }
+
+ /**
+ * Loads an Aconfig package from the specified container and verifies its fingerprint.
+ *
+ * <p>This method is intended for internal use only and may be changed or removed without
+ * notice.
+ *
+ * <p>AconfigStorageException will be stored if there is an error reading from Aconfig Storage.
+ * The specific error code can be got using {@link #getException()}.
+ *
+ * @param container The name of the container.
+ * @param packageName The name of the Aconfig package.
+ * @param packageFingerprint The expected fingerprint of the package.
+ * @return An instance of {@link PlatformAconfigPackageInternal} representing the loaded
+ * package.
+ * @hide
+ */
+ @UnsupportedAppUsage
+ public static PlatformAconfigPackageInternal load(
+ String container, String packageName, long packageFingerprint) {
+ return load(
+ container,
+ packageName,
+ packageFingerprint,
+ StorageFileProvider.getDefaultProvider());
+ }
+
+ /** @hide */
+ public static PlatformAconfigPackageInternal load(
+ String container,
+ String packageName,
+ long packageFingerprint,
+ StorageFileProvider fileProvider) {
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+ try {
+ PackageTable.Node pNode = fileProvider.getPackageTable(container).get(packageName);
+
+ if (pNode == null) {
+ return createExceptionInstance(
+ AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
+ "package "
+ + packageName
+ + " in container "
+ + container
+ + " cannot be found on the device");
+ }
+
+ if (pNode.hasPackageFingerprint()
+ && packageFingerprint != pNode.getPackageFingerprint()) {
+ return new PlatformAconfigPackageInternal(
+ fileProvider.getFlagValueList(container),
+ fileProvider.getFlagTable(container),
+ pNode.getBooleanStartIndex(),
+ pNode.getPackageId(),
+ new AconfigStorageException(
+ AconfigStorageException.ERROR_FILE_FINGERPRINT_MISMATCH,
+ "The fingerprint provided for the Aconfig package "
+ + packageName
+ + " in container "
+ + container
+ + " does not match"
+ + " the fingerprint of the package found on the device."));
+ }
+
+ return new PlatformAconfigPackageInternal(
+ fileProvider.getFlagValueList(container),
+ null,
+ pNode.getBooleanStartIndex(),
+ 0,
+ null);
+
+ } catch (AconfigStorageException e) {
+ return createExceptionInstance(e.getErrorCode(), e.getMessage());
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
+ }
+ }
+
+ /**
+ * Retrieves the value of a boolean flag using its index.
+ *
+ * <p>This method is intended for internal use only and may be changed or removed without
+ * notice.
+ *
+ * <p>This method retrieves the value of a flag within the loaded Aconfig package using its
+ * index. The index is generated at build time and may vary between builds.
+ *
+ * <p>To ensure you are using the correct index, verify that the package's fingerprint matches
+ * the expected fingerprint before calling this method. If the fingerprints do not match, use
+ * {@link #getBooleanFlagValue(String, boolean)} instead.
+ *
+ * @param index The index of the flag within the package.
+ * @return The boolean value of the flag.
+ * @hide
+ */
+ @UnsupportedAppUsage
+ public boolean getBooleanFlagValue(int index) {
+ return mFlagValueList.getBoolean(index + mPackageBooleanStartOffset);
+ }
+
+ /**
+ * Retrieves the value of a boolean flag using its name.
+ *
+ * <p>This method is intended for internal use only and may be changed or removed without
+ * notice.
+ *
+ * <p>This method retrieves the value of a flag within the loaded Aconfig package using its
+ * name.
+ *
+ * @param flagName The name of the flag.
+ * @param defaultValue The default value to return if the flag is not found.
+ * @return The boolean value of the flag.
+ * @hide
+ */
+ @UnsupportedAppUsage
+ public boolean getBooleanFlagValue(String flagName, boolean defaultValue) {
+ FlagTable.Node fNode = mFlagTable.get(mPackageId, flagName);
+ if (fNode == null) {
+ return defaultValue;
+ }
+ return mFlagValueList.getBoolean(fNode.getFlagIndex() + mPackageBooleanStartOffset);
+ }
+
+ /**
+ * Returns any exception that occurred during the loading of the Aconfig package.
+ *
+ * <p>This method is intended for internal use only and may be changed or removed without
+ * notice.
+ *
+ * @return The exception that occurred, or {@code null} if no exception occurred.
+ * @hide
+ */
+ @UnsupportedAppUsage
+ public Exception getException() {
+ return mException;
+ }
+
+ /**
+ * Creates a new {@link PlatformAconfigPackageInternal} instance with an {@link
+ * AconfigStorageException}.
+ *
+ * @param errorCode The error code for the exception.
+ * @param message The error message for the exception.
+ * @return A new {@link PlatformAconfigPackageInternal} instance with the specified exception.
+ */
+ private static PlatformAconfigPackageInternal createExceptionInstance(
+ int errorCode, String message) {
+ return new PlatformAconfigPackageInternal(
+ null, null, 0, 0, new AconfigStorageException(errorCode, message));
+ }
+}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidTest.xml b/tools/aconfig/aconfig_storage_read_api/tests/AconfigStorageReadFunctionalTest.xml
similarity index 95%
rename from tools/aconfig/aconfig_storage_read_api/tests/java/AndroidTest.xml
rename to tools/aconfig/aconfig_storage_read_api/tests/AconfigStorageReadFunctionalTest.xml
index 7ffa18c..ee50060 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidTest.xml
+++ b/tools/aconfig/aconfig_storage_read_api/tests/AconfigStorageReadFunctionalTest.xml
@@ -26,7 +26,7 @@
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
- <option name="test-file-name" value="aconfig_storage_read_api.test.java.apk" />
+ <option name="test-file-name" value="aconfig_storage_read_functional.apk" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.DisableSELinuxTargetPreparer" />
@@ -45,7 +45,7 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
- <option name="package" value="android.aconfig_storage.test" />
+ <option name="package" value="android.aconfig.storage.test" />
<option name="runtime-hint" value="1m" />
</test>
-</configuration>
+</configuration>
\ No newline at end of file
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidStorageJaveTest.xml b/tools/aconfig/aconfig_storage_read_api/tests/AconfigStorageReadUnitTest.xml
similarity index 69%
rename from tools/aconfig/aconfig_storage_read_api/tests/java/AndroidStorageJaveTest.xml
rename to tools/aconfig/aconfig_storage_read_api/tests/AconfigStorageReadUnitTest.xml
index 861b9b5..e528dd5 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidStorageJaveTest.xml
+++ b/tools/aconfig/aconfig_storage_read_api/tests/AconfigStorageReadUnitTest.xml
@@ -17,15 +17,15 @@
<configuration description="Test aconfig storage java tests">
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
- <option name="test-file-name" value="aconfig_storage_package.apk" />
+ <option name="test-file-name" value="aconfig_storage_read_unit.apk" />
</target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
<option name="cleanup" value="true" />
- <option name="push" value="package_v1.map->/data/local/tmp/aconfig_storage_package/testdata/mockup.package.map" />
- <option name="push" value="flag_v1.map->/data/local/tmp/aconfig_storage_package/testdata/mockup.flag.map" />
- <option name="push" value="flag_v1.val->/data/local/tmp/aconfig_storage_package/testdata/mockup.val" />
- <option name="push" value="flag_v1.info->/data/local/tmp/aconfig_storage_package/testdata/mockup.info" />
- <option name="post-push" value="chmod +r /data/local/tmp/aconfig_storage_package/testdata/" />
+ <option name="push" value="package_v2.map->/data/local/tmp/aconfig_storage_read_unit/testdata/mockup.package.map" />
+ <option name="push" value="flag_v2.map->/data/local/tmp/aconfig_storage_read_unit/testdata/mockup.flag.map" />
+ <option name="push" value="flag_v2.val->/data/local/tmp/aconfig_storage_read_unit/testdata/mockup.val" />
+ <option name="push" value="flag_v2.info->/data/local/tmp/aconfig_storage_read_unit/testdata/mockup.info" />
+ <option name="post-push" value="chmod +r /data/local/tmp/aconfig_storage_read_unit/testdata/" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.aconfig.storage.test" />
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/Android.bp b/tools/aconfig/aconfig_storage_read_api/tests/Android.bp
index 6b8942b..fb2fc77 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/Android.bp
+++ b/tools/aconfig/aconfig_storage_read_api/tests/Android.bp
@@ -48,3 +48,53 @@
"general-tests",
],
}
+
+android_test {
+ name: "aconfig_storage_read_functional",
+ srcs: [
+ "functional/srcs/**/*.java",
+ ],
+ static_libs: [
+ "aconfig_device_paths_java",
+ "aconfig_storage_file_java",
+ "aconfig_storage_reader_java",
+ "androidx.test.rules",
+ "libaconfig_storage_read_api_java",
+ "junit",
+ ],
+ jni_libs: [
+ "libaconfig_storage_read_api_rust_jni",
+ ],
+ data: [
+ ":read_api_test_storage_files",
+ ],
+ platform_apis: true,
+ certificate: "platform",
+ test_suites: [
+ "general-tests",
+ ],
+ test_config: "AconfigStorageReadFunctionalTest.xml",
+ team: "trendy_team_android_core_experiments",
+}
+
+android_test {
+ name: "aconfig_storage_read_unit",
+ team: "trendy_team_android_core_experiments",
+ srcs: [
+ "unit/srcs/**/*.java",
+ ],
+ static_libs: [
+ "androidx.test.runner",
+ "junit",
+ "aconfig_storage_reader_java",
+ ],
+ sdk_version: "test_current",
+ data: [
+ ":read_api_test_storage_files",
+ ],
+ test_suites: [
+ "general-tests",
+ ],
+ test_config: "AconfigStorageReadUnitTest.xml",
+ jarjar_rules: "jarjar.txt",
+}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidPackageTestManifest.xml b/tools/aconfig/aconfig_storage_read_api/tests/AndroidManifest.xml
similarity index 100%
rename from tools/aconfig/aconfig_storage_read_api/tests/java/AndroidPackageTestManifest.xml
rename to tools/aconfig/aconfig_storage_read_api/tests/AndroidManifest.xml
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigStorageReadAPITest.java b/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/AconfigStorageReadAPITest.java
similarity index 99%
rename from tools/aconfig/aconfig_storage_read_api/tests/java/AconfigStorageReadAPITest.java
rename to tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/AconfigStorageReadAPITest.java
index 191741e..6dd1bce 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigStorageReadAPITest.java
+++ b/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/AconfigStorageReadAPITest.java
@@ -267,4 +267,4 @@
assertEquals(rVal, jVal);
}
}
-}
+}
\ No newline at end of file
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/PlatformAconfigPackageInternalTest.java b/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/PlatformAconfigPackageInternalTest.java
new file mode 100644
index 0000000..15cfc3b
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/PlatformAconfigPackageInternalTest.java
@@ -0,0 +1,155 @@
+/*
+ * 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 android.aconfig.nano.Aconfig.ENABLED;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import android.aconfig.DeviceProtos;
+import android.aconfig.nano.Aconfig.parsed_flag;
+import android.aconfig.storage.AconfigStorageException;
+import android.aconfig.storage.FlagTable;
+import android.aconfig.storage.FlagValueList;
+import android.aconfig.storage.PackageTable;
+import android.aconfig.storage.StorageFileProvider;
+import android.os.flagging.PlatformAconfigPackageInternal;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+@RunWith(JUnit4.class)
+public class PlatformAconfigPackageInternalTest {
+
+ private static final Set<String> PLATFORM_CONTAINERS = Set.of("system", "vendor", "product");
+
+ @Test
+ public void testAconfigPackageInternal_load() throws IOException {
+ List<parsed_flag> flags = DeviceProtos.loadAndParseFlagProtos();
+ Map<String, PlatformAconfigPackageInternal> readerMap = new HashMap<>();
+ StorageFileProvider fp = StorageFileProvider.getDefaultProvider();
+
+ for (parsed_flag flag : flags) {
+
+ String container = flag.container;
+ String packageName = flag.package_;
+ String flagName = flag.name;
+ if (!PLATFORM_CONTAINERS.contains(container)) continue;
+
+ PackageTable pTable = fp.getPackageTable(container);
+ PackageTable.Node pNode = pTable.get(packageName);
+ FlagTable fTable = fp.getFlagTable(container);
+ FlagTable.Node fNode = fTable.get(pNode.getPackageId(), flagName);
+ FlagValueList fList = fp.getFlagValueList(container);
+
+ int index = pNode.getBooleanStartIndex() + fNode.getFlagIndex();
+ boolean rVal = fList.getBoolean(index);
+
+ PlatformAconfigPackageInternal reader = readerMap.get(packageName);
+ if (reader == null) {
+ reader = PlatformAconfigPackageInternal.load(container, packageName);
+ assertNull(reader.getException());
+ readerMap.put(packageName, reader);
+ }
+ boolean jVal = reader.getBooleanFlagValue(flagName, !rVal);
+
+ assertEquals(rVal, jVal);
+ }
+ }
+
+ @Test
+ public void testPlatformAconfigPackageInternal_load_with_fingerprint() throws IOException {
+ List<parsed_flag> flags = DeviceProtos.loadAndParseFlagProtos();
+ Map<String, PlatformAconfigPackageInternal> readerMap = new HashMap<>();
+ StorageFileProvider fp = StorageFileProvider.getDefaultProvider();
+
+ for (parsed_flag flag : flags) {
+
+ String container = flag.container;
+ String packageName = flag.package_;
+ String flagName = flag.name;
+ if (!PLATFORM_CONTAINERS.contains(container)) continue;
+
+ PackageTable pTable = fp.getPackageTable(container);
+ PackageTable.Node pNode = pTable.get(packageName);
+ FlagTable fTable = fp.getFlagTable(container);
+ FlagTable.Node fNode = fTable.get(pNode.getPackageId(), flagName);
+ FlagValueList fList = fp.getFlagValueList(container);
+
+ int index = pNode.getBooleanStartIndex() + fNode.getFlagIndex();
+ boolean rVal = fList.getBoolean(index);
+
+ long fingerprint = pNode.getPackageFingerprint();
+
+ PlatformAconfigPackageInternal reader = readerMap.get(packageName);
+ if (reader == null) {
+ reader = PlatformAconfigPackageInternal.load(container, packageName, fingerprint);
+ assertNull(reader.getException());
+ readerMap.put(packageName, reader);
+ }
+ boolean jVal = reader.getBooleanFlagValue(fNode.getFlagIndex());
+
+ assertEquals(rVal, jVal);
+ }
+ }
+
+ @Test
+ public void testAconfigPackage_load_withError() throws IOException {
+ // container not found fake_container
+ PlatformAconfigPackageInternal aPackage =
+ PlatformAconfigPackageInternal.load("fake_container", "fake_package", 0);
+ assertEquals(
+ AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+ ((AconfigStorageException) aPackage.getException()).getErrorCode());
+
+ // package not found
+ aPackage = PlatformAconfigPackageInternal.load("system", "fake_container", 0);
+ assertEquals(
+ AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
+ ((AconfigStorageException) aPackage.getException()).getErrorCode());
+
+ // fingerprint doesn't match
+ List<parsed_flag> flags = DeviceProtos.loadAndParseFlagProtos();
+ StorageFileProvider fp = StorageFileProvider.getDefaultProvider();
+
+ parsed_flag flag = flags.get(0);
+
+ String container = flag.container;
+ String packageName = flag.package_;
+ boolean value = flag.state == ENABLED;
+
+ PackageTable pTable = fp.getPackageTable(container);
+ PackageTable.Node pNode = pTable.get(packageName);
+
+ if (pNode.hasPackageFingerprint()) {
+ long fingerprint = pNode.getPackageFingerprint();
+ aPackage = PlatformAconfigPackageInternal.load(container, packageName, fingerprint + 1);
+ assertEquals(
+ // AconfigStorageException.ERROR_FILE_FINGERPRINT_MISMATCH,
+ 5, ((AconfigStorageException) aPackage.getException()).getErrorCode());
+ assertEquals(aPackage.getBooleanFlagValue(flag.name, !value), value);
+ }
+ }
+}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/StorageInternalReaderTest.java b/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/StorageInternalReaderTest.java
similarity index 99%
rename from tools/aconfig/aconfig_storage_read_api/tests/java/StorageInternalReaderTest.java
rename to tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/StorageInternalReaderTest.java
index 3a1bba0..8a8f054 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/StorageInternalReaderTest.java
+++ b/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/StorageInternalReaderTest.java
@@ -42,4 +42,4 @@
assertFalse(reader.getBooleanFlagValue(0));
assertTrue(reader.getBooleanFlagValue(1));
}
-}
+}
\ No newline at end of file
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/jarjar.txt b/tools/aconfig/aconfig_storage_read_api/tests/jarjar.txt
similarity index 91%
rename from tools/aconfig/aconfig_storage_read_api/tests/java/jarjar.txt
rename to tools/aconfig/aconfig_storage_read_api/tests/jarjar.txt
index 24952ec..49250d4 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/jarjar.txt
+++ b/tools/aconfig/aconfig_storage_read_api/tests/jarjar.txt
@@ -15,3 +15,5 @@
rule android.aconfig.storage.PackageTable$* android.aconfig.storage.test.PackageTable$@1
rule android.aconfig.storage.FlagValueList$* android.aconfig.storage.test.FlagValueList@1
rule android.aconfig.storage.SipHasher13$* android.aconfig.storage.test.SipHasher13@1
+
+rule android.os.flagging.PlatformAconfigPackageInternal android.aconfig.storage.test.PlatformAconfigPackageInternal
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigPackageImplTest.java b/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigPackageImplTest.java
deleted file mode 100644
index 80c0994..0000000
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigPackageImplTest.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * 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.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThrows;
-import static org.junit.Assert.assertTrue;
-
-import android.aconfig.storage.AconfigPackageImpl;
-import android.aconfig.storage.AconfigStorageException;
-import android.aconfig.storage.StorageFileProvider;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class AconfigPackageImplTest {
-
- private StorageFileProvider pr;
-
- @Before
- public void setup() {
- pr = new StorageFileProvider(TestDataUtils.TESTDATA_PATH, TestDataUtils.TESTDATA_PATH);
- }
-
- @Test
- public void testLoad_onlyPackageName() throws Exception {
- AconfigPackageImpl p = AconfigPackageImpl.load("com.android.aconfig.storage.test_1", pr);
- assertNotNull(p);
- }
-
- @Test
- public void testLoad_groupNameFingerprint() throws Exception {
- AconfigPackageImpl p =
- AconfigPackageImpl.load("mockup", "com.android.aconfig.storage.test_1", pr);
- assertNotNull(p);
- }
-
- @Test
- public void testLoad_error() throws Exception {
- AconfigPackageImpl p;
- // cannot find package
- AconfigStorageException e =
- assertThrows(
- AconfigStorageException.class,
- () ->
- AconfigPackageImpl.load(
- "mockup", "com.android.aconfig.storage.test_10", pr));
- assertEquals(AconfigStorageException.ERROR_PACKAGE_NOT_FOUND, e.getErrorCode());
- // cannot find package
- e =
- assertThrows(
- AconfigStorageException.class,
- () -> AconfigPackageImpl.load("com.android.aconfig.storage.test_10", pr));
- assertEquals(AconfigStorageException.ERROR_PACKAGE_NOT_FOUND, e.getErrorCode());
- // cannot find container
- e =
- assertThrows(
- AconfigStorageException.class,
- () ->
- AconfigPackageImpl.load(
- null, "com.android.aconfig.storage.test_1", pr));
- assertEquals(AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE, e.getErrorCode());
- e =
- assertThrows(
- AconfigStorageException.class,
- () ->
- AconfigPackageImpl.load(
- "test", "com.android.aconfig.storage.test_1", pr));
- assertEquals(AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE, e.getErrorCode());
-
- // new storage doesn't exist
- pr = new StorageFileProvider("fake/path/", "fake/path/");
- e =
- assertThrows(
- AconfigStorageException.class,
- () -> AconfigPackageImpl.load("fake_package", pr));
- assertEquals(AconfigStorageException.ERROR_PACKAGE_NOT_FOUND, e.getErrorCode());
-
- // file read issue
- pr = new StorageFileProvider(TestDataUtils.TESTDATA_PATH, "fake/path/");
- e =
- assertThrows(
- AconfigStorageException.class,
- () ->
- AconfigPackageImpl.load(
- "mockup", "com.android.aconfig.storage.test_1", pr));
- assertEquals(AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE, e.getErrorCode());
- }
-
- @Test
- public void testGetBooleanFlagValue_flagName() throws Exception {
- AconfigPackageImpl p =
- AconfigPackageImpl.load("mockup", "com.android.aconfig.storage.test_1", pr);
- assertFalse(p.getBooleanFlagValue("disabled_rw", true));
- assertTrue(p.getBooleanFlagValue("enabled_ro", false));
- assertTrue(p.getBooleanFlagValue("enabled_rw", false));
- assertFalse(p.getBooleanFlagValue("fake", false));
- }
-
- @Test
- public void testGetBooleanFlagValue_index() throws Exception {
- AconfigPackageImpl p =
- AconfigPackageImpl.load("mockup", "com.android.aconfig.storage.test_1", pr);
- assertFalse(p.getBooleanFlagValue(0));
- assertTrue(p.getBooleanFlagValue(1));
- assertTrue(p.getBooleanFlagValue(2));
- }
-}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/Android.bp b/tools/aconfig/aconfig_storage_read_api/tests/java/Android.bp
deleted file mode 100644
index 0de34a6..0000000
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/Android.bp
+++ /dev/null
@@ -1,48 +0,0 @@
-android_test {
- name: "aconfig_storage_read_api.test.java",
- srcs: ["./**/*.java"],
- static_libs: [
- "aconfig_device_paths_java",
- "aconfig_storage_file_java",
- "aconfig_storage_reader_java",
- "androidx.test.rules",
- "libaconfig_storage_read_api_java",
- "junit",
- ],
- jni_libs: [
- "libaconfig_storage_read_api_rust_jni",
- ],
- data: [
- ":read_api_test_storage_files",
- ],
- platform_apis: true,
- certificate: "platform",
- test_suites: [
- "general-tests",
- ],
- team: "trendy_team_android_core_experiments",
-}
-
-android_test {
- name: "aconfig_storage_package",
- team: "trendy_team_android_core_experiments",
- srcs: [
- "AconfigPackageImplTest.java",
- "TestDataUtils.java",
- ],
- static_libs: [
- "androidx.test.runner",
- "junit",
- "aconfig_storage_reader_java",
- ],
- test_config: "AndroidStorageJaveTest.xml",
- manifest: "AndroidPackageTestManifest.xml",
- sdk_version: "test_current",
- data: [
- ":read_api_test_storage_files",
- ],
- test_suites: [
- "general-tests",
- ],
- jarjar_rules: "jarjar.txt",
-}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidManifest.xml b/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidManifest.xml
deleted file mode 100644
index 78bfb37..0000000
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidManifest.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.aconfig_storage.test">
- <application>
- <uses-library android:name="android.test.runner" />
- </application>
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="android.aconfig_storage.test" />
-
-</manifest>
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/TestDataUtils.java b/tools/aconfig/aconfig_storage_read_api/tests/java/TestDataUtils.java
deleted file mode 100644
index d5cddc7..0000000
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/TestDataUtils.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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 java.io.FileInputStream;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-
-public final class TestDataUtils {
- public static final String TEST_PACKAGE_MAP_PATH = "mockup.package.map";
- public static final String TEST_FLAG_MAP_PATH = "mockup.flag.map";
- public static final String TEST_FLAG_VAL_PATH = "mockup.val";
- public static final String TEST_FLAG_INFO_PATH = "mockup.info";
-
- public static final String TESTDATA_PATH =
- "/data/local/tmp/aconfig_storage_package/testdata/";
-
- public static ByteBuffer getTestPackageMapByteBuffer() throws Exception {
- return readFile(TESTDATA_PATH + TEST_PACKAGE_MAP_PATH);
- }
-
- public static ByteBuffer getTestFlagMapByteBuffer() throws Exception {
- return readFile(TESTDATA_PATH + TEST_FLAG_MAP_PATH);
- }
-
- public static ByteBuffer getTestFlagValByteBuffer() throws Exception {
- return readFile(TESTDATA_PATH + TEST_FLAG_VAL_PATH);
- }
-
- public static ByteBuffer getTestFlagInfoByteBuffer() throws Exception {
- return readFile(TESTDATA_PATH + TEST_FLAG_INFO_PATH);
- }
-
- private static ByteBuffer readFile(String fileName) throws Exception {
- InputStream input = new FileInputStream(fileName);
- return ByteBuffer.wrap(input.readAllBytes());
- }
-}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/unit/srcs/PlatformAconfigPackageInternalTest.java b/tools/aconfig/aconfig_storage_read_api/tests/unit/srcs/PlatformAconfigPackageInternalTest.java
new file mode 100644
index 0000000..392f644
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/tests/unit/srcs/PlatformAconfigPackageInternalTest.java
@@ -0,0 +1,188 @@
+/*
+ * 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.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.aconfig.storage.AconfigStorageException;
+import android.aconfig.storage.PackageTable;
+import android.aconfig.storage.StorageFileProvider;
+import android.os.flagging.PlatformAconfigPackageInternal;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class PlatformAconfigPackageInternalTest {
+
+ public static final String TESTDATA_PATH =
+ "/data/local/tmp/aconfig_storage_read_unit/testdata/";
+
+ private StorageFileProvider pr;
+
+ @Before
+ public void setup() {
+ pr = new StorageFileProvider(TESTDATA_PATH, TESTDATA_PATH);
+ }
+
+ @Test
+ public void testLoad_container_package() throws Exception {
+ PlatformAconfigPackageInternal p =
+ PlatformAconfigPackageInternal.load(
+ "mockup", "com.android.aconfig.storage.test_1", pr);
+ assertNull(p.getException());
+ }
+
+ @Test
+ public void testLoad_container_package_error() throws Exception {
+ // cannot find package
+ PlatformAconfigPackageInternal p =
+ PlatformAconfigPackageInternal.load(
+ "mockup", "com.android.aconfig.storage.test_10", pr);
+
+ assertEquals(
+ AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
+ ((AconfigStorageException) p.getException()).getErrorCode());
+
+ // cannot find container
+ p = PlatformAconfigPackageInternal.load(null, "com.android.aconfig.storage.test_1", pr);
+ assertEquals(
+ AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+ ((AconfigStorageException) p.getException()).getErrorCode());
+ p = PlatformAconfigPackageInternal.load("test", "com.android.aconfig.storage.test_1", pr);
+ assertEquals(
+ AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+ ((AconfigStorageException) p.getException()).getErrorCode());
+
+ // new storage doesn't exist
+ pr = new StorageFileProvider("fake/path/", "fake/path/");
+ p = PlatformAconfigPackageInternal.load("mockup", "com.android.aconfig.storage.test_1", pr);
+ assertEquals(
+ AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+ ((AconfigStorageException) p.getException()).getErrorCode());
+
+ // file read issue
+ pr = new StorageFileProvider(TESTDATA_PATH, "fake/path/");
+ p = PlatformAconfigPackageInternal.load("mockup", "com.android.aconfig.storage.test_1", pr);
+ assertEquals(
+ AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+ ((AconfigStorageException) p.getException()).getErrorCode());
+ }
+
+ @Test
+ public void testLoad_container_package_fingerprint() throws Exception {
+ PackageTable packageTable = pr.getPackageTable("mockup");
+
+ PackageTable.Node node1 = packageTable.get("com.android.aconfig.storage.test_1");
+
+ long fingerprint = node1.getPackageFingerprint();
+ PlatformAconfigPackageInternal p =
+ PlatformAconfigPackageInternal.load(
+ "mockup", "com.android.aconfig.storage.test_1", fingerprint, pr);
+ assertNull(p.getException());
+ }
+
+ @Test
+ public void testLoad_container_package_fingerprint_error() throws Exception {
+
+ PackageTable packageTable = pr.getPackageTable("mockup");
+
+ PackageTable.Node node1 = packageTable.get("com.android.aconfig.storage.test_1");
+
+ long fingerprint = node1.getPackageFingerprint();
+
+ // cannot find package
+ PlatformAconfigPackageInternal p =
+ PlatformAconfigPackageInternal.load(
+ "mockup", "com.android.aconfig.storage.test_10", fingerprint, pr);
+
+ assertEquals(
+ AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
+ ((AconfigStorageException) p.getException()).getErrorCode());
+
+ // cannot find container
+ p =
+ PlatformAconfigPackageInternal.load(
+ null, "com.android.aconfig.storage.test_1", fingerprint, pr);
+ assertEquals(
+ AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+ ((AconfigStorageException) p.getException()).getErrorCode());
+ p =
+ PlatformAconfigPackageInternal.load(
+ "test", "com.android.aconfig.storage.test_1", fingerprint, pr);
+ assertEquals(
+ AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+ ((AconfigStorageException) p.getException()).getErrorCode());
+ // fingerprint doesn't match
+ p =
+ PlatformAconfigPackageInternal.load(
+ "mockup", "com.android.aconfig.storage.test_1", fingerprint + 1, pr);
+ assertEquals(
+ // AconfigStorageException.ERROR_FILE_FINGERPRINT_MISMATCH,
+ 5, ((AconfigStorageException) p.getException()).getErrorCode());
+
+ // new storage doesn't exist
+ pr = new StorageFileProvider("fake/path/", "fake/path/");
+ p =
+ PlatformAconfigPackageInternal.load(
+ "mockup", "com.android.aconfig.storage.test_1", fingerprint, pr);
+ assertEquals(
+ AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+ ((AconfigStorageException) p.getException()).getErrorCode());
+
+ // file read issue
+ pr = new StorageFileProvider(TESTDATA_PATH, "fake/path/");
+ p =
+ PlatformAconfigPackageInternal.load(
+ "mockup", "com.android.aconfig.storage.test_1", fingerprint, pr);
+ assertEquals(
+ AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
+ ((AconfigStorageException) p.getException()).getErrorCode());
+ }
+
+ @Test
+ public void testGetBooleanFlagValue_flagName() throws Exception {
+ PlatformAconfigPackageInternal p =
+ PlatformAconfigPackageInternal.load(
+ "mockup", "com.android.aconfig.storage.test_1", pr);
+ assertFalse(p.getBooleanFlagValue("disabled_rw", true));
+ assertTrue(p.getBooleanFlagValue("enabled_ro", false));
+ assertTrue(p.getBooleanFlagValue("enabled_rw", false));
+ assertFalse(p.getBooleanFlagValue("fake", false));
+ }
+
+ @Test
+ public void testGetBooleanFlagValue_index() throws Exception {
+
+ PackageTable packageTable = pr.getPackageTable("mockup");
+
+ PackageTable.Node node1 = packageTable.get("com.android.aconfig.storage.test_1");
+
+ long fingerprint = node1.getPackageFingerprint();
+ PlatformAconfigPackageInternal p =
+ PlatformAconfigPackageInternal.load(
+ "mockup", "com.android.aconfig.storage.test_1", fingerprint, pr);
+ assertFalse(p.getBooleanFlagValue(0));
+ assertTrue(p.getBooleanFlagValue(1));
+ assertTrue(p.getBooleanFlagValue(2));
+ }
+}
diff --git a/tools/aconfig/fake_device_config/Android.bp b/tools/aconfig/fake_device_config/Android.bp
index 1f17e6b..4cd5070 100644
--- a/tools/aconfig/fake_device_config/Android.bp
+++ b/tools/aconfig/fake_device_config/Android.bp
@@ -32,3 +32,13 @@
host_supported: true,
is_stubs_module: true,
}
+
+java_library {
+ name: "aconfig_storage_stub",
+ srcs: [
+ "src/android/os/flagging/**/*.java",
+ ],
+ sdk_version: "core_current",
+ host_supported: true,
+ is_stubs_module: true,
+}
diff --git a/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigStorageReadException.java b/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigStorageReadException.java
new file mode 100644
index 0000000..bfec98c
--- /dev/null
+++ b/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigStorageReadException.java
@@ -0,0 +1,61 @@
+/*
+ * 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.os.flagging;
+
+public class AconfigStorageReadException extends RuntimeException {
+
+ /** Generic error code indicating an unspecified Aconfig Storage error. */
+ public static final int ERROR_GENERIC = 0;
+
+ /** Error code indicating that the Aconfig Storage system is not found on the device. */
+ public static final int ERROR_STORAGE_SYSTEM_NOT_FOUND = 1;
+
+ /** Error code indicating that the requested configuration package is not found. */
+ public static final int ERROR_PACKAGE_NOT_FOUND = 2;
+
+ /** Error code indicating that the specified container is not found. */
+ public static final int ERROR_CONTAINER_NOT_FOUND = 3;
+
+ /** Error code indicating that there was an error reading the Aconfig Storage file. */
+ public static final int ERROR_CANNOT_READ_STORAGE_FILE = 4;
+
+ public static final int ERROR_FILE_FINGERPRINT_MISMATCH = 5;
+
+ public AconfigStorageReadException(int errorCode, String msg) {
+ super(msg);
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public AconfigStorageReadException(int errorCode, String msg, Throwable cause) {
+ super(msg, cause);
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public AconfigStorageReadException(int errorCode, Throwable cause) {
+ super(cause);
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ public int getErrorCode() {
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ @Override
+ public String getMessage() {
+ throw new UnsupportedOperationException("Stub!");
+ }
+}