diff --git a/tools/aconfig/.editorconfig b/tools/aconfig/.editorconfig
new file mode 100644
index 0000000000..cc5985f843
--- /dev/null
+++ b/tools/aconfig/.editorconfig
@@ -0,0 +1,9 @@
+# EditorConfig is awesome: https://EditorConfig.org
+
+# top-most EditorConfig file
+root = true
+
+[*.java]
+indent_style = tab
+indent_size = 4
+
diff --git a/tools/aconfig/TEST_MAPPING b/tools/aconfig/TEST_MAPPING
index 421e94a8a6..448d8cf8af 100644
--- a/tools/aconfig/TEST_MAPPING
+++ b/tools/aconfig/TEST_MAPPING
@@ -94,12 +94,16 @@
{
// aconfig_storage read api cpp integration tests
"name": "aconfig_storage_read_api.test.cpp"
- }
- ],
- "postsubmit": [
+ },
{
// aconfig_storage file cpp integration tests
"name": "aconfig_storage_file.test.cpp"
}
+ ],
+ "postsubmit": [
+ {
+ // aconfig_storage read api java integration tests
+ "name": "aconfig_storage_read_api.test.java"
+ }
]
}
diff --git a/tools/aconfig/aconfig_storage_read_api/Android.bp b/tools/aconfig/aconfig_storage_read_api/Android.bp
index 9b842546f5..3b124b15c1 100644
--- a/tools/aconfig/aconfig_storage_read_api/Android.bp
+++ b/tools/aconfig/aconfig_storage_read_api/Android.bp
@@ -111,3 +111,28 @@ cc_defaults {
"liblog",
],
}
+
+rust_ffi_shared {
+ name: "libaconfig_storage_read_api_rust_jni",
+ crate_name: "aconfig_storage_read_api_rust_jni",
+ srcs: ["srcs/lib.rs"],
+ rustlibs: [
+ "libaconfig_storage_read_api",
+ "libanyhow",
+ "libjni",
+ ],
+ prefer_rlib: true,
+}
+
+java_library {
+ name: "libaconfig_storage_read_api_java",
+ srcs: [
+ "srcs/**/*.java",
+ ],
+ required: ["libaconfig_storage_read_api_rust_jni"],
+ min_sdk_version: "UpsideDownCake",
+ apex_available: [
+ "//apex_available:anyapex",
+ "//apex_available:platform",
+ ],
+}
diff --git a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/AconfigStorageReadAPI.java b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/AconfigStorageReadAPI.java
new file mode 100644
index 0000000000..7746b58f32
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/AconfigStorageReadAPI.java
@@ -0,0 +1,88 @@
+/*
+ * 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.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileChannel.MapMode;
+
+import android.aconfig.storage.PackageReadContext;
+import android.aconfig.storage.FlagReadContext;
+import android.aconfig.storage.BooleanFlagValue;
+
+import dalvik.annotation.optimization.FastNative;
+
+public class AconfigStorageReadAPI {
+
+ // Storage file dir on device
+ private static final String STORAGEDIR = "/metadata/aconfig";
+
+ // Stoarge file type
+ public enum StorageFileType {
+ PACKAGE_MAP,
+ FLAG_MAP,
+ FLAG_VAL,
+ FLAG_INFO
+ }
+
+ // Map a storage file given file path
+ public static MappedByteBuffer mapStorageFile(String file) throws IOException {
+ FileInputStream stream = new FileInputStream(file);
+ FileChannel channel = stream.getChannel();
+ return channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
+ }
+
+ // Map a storage file given container and file type
+ public static MappedByteBuffer getMappedFile(
+ String container,
+ StorageFileType type) throws IOException{
+ switch (type) {
+ case PACKAGE_MAP:
+ return mapStorageFile(STORAGEDIR + "/maps/" + container + ".package.map");
+ case FLAG_MAP:
+ return mapStorageFile(STORAGEDIR + "/maps/" + container + ".flag.map");
+ case FLAG_VAL:
+ return mapStorageFile(STORAGEDIR + "/boot/" + container + ".val");
+ case FLAG_INFO:
+ return mapStorageFile(STORAGEDIR + "/boot/" + container + ".info");
+ default:
+ throw new IOException("Invalid storage file type");
+ }
+ }
+
+ // JNI interface to get package read context
+ @FastNative
+ public static native PackageReadContext getPackageReadContext(
+ ByteBuffer mappedFile, String packageName);
+
+ // JNI interface to get flag read context
+ @FastNative
+ public static native FlagReadContext getFlagReadContext(
+ ByteBuffer mappedFile, int packageId, String flagName);
+
+ // JNI interface to get boolean flag value
+ @FastNative
+ public static native BooleanFlagValue getBooleanFlagValue(
+ ByteBuffer mappedFile, int flagIndex);
+
+ static {
+ System.loadLibrary("aconfig_storage_read_api_rust_jni");
+ }
+}
diff --git a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/BooleanFlagValue.java b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/BooleanFlagValue.java
new file mode 100644
index 0000000000..11fe447928
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/BooleanFlagValue.java
@@ -0,0 +1,30 @@
+package android.aconfig.storage;
+/*
+ * 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.
+ */
+
+public class BooleanFlagValue {
+ public boolean mQuerySuccess;
+ public String mErrorMessage;
+ public boolean mFlagValue;
+
+ public BooleanFlagValue(boolean querySuccess,
+ String errorMessage,
+ boolean value) {
+ mQuerySuccess = querySuccess;
+ mErrorMessage = errorMessage;
+ mFlagValue = value;
+ }
+}
diff --git a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/FlagReadContext.java b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/FlagReadContext.java
new file mode 100644
index 0000000000..57a36cafd2
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/FlagReadContext.java
@@ -0,0 +1,56 @@
+package android.aconfig.storage;
+/*
+ * 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.
+ */
+
+public class FlagReadContext {
+ public boolean mQuerySuccess;
+ public String mErrorMessage;
+ public boolean mFlagExists;
+ public StoredFlagType mFlagType;
+ public int mFlagIndex;
+
+ public FlagReadContext(boolean querySuccess,
+ String errorMessage,
+ boolean flagExists,
+ int flagType,
+ int flagIndex) {
+ mQuerySuccess = querySuccess;
+ mErrorMessage = errorMessage;
+ mFlagExists = flagExists;
+ mFlagType = StoredFlagType.fromInteger(flagType);
+ mFlagIndex = flagIndex;
+ }
+
+ // Flag type enum, consistent with the definition in aconfig_storage_file/src/lib.rs
+ public enum StoredFlagType {
+ ReadWriteBoolean,
+ ReadOnlyBoolean,
+ FixedReadOnlyBoolean;
+
+ public static StoredFlagType fromInteger(int x) {
+ switch(x) {
+ case 0:
+ return ReadWriteBoolean;
+ case 1:
+ return ReadOnlyBoolean;
+ case 2:
+ return FixedReadOnlyBoolean;
+ default:
+ return null;
+ }
+ }
+ }
+}
diff --git a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/PackageReadContext.java b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/PackageReadContext.java
new file mode 100644
index 0000000000..60d6b663a2
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/PackageReadContext.java
@@ -0,0 +1,36 @@
+package android.aconfig.storage;
+/*
+ * 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.
+ */
+
+public class PackageReadContext {
+ public boolean mQuerySuccess;
+ public String mErrorMessage;
+ public boolean mPackageExists;
+ public int mPackageId;
+ public int mBooleanStartIndex;
+
+ public PackageReadContext(boolean querySuccess,
+ String errorMessage,
+ boolean packageExists,
+ int packageId,
+ int booleanStartIndex) {
+ mQuerySuccess = querySuccess;
+ mErrorMessage = errorMessage;
+ mPackageExists = packageExists;
+ mPackageId = packageId;
+ mBooleanStartIndex = booleanStartIndex;
+ }
+}
diff --git a/tools/aconfig/aconfig_storage_read_api/srcs/lib.rs b/tools/aconfig/aconfig_storage_read_api/srcs/lib.rs
new file mode 100644
index 0000000000..e195eb8caa
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/srcs/lib.rs
@@ -0,0 +1,203 @@
+//! aconfig storage read api java rust interlop
+
+use aconfig_storage_read_api::flag_table_query::find_flag_read_context;
+use aconfig_storage_read_api::flag_value_query::find_boolean_flag_value;
+use aconfig_storage_read_api::package_table_query::find_package_read_context;
+use aconfig_storage_read_api::{FlagReadContext, PackageReadContext};
+
+use anyhow::Result;
+use jni::objects::{JByteBuffer, JClass, JString, JValue};
+use jni::sys::{jint, jobject};
+use jni::JNIEnv;
+
+/// Call rust find package read context
+fn get_package_read_context_java(
+ env: &mut JNIEnv,
+ file: JByteBuffer,
+ package: JString,
+) -> Result