Merge "Export PRODUCT_VENDOR_LINKER_CONFIG_FRAGMENTS to soong" into main
diff --git a/core/Makefile b/core/Makefile
index 638d2b9..25429e7 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -5298,7 +5298,7 @@
--dirmap /system_ext:$(TARGET_OUT_SYSTEM_EXT) \
--dirmap /product:$(TARGET_OUT_PRODUCT) \
--dirmap /apex:$(APEX_OUT) \
- $(VINTF_FRAMEWORK_MANIFEST_FROZEN_DIR) > $@ 2>&1 ) || ( cat $@ && exit 1 )
+ system/libhidl/vintfdata/frozen > $@ 2>&1 ) || ( cat $@ && exit 1 )
$(call declare-1p-target,$(vintffm_log))
diff --git a/core/android_soong_config_vars.mk b/core/android_soong_config_vars.mk
index 48b6ff2..10d365c 100644
--- a/core/android_soong_config_vars.mk
+++ b/core/android_soong_config_vars.mk
@@ -102,6 +102,10 @@
$(call add_soong_config_var_value,ANDROID,avf_microdroid_guest_gki_version,$(PRODUCT_AVF_MICRODROID_GUEST_GKI_VERSION))
endif
+ifdef TARGET_BOOTS_16K
+$(call soong_config_set_bool,ANDROID,target_boots_16k,$(filter true,$(TARGET_BOOTS_16K)))
+endif
+
ifdef PRODUCT_MEMCG_V2_FORCE_ENABLED
$(call add_soong_config_var_value,ANDROID,memcg_v2_force_enabled,$(PRODUCT_MEMCG_V2_FORCE_ENABLED))
endif
@@ -234,3 +238,18 @@
ifdef BOARD_USE_MAX_SECURE_RESOURCE
$(call soong_config_set,video_codec,board_use_max_secure_resource,$(BOARD_USE_MAX_SECURE_RESOURCE))
endif
+
+# Export related variables to soong for hardware/google/graphics/common/libacryl:libacryl
+ifdef BOARD_LIBACRYL_DEFAULT_COMPOSITOR
+ $(call soong_config_set,acryl,libacryl_default_compositor,$(BOARD_LIBACRYL_DEFAULT_COMPOSITOR))
+endif
+ifdef BOARD_LIBACRYL_DEFAULT_SCALER
+ $(call soong_config_set,acryl,libacryl_default_scaler,$(BOARD_LIBACRYL_DEFAULT_SCALER))
+endif
+ifdef BOARD_LIBACRYL_DEFAULT_BLTER
+ $(call soong_config_set,acryl,libacryl_default_blter,$(BOARD_LIBACRYL_DEFAULT_BLTER))
+endif
+ifdef BOARD_LIBACRYL_G2D_HDR_PLUGIN
+ #BOARD_LIBACRYL_G2D_HDR_PLUGIN is set in each board config
+ $(call soong_config_set_bool,acryl,libacryl_use_g2d_hdr_plugin,true)
+endif
diff --git a/core/soong_config.mk b/core/soong_config.mk
index b608d2f..ac49aee 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -352,6 +352,7 @@
$(call add_json_list, SystemExtPropFiles, $(TARGET_SYSTEM_EXT_PROP))
$(call add_json_list, ProductPropFiles, $(TARGET_PRODUCT_PROP))
$(call add_json_list, OdmPropFiles, $(TARGET_ODM_PROP))
+$(call add_json_list, VendorPropFiles, $(TARGET_VENDOR_PROP))
$(call add_json_str, ExtraAllowedDepsTxt, $(EXTRA_ALLOWED_DEPS_TXT))
@@ -437,6 +438,26 @@
$(call end_json_map)
+# For converting vintf_data
+$(call add_json_list, DeviceMatrixFile, $(DEVICE_MATRIX_FILE))
+$(call add_json_list, ProductManifestFiles, $(PRODUCT_MANIFEST_FILES))
+$(call add_json_list, SystemManifestFile, $(DEVICE_FRAMEWORK_MANIFEST_FILE))
+SYSTEM_EXT_HWSERVICE_FILES :=
+ifeq ($(PRODUCT_HIDL_ENABLED),true)
+ ifneq ($(filter hwservicemanager,$(PRODUCT_PACKAGES)),)
+ SYSTEM_EXT_HWSERVICE_FILES += system/hwservicemanager/hwservicemanager_no_max.xml
+ else
+ $(error If PRODUCT_HIDL_ENABLED is set, hwservicemanager must be added to PRODUCT_PACKAGES explicitly)
+ endif
+else
+ ifneq ($(filter hwservicemanager,$(PRODUCT_PACKAGES)),)
+ SYSTEM_EXT_HWSERVICE_FILES += system/hwservicemanager/hwservicemanager.xml
+ else ifneq ($(filter hwservicemanager,$(PRODUCT_PACKAGES_SHIPPING_API_LEVEL_34)),)
+ SYSTEM_EXT_HWSERVICE_FILES += system/hwservicemanager/hwservicemanager.xml
+ endif
+endif
+$(call add_json_list, SystemExtManifestFiles, $(SYSTEM_EXT_MANIFEST_FILES) $(SYSTEM_EXT_HWSERVICE_FILES))
+
$(call json_end)
$(file >$(SOONG_VARIABLES).tmp,$(json_contents))
diff --git a/core/soong_extra_config.mk b/core/soong_extra_config.mk
index 00b5c0f..2ff83a1 100644
--- a/core/soong_extra_config.mk
+++ b/core/soong_extra_config.mk
@@ -43,6 +43,7 @@
$(call add_json_list, PRODUCT_PRODUCT_PROPERTIES, $(call collapse-prop-pairs,PRODUCT_PRODUCT_PROPERTIES))
$(call add_json_list, PRODUCT_ODM_PROPERTIES, $(call collapse-prop-pairs,PRODUCT_ODM_PROPERTIES))
$(call add_json_list, PRODUCT_PROPERTY_OVERRIDES, $(call collapse-prop-pairs,PRODUCT_PROPERTY_OVERRIDES))
+$(call add_json_list, PRODUCT_DEFAULT_PROPERTY_OVERRIDES, $(call collapse-prop-pairs,PRODUCT_DEFAULT_PROPERTY_OVERRIDES))
$(call add_json_str, BootloaderBoardName, $(TARGET_BOOTLOADER_BOARD_NAME))
diff --git a/target/product/base_system.mk b/target/product/base_system.mk
index 4a27b7d..5ce21e2 100644
--- a/target/product/base_system.mk
+++ b/target/product/base_system.mk
@@ -274,7 +274,6 @@
Shell \
shell_and_utilities_system \
sm \
- snapshotctl \
snapuserd \
storaged \
surfaceflinger \
@@ -492,6 +491,7 @@
record_binder \
servicedispatcher \
showmap \
+ snapshotctl \
sqlite3 \
ss \
start_with_lockagent \
@@ -505,10 +505,6 @@
unwind_reg_info \
unwind_symbols \
-# For Remotely Provisioned Certificate Processor
-PRODUCT_SYSTEM_PROPERTIES += \
- remote_provisioning.use_cert_processor=false
-
# The set of packages whose code can be loaded by the system server.
PRODUCT_SYSTEM_SERVER_APPS += \
SettingsProvider \
diff --git a/tools/aconfig/aconfig/src/codegen/java.rs b/tools/aconfig/aconfig/src/codegen/java.rs
index 47d4042..81c7d00 100644
--- a/tools/aconfig/aconfig/src/codegen/java.rs
+++ b/tools/aconfig/aconfig/src/codegen/java.rs
@@ -561,6 +561,8 @@
+ "flag declaration.",
e
);
+ } catch (SecurityException e) {
+ // for isolated process case, skip loading flag value from the storage, use the default
}
aconfig_test_is_cached = true;
}
@@ -579,6 +581,8 @@
+ "flag declaration.",
e
);
+ } catch (SecurityException e) {
+ // for isolated process case, skip loading flag value from the storage, use the default
}
other_namespace_is_cached = true;
}
@@ -787,6 +791,8 @@
+ "flag declaration.",
e
);
+ } catch (SecurityException e) {
+ // for isolated process case, skip loading flag value from the storage, use the default
}
aconfig_test_is_cached = true;
}
diff --git a/tools/aconfig/aconfig/src/codegen/rust.rs b/tools/aconfig/aconfig/src/codegen/rust.rs
index d318b96..569a34b 100644
--- a/tools/aconfig/aconfig/src/codegen/rust.rs
+++ b/tools/aconfig/aconfig/src/codegen/rust.rs
@@ -297,7 +297,7 @@
},
None => {
log!(Level::Error, "no context found for package com.android.aconfig.test");
- Ok(false)
+ Err(format!("failed to flag package com.android.aconfig.test"))
}
}
})
@@ -309,7 +309,7 @@
},
Err(err) => {
log!(Level::Error, "aconfig_rust_codegen: error: {err}");
- panic!("failed to read flag value: {err}");
+ return false;
}
}
} else {
@@ -344,7 +344,7 @@
},
None => {
log!(Level::Error, "no context found for package com.android.aconfig.test");
- Ok(false)
+ Err(format!("failed to flag package com.android.aconfig.test"))
}
}
})
@@ -356,7 +356,7 @@
},
Err(err) => {
log!(Level::Error, "aconfig_rust_codegen: error: {err}");
- panic!("failed to read flag value: {err}");
+ return false;
}
}
} else {
@@ -391,7 +391,7 @@
},
None => {
log!(Level::Error, "no context found for package com.android.aconfig.test");
- Ok(false)
+ Err(format!("failed to flag package com.android.aconfig.test"))
}
}
})
@@ -403,7 +403,7 @@
},
Err(err) => {
log!(Level::Error, "aconfig_rust_codegen: error: {err}");
- panic!("failed to read flag value: {err}");
+ return false;
}
}
} else {
@@ -439,7 +439,7 @@
},
None => {
log!(Level::Error, "no context found for package com.android.aconfig.test");
- Ok(true)
+ Err(format!("failed to flag package com.android.aconfig.test"))
}
}
})
@@ -451,7 +451,7 @@
},
Err(err) => {
log!(Level::Error, "aconfig_rust_codegen: error: {err}");
- panic!("failed to read flag value: {err}");
+ return true;
}
}
} else {
diff --git a/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template b/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
index 26d3069..8c7b3fa 100644
--- a/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
+++ b/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
@@ -73,6 +73,8 @@
+ "flag declaration.",
e
);
+ } catch (SecurityException e) \{
+ // for isolated process case, skip loading flag value from the storage, use the default
}
{namespace_with_flags.namespace}_is_cached = true;
}
diff --git a/tools/aconfig/aconfig/templates/cpp_source_file.template b/tools/aconfig/aconfig/templates/cpp_source_file.template
index eaaf86f..df3b10d 100644
--- a/tools/aconfig/aconfig/templates/cpp_source_file.template
+++ b/tools/aconfig/aconfig/templates/cpp_source_file.template
@@ -92,17 +92,21 @@
aconfig_storage::StorageFileType::package_map);
if (!package_map_file.ok()) \{
ALOGE("error: failed to get package map file: %s", package_map_file.error().c_str());
+ package_exists_in_storage_ = false;
+ return;
}
auto context = aconfig_storage::get_package_read_context(
**package_map_file, "{package}");
if (!context.ok()) \{
ALOGE("error: failed to get package read context: %s", context.error().c_str());
+ package_exists_in_storage_ = false;
+ return;
}
if (!(context->package_exists)) \{
- package_exists_in_storage_ = false;
- return;
+ package_exists_in_storage_ = false;
+ return;
}
// cache package boolean flag start index
@@ -116,6 +120,8 @@
aconfig_storage::StorageFileType::flag_val);
if (!flag_value_file.ok()) \{
ALOGE("error: failed to get flag value file: %s", flag_value_file.error().c_str());
+ package_exists_in_storage_ = false;
+ return;
}
// cache flag value file
diff --git a/tools/aconfig/aconfig/templates/rust.template b/tools/aconfig/aconfig/templates/rust.template
index 6456360..d0079d4 100644
--- a/tools/aconfig/aconfig/templates/rust.template
+++ b/tools/aconfig/aconfig/templates/rust.template
@@ -53,7 +53,7 @@
},
None => \{
log!(Level::Error, "no context found for package {package}");
- Ok({flag.default_value})
+ Err(format!("failed to flag package {package}"))
}
}
})
@@ -65,7 +65,7 @@
},
Err(err) => \{
log!(Level::Error, "aconfig_rust_codegen: error: \{err}");
- panic!("failed to read flag value: \{err}");
+ return {flag.default_value};
}
}
} else \{
diff --git a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/ByteBufferReader.java b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/ByteBufferReader.java
index 4bea083..9571568 100644
--- a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/ByteBufferReader.java
+++ b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/ByteBufferReader.java
@@ -41,8 +41,16 @@
return this.mByteBuffer.getInt();
}
+ public long readLong() {
+ return this.mByteBuffer.getLong();
+ }
+
public String readString() {
int length = readInt();
+ if (length > 1024) {
+ throw new AconfigStorageException(
+ "String length exceeds maximum allowed size (1024 bytes): " + length);
+ }
byte[] bytes = new byte[length];
mByteBuffer.get(bytes, 0, length);
return new String(bytes, StandardCharsets.UTF_8);
diff --git a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/PackageTable.java b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/PackageTable.java
index 39b7e59..a45d12a 100644
--- a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/PackageTable.java
+++ b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/PackageTable.java
@@ -124,8 +124,10 @@
private String mPackageName;
private int mPackageId;
+ private long mPackageFingerprint;
private int mBooleanStartIndex;
private int mNextOffset;
+ private boolean mHasPackageFingerprint;
private static Node fromBytes(ByteBufferReader reader, int version) {
switch (version) {
@@ -153,9 +155,11 @@
Node node = new Node();
node.mPackageName = reader.readString();
node.mPackageId = reader.readInt();
+ node.mPackageFingerprint = reader.readLong();
node.mBooleanStartIndex = reader.readInt();
node.mNextOffset = reader.readInt();
node.mNextOffset = node.mNextOffset == 0 ? -1 : node.mNextOffset;
+ node.mHasPackageFingerprint = true;
return node;
}
@@ -189,6 +193,10 @@
return mPackageId;
}
+ public long getPackageFingerprint() {
+ return mPackageFingerprint;
+ }
+
public int getBooleanStartIndex() {
return mBooleanStartIndex;
}
@@ -196,5 +204,9 @@
public int getNextOffset() {
return mNextOffset;
}
+
+ public boolean hasPackageFingerprint() {
+ return mHasPackageFingerprint;
+ }
}
}
diff --git a/tools/aconfig/aconfig_storage_file/tests/srcs/PackageTableTest.java b/tools/aconfig/aconfig_storage_file/tests/srcs/PackageTableTest.java
index e7e19d8..dc2ad92 100644
--- a/tools/aconfig/aconfig_storage_file/tests/srcs/PackageTableTest.java
+++ b/tools/aconfig/aconfig_storage_file/tests/srcs/PackageTableTest.java
@@ -17,6 +17,7 @@
package android.aconfig.storage.test;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import android.aconfig.storage.FileType;
import android.aconfig.storage.PackageTable;
@@ -66,5 +67,9 @@
assertEquals(159, node1.getNextOffset());
assertEquals(-1, node2.getNextOffset());
assertEquals(-1, node4.getNextOffset());
+
+ assertFalse(node1.hasPackageFingerprint());
+ assertFalse(node2.hasPackageFingerprint());
+ assertFalse(node4.hasPackageFingerprint());
}
}
diff --git a/tools/aconfig/aconfig_storage_read_api/Android.bp b/tools/aconfig/aconfig_storage_read_api/Android.bp
index 80b8ece..666c5ba 100644
--- a/tools/aconfig/aconfig_storage_read_api/Android.bp
+++ b/tools/aconfig/aconfig_storage_read_api/Android.bp
@@ -154,6 +154,8 @@
java_library {
name: "aconfig_storage_reader_java",
srcs: [
+ "srcs/android/aconfig/storage/AconfigPackageImpl.java",
+ "srcs/android/aconfig/storage/StorageFileProvider.java",
"srcs/android/aconfig/storage/StorageInternalReader.java",
],
libs: [
@@ -175,6 +177,8 @@
java_library {
name: "aconfig_storage_reader_java_none",
srcs: [
+ "srcs/android/aconfig/storage/AconfigPackageImpl.java",
+ "srcs/android/aconfig/storage/StorageFileProvider.java",
"srcs/android/aconfig/storage/StorageInternalReader.java",
],
libs: [
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
new file mode 100644
index 0000000..4d020cf
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/AconfigPackageImpl.java
@@ -0,0 +1,134 @@
+/*
+ * 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;
+import java.util.ArrayList;
+import java.util.List;
+
+/** @hide */
+public class AconfigPackageImpl {
+ private FlagTable mFlagTable;
+ private FlagValueList mFlagValueList;
+ private PackageTable.Node mPNode;
+
+ /** @hide */
+ public static AconfigPackageImpl load(String packageName, StorageFileProvider fileProvider) {
+ AconfigPackageImpl aPackage = new AconfigPackageImpl();
+ if (!aPackage.init(null, packageName, fileProvider)) {
+ return null;
+ }
+ return aPackage;
+ }
+
+ /** @hide */
+ public static AconfigPackageImpl load(
+ String container, String packageName, StorageFileProvider fileProvider) {
+ if (container == null) {
+ return null;
+ }
+ AconfigPackageImpl aPackage = new AconfigPackageImpl();
+ if (!aPackage.init(container, packageName, fileProvider)) {
+ return null;
+ }
+ return aPackage;
+ }
+
+ /** @hide */
+ public boolean getBooleanFlagValue(String flagName, boolean defaultValue) {
+ FlagTable.Node fNode = mFlagTable.get(mPNode.getPackageId(), flagName);
+ // no such flag in this package
+ if (fNode == null) return defaultValue;
+ int index = fNode.getFlagIndex() + mPNode.getBooleanStartIndex();
+ return mFlagValueList.getBoolean(index);
+ }
+
+ /** @hide */
+ public boolean getBooleanFlagValue(int index) {
+ return mFlagValueList.getBoolean(index + mPNode.getBooleanStartIndex());
+ }
+
+ /** @hide */
+ public long getPackageFingerprint() {
+ return mPNode.getPackageFingerprint();
+ }
+
+ /** @hide */
+ public boolean hasPackageFingerprint() {
+ return mPNode.hasPackageFingerprint();
+ }
+
+ private boolean init(
+ String containerName, String packageName, StorageFileProvider fileProvider) {
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+ String container = containerName;
+ try {
+ // for devices don't have new storage directly return
+ if (!fileProvider.containerFileExists(null)) {
+ return false;
+ }
+ PackageTable.Node pNode = null;
+
+ if (container == null) {
+ PackageTable pTable = null;
+ // check if device has flag files on the system partition
+ // if the device has then search system partition first
+ container = "system";
+ if (fileProvider.containerFileExists(container)) {
+ pTable = fileProvider.getPackageTable(container);
+ pNode = pTable.get(packageName);
+ }
+ List<Path> mapFiles = new ArrayList<>();
+ if (pNode == null) {
+ mapFiles = fileProvider.listPackageMapFiles();
+ if (mapFiles.isEmpty()) return false;
+ }
+
+ for (Path p : mapFiles) {
+ pTable = StorageFileProvider.getPackageTable(p);
+ pNode = pTable.get(packageName);
+ if (pNode != null) {
+ container = pTable.getHeader().getContainer();
+ break;
+ }
+ }
+ } else {
+ pNode = fileProvider.getPackageTable(container).get(packageName);
+ }
+
+ if (pNode == null) {
+ // for the case package is not found in all container, return instead of throwing
+ // error
+ return false;
+ }
+
+ mFlagTable = fileProvider.getFlagTable(container);
+ mFlagValueList = fileProvider.getFlagValueList(container);
+ mPNode = pNode;
+ } catch (Exception e) {
+ throw new AconfigStorageException(
+ String.format(
+ "cannot load package %s, from container %s", packageName, container),
+ e);
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
+ }
+ return true;
+ }
+}
diff --git a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/StorageFileProvider.java b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/StorageFileProvider.java
new file mode 100644
index 0000000..6a6f007
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/StorageFileProvider.java
@@ -0,0 +1,123 @@
+/*
+ * 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.Closeable;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.ArrayList;
+import java.util.List;
+
+/** @hide */
+public class StorageFileProvider {
+
+ private static final String DEFAULT_MAP_PATH = "/metadata/aconfig/maps/";
+ private static final String DEFAULT_BOOT_PATH = "/metadata/aconfig/boot/";
+ private static final String PMAP_FILE_EXT = ".package.map";
+ private static final String FMAP_FILE_EXT = ".flag.map";
+ private static final String VAL_FILE_EXT = ".val";
+
+ private final String mMapPath;
+ private final String mBootPath;
+
+ /** @hide */
+ public StorageFileProvider getDefaultProvider() {
+ return new StorageFileProvider(DEFAULT_MAP_PATH, DEFAULT_BOOT_PATH);
+ }
+
+ /** @hide */
+ public StorageFileProvider(String mapPath, String bootPath) {
+ mMapPath = mapPath;
+ mBootPath = bootPath;
+ }
+
+ /** @hide */
+ public boolean containerFileExists(String container) {
+ if (container == null) {
+ return Files.exists(Paths.get(DEFAULT_MAP_PATH));
+ }
+ return Files.exists(Paths.get(mMapPath, container + PMAP_FILE_EXT));
+ }
+
+ /** @hide */
+ public List<Path> listPackageMapFiles() {
+ List<Path> result = new ArrayList<>();
+ try {
+ DirectoryStream<Path> stream =
+ Files.newDirectoryStream(Paths.get(mMapPath), "*" + PMAP_FILE_EXT);
+ for (Path entry : stream) {
+ result.add(entry);
+ // sb.append(entry. toString());
+ }
+ } catch (Exception e) {
+ throw new AconfigStorageException(
+ String.format("Fail to list map files in path %s", mMapPath), e);
+ }
+
+ return result;
+ }
+
+ /** @hide */
+ public PackageTable getPackageTable(String container) {
+ return getPackageTable(Paths.get(mMapPath, container + PMAP_FILE_EXT));
+ }
+
+ /** @hide */
+ public FlagTable getFlagTable(String container) {
+ return FlagTable.fromBytes(mapStorageFile(Paths.get(mMapPath, container + FMAP_FILE_EXT)));
+ }
+
+ /** @hide */
+ public FlagValueList getFlagValueList(String container) {
+ return FlagValueList.fromBytes(
+ mapStorageFile(Paths.get(mBootPath, container + VAL_FILE_EXT)));
+ }
+
+ /** @hide */
+ public static PackageTable getPackageTable(Path path) {
+ return PackageTable.fromBytes(mapStorageFile(path));
+ }
+
+ // Map a storage file given file path
+ private static MappedByteBuffer mapStorageFile(Path file) {
+ FileChannel channel = null;
+ try {
+ channel = FileChannel.open(file, StandardOpenOption.READ);
+ 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);
+ } finally {
+ quietlyDispose(channel);
+ }
+ }
+
+ private static void quietlyDispose(Closeable closable) {
+ try {
+ if (closable != null) {
+ closable.close();
+ }
+ } catch (Exception e) {
+ // no need to care, at least as of now
+ }
+ }
+}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigPackageImplTest.java b/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigPackageImplTest.java
new file mode 100644
index 0000000..0f3be7a
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/tests/java/AconfigPackageImplTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.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.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class AconfigPackageImplTest {
+
+ @Test
+ public void testLoad_onlyPackageName() throws Exception {
+ StorageFileProvider pr =
+ new StorageFileProvider(TestDataUtils.TESTDATA_PATH, TestDataUtils.TESTDATA_PATH);
+ AconfigPackageImpl p = AconfigPackageImpl.load("com.android.aconfig.storage.test_1", pr);
+ assertNotNull(p);
+ }
+
+ @Test
+ public void testLoad_groupNameFingerprint() throws Exception {
+ StorageFileProvider pr =
+ new StorageFileProvider(TestDataUtils.TESTDATA_PATH, TestDataUtils.TESTDATA_PATH);
+ AconfigPackageImpl p =
+ AconfigPackageImpl.load("mockup", "com.android.aconfig.storage.test_1", pr);
+ assertNotNull(p);
+
+ assertThrows(
+ AconfigStorageException.class,
+ () -> AconfigPackageImpl.load("test", "com.android.aconfig.storage.test_1", pr));
+ }
+
+ @Test
+ public void testGetBooleanFlagValue_flagName() throws Exception {
+ StorageFileProvider pr =
+ new StorageFileProvider(TestDataUtils.TESTDATA_PATH, TestDataUtils.TESTDATA_PATH);
+ 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 {
+ StorageFileProvider pr =
+ new StorageFileProvider(TestDataUtils.TESTDATA_PATH, TestDataUtils.TESTDATA_PATH);
+ AconfigPackageImpl p =
+ AconfigPackageImpl.load("mockup", "com.android.aconfig.storage.test_1", pr);
+ assertFalse(p.getBooleanFlagValue(0));
+ assertTrue(p.getBooleanFlagValue(1));
+ assertTrue(p.getBooleanFlagValue(2));
+ }
+
+ @Test
+ public void testHasPackageFingerprint() throws Exception {
+ StorageFileProvider pr =
+ new StorageFileProvider(TestDataUtils.TESTDATA_PATH, TestDataUtils.TESTDATA_PATH);
+ AconfigPackageImpl p =
+ AconfigPackageImpl.load("mockup", "com.android.aconfig.storage.test_1", pr);
+ assertFalse(p.hasPackageFingerprint());
+ }
+}
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 3d4e9ad..9c88122 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/java/Android.bp
+++ b/tools/aconfig/aconfig_storage_read_api/tests/java/Android.bp
@@ -22,3 +22,28 @@
],
team: "trendy_team_android_core_experiments",
}
+
+android_test {
+ name: "aconfig_storage_package",
+ team: "trendy_team_android_core_experiments",
+ srcs: [
+ "AconfigPackageImplTest.java",
+ "StorageFileProviderTest.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/AndroidPackageTestManifest.xml b/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidPackageTestManifest.xml
new file mode 100644
index 0000000..5e01879
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidPackageTestManifest.xml
@@ -0,0 +1,27 @@
+<?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/AndroidStorageJaveTest.xml b/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidStorageJaveTest.xml
new file mode 100644
index 0000000..3d5bb8e
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/tests/java/AndroidStorageJaveTest.xml
@@ -0,0 +1,34 @@
+<?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.
+ -->
+<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" />
+ </target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="cleanup" value="true" />
+ <option name="push" value="package.map->/data/local/tmp/aconfig_storage_package/testdata/mockup.package.map" />
+ <option name="push" value="flag.map->/data/local/tmp/aconfig_storage_package/testdata/mockup.flag.map" />
+ <option name="push" value="flag.val->/data/local/tmp/aconfig_storage_package/testdata/mockup.val" />
+ <option name="push" value="flag.info->/data/local/tmp/aconfig_storage_package/testdata/mockup.info" />
+ <option name="post-push" value="chmod +r /data/local/tmp/aconfig_storage_package/testdata/" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.aconfig.storage.test" />
+ <option name="runtime-hint" value="1m" />
+ </test>
+</configuration>
\ No newline at end of file
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/StorageFileProviderTest.java b/tools/aconfig/aconfig_storage_read_api/tests/java/StorageFileProviderTest.java
new file mode 100644
index 0000000..ba1ae9e
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/tests/java/StorageFileProviderTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.assertTrue;
+
+import android.aconfig.storage.FlagTable;
+import android.aconfig.storage.FlagValueList;
+import android.aconfig.storage.PackageTable;
+import android.aconfig.storage.StorageFileProvider;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+
+@RunWith(JUnit4.class)
+public class StorageFileProviderTest {
+
+ @Test
+ public void testContainerFileExists() throws Exception {
+ StorageFileProvider p =
+ new StorageFileProvider(TestDataUtils.TESTDATA_PATH, TestDataUtils.TESTDATA_PATH);
+ assertTrue(p.containerFileExists(null));
+ assertTrue(p.containerFileExists("mockup"));
+ assertFalse(p.containerFileExists("fake"));
+ }
+
+ @Test
+ public void testListpackageMapFiles() throws Exception {
+ StorageFileProvider p =
+ new StorageFileProvider(TestDataUtils.TESTDATA_PATH, TestDataUtils.TESTDATA_PATH);
+ // throw new Exception(Environment.getExternalStorageDirectory().getAbsolutePath());
+ List<Path> file = p.listPackageMapFiles();
+ assertEquals(1, file.size());
+ assertTrue(
+ file.get(0)
+ .equals(
+ Paths.get(
+ TestDataUtils.TESTDATA_PATH,
+ TestDataUtils.TEST_PACKAGE_MAP_PATH)));
+ }
+
+ @Test
+ public void testLoadFiles() throws Exception {
+ StorageFileProvider p =
+ new StorageFileProvider(TestDataUtils.TESTDATA_PATH, TestDataUtils.TESTDATA_PATH);
+ PackageTable pt = p.getPackageTable("mockup");
+ assertNotNull(pt);
+ pt =
+ StorageFileProvider.getPackageTable(
+ Paths.get(
+ TestDataUtils.TESTDATA_PATH, TestDataUtils.TEST_PACKAGE_MAP_PATH));
+ assertNotNull(pt);
+ FlagTable f = p.getFlagTable("mockup");
+ assertNotNull(f);
+ FlagValueList v = p.getFlagValueList("mockup");
+ assertNotNull(v);
+ }
+}
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/java/TestDataUtils.java b/tools/aconfig/aconfig_storage_read_api/tests/java/TestDataUtils.java
new file mode 100644
index 0000000..d5cddc7
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/tests/java/TestDataUtils.java
@@ -0,0 +1,52 @@
+/*
+ * 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/java/jarjar.txt b/tools/aconfig/aconfig_storage_read_api/tests/java/jarjar.txt
new file mode 100644
index 0000000..64ba09c
--- /dev/null
+++ b/tools/aconfig/aconfig_storage_read_api/tests/java/jarjar.txt
@@ -0,0 +1,17 @@
+rule android.aconfig.storage.AconfigStorageException android.aconfig.storage.test.AconfigStorageException
+rule android.aconfig.storage.FlagTable android.aconfig.storage.test.FlagTable
+rule android.aconfig.storage.PackageTable android.aconfig.storage.test.PackageTable
+rule android.aconfig.storage.ByteBufferReader android.aconfig.storage.test.ByteBufferReader
+rule android.aconfig.storage.FlagType android.aconfig.storage.test.FlagType
+rule android.aconfig.storage.SipHasher13 android.aconfig.storage.test.SipHasher13
+rule android.aconfig.storage.FileType android.aconfig.storage.test.FileType
+rule android.aconfig.storage.FlagValueList android.aconfig.storage.test.FlagValueList
+rule android.aconfig.storage.TableUtils android.aconfig.storage.test.TableUtils
+rule android.aconfig.storage.Package android.aconfig.storage.test.Package
+rule android.aconfig.storage.StorageFileProvider android.aconfig.storage.test.StorageFileProvider
+
+
+rule android.aconfig.storage.FlagTable$* android.aconfig.storage.test.FlagTable$@1
+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
diff --git a/tools/aconfig/aflags/src/load_protos.rs b/tools/aconfig/aflags/src/load_protos.rs
index f201d8f..c5ac8ff 100644
--- a/tools/aconfig/aflags/src/load_protos.rs
+++ b/tools/aconfig/aflags/src/load_protos.rs
@@ -51,7 +51,10 @@
let paths = aconfig_device_paths::parsed_flags_proto_paths()?;
for path in paths {
- let bytes = fs::read(path.clone())?;
+ let Ok(bytes) = fs::read(&path) else {
+ eprintln!("warning: failed to read {:?}", path);
+ continue;
+ };
let parsed_flags: ProtoParsedFlags = protobuf::Message::parse_from_bytes(&bytes)?;
for flag in parsed_flags.parsed_flag {
// TODO(b/334954748): enforce one-container-per-flag invariant.