Merge "Add dexpreopt files to ALL_MODULES.$(m).INSTALLED" into main
diff --git a/core/Makefile b/core/Makefile
index 863e560..f6b0401 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -1075,8 +1075,8 @@
 	done;
 	rm -rf $(TARGET_OUT_RAMDISK_16K)/lib/modules
 	mkdir -p $(TARGET_OUT_RAMDISK_16K)/lib/modules
-	KERNEL_RELEASE=`$(EXTRACT_KERNEL) --input $(BOARD_KERNEL_PATH_16K) --output-release /dev/stdout` ;\
-	IS_16K_KERNEL=`$(EXTRACT_KERNEL) --input $(BOARD_KERNEL_PATH_16K) --output-config /dev/stdout` ;\
+	KERNEL_RELEASE=`$(EXTRACT_KERNEL) --tools lz4:$(LZ4) --input $(BOARD_KERNEL_PATH_16K) --output-release` ;\
+	IS_16K_KERNEL=`$(EXTRACT_KERNEL) --tools lz4:$(LZ4) --input $(BOARD_KERNEL_PATH_16K) --output-config` ;\
 	if [[ "$$IS_16K_KERNEL" == *"CONFIG_ARM64_16K_PAGES=y"* ]]; then SUFFIX=_16k; fi ;\
 	cp -r $(RAMDISK_16K_STAGING_DIR)/lib/modules/0.0 $(TARGET_OUT_RAMDISK_16K)/lib/modules/$$KERNEL_RELEASE$$SUFFIX
 	$(MKBOOTFS) $(TARGET_OUT_RAMDISK_16K) | $(COMPRESSION_COMMAND) > $@
@@ -1208,6 +1208,29 @@
   $(if $(1),--partition_size $(1),--dynamic_partition_size)
 endef
 
+# $1: output boot image target
+# $2: input path to kernel binary
+define build_boot_from_kernel_avb_enabled
+  $(eval kernel := $(2))
+  $(MKBOOTIMG) --kernel $(kernel) $(INTERNAL_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $(1)
+  $(if $(BOARD_GKI_SIGNING_KEY_PATH), \
+    $(eval boot_signature := $(call intermediates-dir-for,PACKAGING,generic_boot)/$(notdir $(1)).boot_signature) \
+    $(eval kernel_signature := $(call intermediates-dir-for,PACKAGING,generic_kernel)/$(notdir $(kernel)).boot_signature) \
+    $(call generate_generic_boot_image_certificate,$(1),$(boot_signature),boot,$(BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS)) $(newline) \
+    $(call generate_generic_boot_image_certificate,$(kernel),$(kernel_signature),generic_kernel,$(BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS)) $(newline) \
+    cat $(kernel_signature) >> $(boot_signature) $(newline) \
+    $(call assert-max-image-size,$(boot_signature),16 << 10) $(newline) \
+    truncate -s $$(( 16 << 10 )) $(boot_signature) $(newline) \
+    cat "$(boot_signature)" >> $(1))
+  $(call assert-max-image-size,$(1),$(call get-hash-image-max-size,$(call get-bootimage-partition-size,$(1),boot)))
+  $(AVBTOOL) add_hash_footer \
+          --image $(1) \
+          $(call get-partition-size-argument,$(call get-bootimage-partition-size,$(1),boot)) \
+          --partition_name boot $(INTERNAL_AVB_BOOT_SIGNING_ARGS) \
+          $(BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS)
+endef
+
+
 ifndef BOARD_PREBUILT_BOOTIMAGE
 
 ifneq ($(strip $(TARGET_NO_KERNEL)),true)
@@ -1309,28 +1332,6 @@
 
 ifeq (true,$(BOARD_AVB_ENABLE))
 
-# $1: output boot image target
-# $2: input path to kernel binary
-define build_boot_from_kernel_avb_enabled
-  $(eval kernel := $(2))
-  $(MKBOOTIMG) --kernel $(kernel) $(INTERNAL_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $(1)
-  $(if $(BOARD_GKI_SIGNING_KEY_PATH), \
-    $(eval boot_signature := $(call intermediates-dir-for,PACKAGING,generic_boot)/$(notdir $(1)).boot_signature) \
-    $(eval kernel_signature := $(call intermediates-dir-for,PACKAGING,generic_kernel)/$(notdir $(kernel)).boot_signature) \
-    $(call generate_generic_boot_image_certificate,$(1),$(boot_signature),boot,$(BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS)) $(newline) \
-    $(call generate_generic_boot_image_certificate,$(kernel),$(kernel_signature),generic_kernel,$(BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS)) $(newline) \
-    cat $(kernel_signature) >> $(boot_signature) $(newline) \
-    $(call assert-max-image-size,$(boot_signature),16 << 10) $(newline) \
-    truncate -s $$(( 16 << 10 )) $(boot_signature) $(newline) \
-    cat "$(boot_signature)" >> $(1))
-  $(call assert-max-image-size,$(1),$(call get-hash-image-max-size,$(call get-bootimage-partition-size,$(1),boot)))
-  $(AVBTOOL) add_hash_footer \
-          --image $(1) \
-          $(call get-partition-size-argument,$(call get-bootimage-partition-size,$(1),boot)) \
-          --partition_name boot $(INTERNAL_AVB_BOOT_SIGNING_ARGS) \
-          $(BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS)
-endef
-
 # $1: boot image target
 define build_boot_board_avb_enabled
   $(eval kernel := $(call bootimage-to-kernel,$(1)))
@@ -5774,9 +5775,6 @@
 ifeq ($(BUILDING_WITH_VSDK),true)
 	$(hide) echo "building_with_vsdk=true" >> $@
 endif
-ifeq ($(TARGET_FLATTEN_APEX),false)
-	$(hide) echo "target_flatten_apex=false" >> $@
-endif
 
 $(call declare-0p-target,$(INSTALLED_FASTBOOT_INFO_TARGET))
 
diff --git a/core/board_config.mk b/core/board_config.mk
index c3a6864..2699512 100644
--- a/core/board_config.mk
+++ b/core/board_config.mk
@@ -971,24 +971,6 @@
 endif
 TARGET_VENDOR_TEST_SUFFIX := /vendor
 
-###########################################
-# APEXes are by default not flattened, i.e. updatable.
-#
-# APEX flattening can also be forcibly enabled (resp. disabled) by
-# setting OVERRIDE_TARGET_FLATTEN_APEX to true (resp. false), e.g. by
-# setting the OVERRIDE_TARGET_FLATTEN_APEX environment variable.
-ifdef OVERRIDE_TARGET_FLATTEN_APEX
-  TARGET_FLATTEN_APEX := $(OVERRIDE_TARGET_FLATTEN_APEX)
-endif
-
-# TODO(b/278826656) Remove the following message
-ifeq (true,$(TARGET_FLATTEN_APEX))
-  $(warning ********************************************************************************)
-  $(warning Flattened APEX will be deprecated soon. Please stop using flattened APEX and use)
-  $(warning "image" APEX instead.)
-  $(warning ********************************************************************************)
-endif
-
 ifeq (,$(TARGET_BUILD_UNBUNDLED))
 ifdef PRODUCT_EXTRA_VNDK_VERSIONS
   $(foreach v,$(PRODUCT_EXTRA_VNDK_VERSIONS),$(call check_vndk_version,$(v)))
diff --git a/core/config.mk b/core/config.mk
index 0809ced..ac49cec 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -408,22 +408,6 @@
 $(if $(findstring ro.config.low_ram=true,$(PRODUCT_ODM_PROPERTIES)),true,false)))))))))
 endef
 
-# Get the board API level.
-board_api_level := $(PLATFORM_SDK_VERSION)
-ifdef BOARD_API_LEVEL
-  board_api_level := $(BOARD_API_LEVEL)
-else ifdef BOARD_SHIPPING_API_LEVEL
-  # Vendors with GRF must define BOARD_SHIPPING_API_LEVEL for the vendor API level.
-  board_api_level := $(BOARD_SHIPPING_API_LEVEL)
-endif
-
-# Calculate the VSR vendor API level.
-vsr_vendor_api_level := $(board_api_level)
-
-ifdef PRODUCT_SHIPPING_API_LEVEL
-  vsr_vendor_api_level := $(call math_min,$(PRODUCT_SHIPPING_API_LEVEL),$(board_api_level))
-endif
-
 # Set TARGET_MAX_PAGE_SIZE_SUPPORTED.
 # TARGET_MAX_PAGE_SIZE_SUPPORTED indicates the alignment of the ELF segments.
 ifdef PRODUCT_MAX_PAGE_SIZE_SUPPORTED
@@ -435,7 +419,7 @@
   # The default binary alignment for userspace is 4096.
   TARGET_MAX_PAGE_SIZE_SUPPORTED := 4096
   # When VSR vendor API level >= 34, binary alignment will be 65536.
-  ifeq ($(call math_gt_or_eq,$(vsr_vendor_api_level),34),true)
+  ifeq ($(call math_gt_or_eq,$(VSR_VENDOR_API_LEVEL),34),true)
     ifeq ($(TARGET_ARCH),arm64)
       TARGET_MAX_PAGE_SIZE_SUPPORTED := 65536
     endif
@@ -946,13 +930,14 @@
 .KATI_READONLY := IS_TARGET_MIXED_SEPOLICY
 
 # A list of SEPolicy versions, besides PLATFORM_SEPOLICY_VERSION, that the framework supports.
-PLATFORM_SEPOLICY_COMPAT_VERSIONS := \
+PLATFORM_SEPOLICY_COMPAT_VERSIONS := $(filter-out $(PLATFORM_SEPOLICY_VERSION), \
     29.0 \
     30.0 \
     31.0 \
     32.0 \
     33.0 \
     34.0 \
+    )
 
 .KATI_READONLY := \
     PLATFORM_SEPOLICY_COMPAT_VERSIONS \
diff --git a/core/product.mk b/core/product.mk
index b66f1e2..bf85c78 100644
--- a/core/product.mk
+++ b/core/product.mk
@@ -430,6 +430,9 @@
 # specified we default to COW version 2 in update_engine for backwards compatibility
 _product_single_value_vars += PRODUCT_VIRTUAL_AB_COW_VERSION
 
+# If set, determines whether the build system checks vendor seapp contexts violations.
+_product_single_value_vars += PRODUCT_CHECK_VENDOR_SEAPP_VIOLATIONS
+
 _product_list_vars += PRODUCT_AFDO_PROFILES
 
 .KATI_READONLY := _product_single_value_vars _product_list_vars
diff --git a/core/product_config.mk b/core/product_config.mk
index 3f9eb24..832d6ad 100644
--- a/core/product_config.mk
+++ b/core/product_config.mk
@@ -572,6 +572,32 @@
       $(PRODUCT_ENFORCE_RRO_EXEMPTED_TARGETS))
 endif
 
+# Get the board API level.
+board_api_level := $(PLATFORM_SDK_VERSION)
+ifdef BOARD_API_LEVEL
+  board_api_level := $(BOARD_API_LEVEL)
+else ifdef BOARD_SHIPPING_API_LEVEL
+  # Vendors with GRF must define BOARD_SHIPPING_API_LEVEL for the vendor API level.
+  board_api_level := $(BOARD_SHIPPING_API_LEVEL)
+endif
+
+# Calculate the VSR vendor API level.
+VSR_VENDOR_API_LEVEL := $(board_api_level)
+
+ifdef PRODUCT_SHIPPING_API_LEVEL
+  VSR_VENDOR_API_LEVEL := $(call math_min,$(PRODUCT_SHIPPING_API_LEVEL),$(board_api_level))
+endif
+.KATI_READONLY := VSR_VENDOR_API_LEVEL
+
+# Boolean variable determining if vendor seapp contexts is enforced
+CHECK_VENDOR_SEAPP_VIOLATIONS := false
+ifneq ($(call math_gt,$(VSR_VENDOR_API_LEVEL),34),)
+  CHECK_VENDOR_SEAPP_VIOLATIONS := true
+else ifneq ($(PRODUCT_CHECK_VENDOR_SEAPP_VIOLATIONS),)
+  CHECK_VENDOR_SEAPP_VIOLATIONS := $(PRODUCT_CHECK_VENDOR_SEAPP_VIOLATIONS)
+endif
+.KATI_READONLY := CHECK_VENDOR_SEAPP_VIOLATIONS
+
 define product-overrides-config
 $$(foreach rule,$$(PRODUCT_$(1)_OVERRIDES),\
     $$(if $$(filter 2,$$(words $$(subst :,$$(space),$$(rule)))),,\
diff --git a/core/soong_config.mk b/core/soong_config.mk
index 26998ed..7d8092d 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -324,6 +324,8 @@
 
 $(call add_json_bool, KeepVndk, $(filter true,$(KEEP_VNDK)))
 
+$(call add_json_bool, CheckVendorSeappViolations, $(filter true,$(CHECK_VENDOR_SEAPP_VIOLATIONS)))
+
 $(call json_end)
 
 $(file >$(SOONG_VARIABLES).tmp,$(json_contents))
diff --git a/target/product/base_system.mk b/target/product/base_system.mk
index 001ed45..03de6a8 100644
--- a/target/product/base_system.mk
+++ b/target/product/base_system.mk
@@ -432,3 +432,6 @@
     frameworks/base/config/dirty-image-objects:system/etc/dirty-image-objects)
 
 $(call inherit-product, $(SRC_TARGET_DIR)/product/runtime_libart.mk)
+
+# Use "image" APEXes always.
+$(call inherit-product,$(SRC_TARGET_DIR)/product/updatable_apex.mk)
diff --git a/target/product/updatable_apex.mk b/target/product/updatable_apex.mk
index c19982b..8357fdf 100644
--- a/target/product/updatable_apex.mk
+++ b/target/product/updatable_apex.mk
@@ -14,17 +14,13 @@
 # limitations under the License.
 #
 
-# Inherit this when the target needs to support updating APEXes
+# com.android.apex.cts.shim.v1_prebuilt overrides CtsShimPrebuilt
+# and CtsShimPrivPrebuilt since they are packaged inside the APEX.
+PRODUCT_PACKAGES += com.android.apex.cts.shim.v1_prebuilt
+PRODUCT_SYSTEM_PROPERTIES := ro.apex.updatable=true
 
-ifneq ($(OVERRIDE_TARGET_FLATTEN_APEX),true)
-  # com.android.apex.cts.shim.v1_prebuilt overrides CtsShimPrebuilt
-  # and CtsShimPrivPrebuilt since they are packaged inside the APEX.
-  PRODUCT_PACKAGES += com.android.apex.cts.shim.v1_prebuilt
-  PRODUCT_SYSTEM_PROPERTIES := ro.apex.updatable=true
-  TARGET_FLATTEN_APEX := false
-  # Use compressed apexes in pre-installed partitions.
-  # Note: this doesn't mean that all pre-installed apexes will be compressed.
-  #  Whether an apex is compressed or not is controlled at apex Soong module
-  #  via compresible property.
-  PRODUCT_COMPRESSED_APEX := true
-endif
+# Use compressed apexes in pre-installed partitions.
+# Note: this doesn't mean that all pre-installed apexes will be compressed.
+#  Whether an apex is compressed or not is controlled at apex Soong module
+#  via compresible property.
+PRODUCT_COMPRESSED_APEX := true
diff --git a/tools/BUILD.bazel b/tools/BUILD.bazel
index 0de178b..2dbb585 100644
--- a/tools/BUILD.bazel
+++ b/tools/BUILD.bazel
@@ -1,6 +1,7 @@
 py_library(
     name = "event_log_tags",
     srcs = ["event_log_tags.py"],
+    imports = ["."],
 )
 
 py_binary(
diff --git a/tools/aconfig/protos/aconfig.proto b/tools/aconfig/protos/aconfig.proto
index 4cad69a..d5e2868 100644
--- a/tools/aconfig/protos/aconfig.proto
+++ b/tools/aconfig/protos/aconfig.proto
@@ -39,6 +39,7 @@
   optional string namespace = 2;
   optional string description = 3;
   repeated string bug = 4;
+  optional bool is_fixed_read_only = 5;
 };
 
 message flag_declarations {
@@ -75,6 +76,7 @@
   optional flag_state state = 6;
   optional flag_permission permission = 7;
   repeated tracepoint trace = 8;
+  optional bool is_fixed_read_only = 9;
 }
 
 message parsed_flags {
diff --git a/tools/aconfig/src/codegen_cpp.rs b/tools/aconfig/src/codegen_cpp.rs
index 30e564a..8c2d7ba 100644
--- a/tools/aconfig/src/codegen_cpp.rs
+++ b/tools/aconfig/src/codegen_cpp.rs
@@ -131,6 +131,8 @@
 
     virtual bool disabled_rw() = 0;
 
+    virtual bool enabled_fixed_ro() = 0;
+
     virtual bool enabled_ro() = 0;
 
     virtual bool enabled_rw() = 0;
@@ -146,6 +148,10 @@
     return provider_->disabled_rw();
 }
 
+inline bool enabled_fixed_ro() {
+    return true;
+}
+
 inline bool enabled_ro() {
     return true;
 }
@@ -163,6 +169,8 @@
 
 bool com_android_aconfig_test_disabled_rw();
 
+bool com_android_aconfig_test_enabled_fixed_ro();
+
 bool com_android_aconfig_test_enabled_ro();
 
 bool com_android_aconfig_test_enabled_rw();
@@ -194,6 +202,10 @@
 
     virtual void disabled_rw(bool val) = 0;
 
+    virtual bool enabled_fixed_ro() = 0;
+
+    virtual void enabled_fixed_ro(bool val) = 0;
+
     virtual bool enabled_ro() = 0;
 
     virtual void enabled_ro(bool val) = 0;
@@ -223,6 +235,14 @@
     provider_->disabled_rw(val);
 }
 
+inline bool enabled_fixed_ro() {
+    return provider_->enabled_fixed_ro();
+}
+
+inline void enabled_fixed_ro(bool val) {
+    provider_->enabled_fixed_ro(val);
+}
+
 inline bool enabled_ro() {
     return provider_->enabled_ro();
 }
@@ -256,6 +276,10 @@
 
 void set_com_android_aconfig_test_disabled_rw(bool val);
 
+bool com_android_aconfig_test_enabled_fixed_ro();
+
+void set_com_android_aconfig_test_enabled_fixed_ro(bool val);
+
 bool com_android_aconfig_test_enabled_ro();
 
 void set_com_android_aconfig_test_enabled_ro(bool val);
@@ -294,6 +318,10 @@
                     "false") == "true";
             }
 
+            virtual bool enabled_fixed_ro() override {
+                return true;
+            }
+
             virtual bool enabled_ro() override {
                 return true;
             }
@@ -319,6 +347,10 @@
     return com::android::aconfig::test::disabled_rw();
 }
 
+bool com_android_aconfig_test_enabled_fixed_ro() {
+    return true;
+}
+
 bool com_android_aconfig_test_enabled_ro() {
     return true;
 }
@@ -373,6 +405,19 @@
                 overrides_["disabled_rw"] = val;
             }
 
+            virtual bool enabled_fixed_ro() override {
+                auto it = overrides_.find("enabled_fixed_ro");
+                  if (it != overrides_.end()) {
+                      return it->second;
+                } else {
+                  return true;
+                }
+            }
+
+            virtual void enabled_fixed_ro(bool val) override {
+                overrides_["enabled_fixed_ro"] = val;
+            }
+
             virtual bool enabled_ro() override {
                 auto it = overrides_.find("enabled_ro");
                   if (it != overrides_.end()) {
@@ -402,7 +447,6 @@
                 overrides_["enabled_rw"] = val;
             }
 
-
             virtual void reset_flags() override {
                 overrides_.clear();
             }
@@ -430,6 +474,16 @@
     com::android::aconfig::test::disabled_rw(val);
 }
 
+
+bool com_android_aconfig_test_enabled_fixed_ro() {
+    return com::android::aconfig::test::enabled_fixed_ro();
+}
+
+void set_com_android_aconfig_test_enabled_fixed_ro(bool val) {
+    com::android::aconfig::test::enabled_fixed_ro(val);
+}
+
+
 bool com_android_aconfig_test_enabled_ro() {
     return com::android::aconfig::test::enabled_ro();
 }
diff --git a/tools/aconfig/src/codegen_java.rs b/tools/aconfig/src/codegen_java.rs
index 2c9dcf5..be0ec97 100644
--- a/tools/aconfig/src/codegen_java.rs
+++ b/tools/aconfig/src/codegen_java.rs
@@ -121,6 +121,7 @@
     public interface FeatureFlags {
         boolean disabledRo();
         boolean disabledRw();
+        boolean enabledFixedRo();
         boolean enabledRo();
         boolean enabledRw();
     "#;
@@ -130,6 +131,7 @@
     public final class Flags {
         public static final String FLAG_DISABLED_RO = "com.android.aconfig.test.disabled_ro";
         public static final String FLAG_DISABLED_RW = "com.android.aconfig.test.disabled_rw";
+        public static final String FLAG_ENABLED_FIXED_RO = "com.android.aconfig.test.enabled_fixed_ro";
         public static final String FLAG_ENABLED_RO = "com.android.aconfig.test.enabled_ro";
         public static final String FLAG_ENABLED_RW = "com.android.aconfig.test.enabled_rw";
 
@@ -139,6 +141,9 @@
         public static boolean disabledRw() {
             return FEATURE_FLAGS.disabledRw();
         }
+        public static boolean enabledFixedRo() {
+            return FEATURE_FLAGS.enabledFixedRo();
+        }
         public static boolean enabledRo() {
             return FEATURE_FLAGS.enabledRo();
         }
@@ -159,6 +164,11 @@
                 "Method is not implemented.");
         }
         @Override
+        public boolean enabledFixedRo() {
+            throw new UnsupportedOperationException(
+                "Method is not implemented.");
+        }
+        @Override
         public boolean enabledRo() {
             throw new UnsupportedOperationException(
                 "Method is not implemented.");
@@ -211,6 +221,10 @@
                 );
             }
             @Override
+            public boolean enabledFixedRo() {
+                return true;
+            }
+            @Override
             public boolean enabledRo() {
                 return true;
             }
@@ -311,6 +325,10 @@
                 return getFlag(Flags.FLAG_DISABLED_RW);
             }
             @Override
+            public boolean enabledFixedRo() {
+                return getFlag(Flags.FLAG_ENABLED_FIXED_RO);
+            }
+            @Override
             public boolean enabledRo() {
                 return getFlag(Flags.FLAG_ENABLED_RO);
             }
@@ -341,6 +359,7 @@
             private HashMap<String, Boolean> mFlagMap = Stream.of(
                     Flags.FLAG_DISABLED_RO,
                     Flags.FLAG_DISABLED_RW,
+                    Flags.FLAG_ENABLED_FIXED_RO,
                     Flags.FLAG_ENABLED_RO,
                     Flags.FLAG_ENABLED_RW
                 )
diff --git a/tools/aconfig/src/codegen_rust.rs b/tools/aconfig/src/codegen_rust.rs
index 0234eb2..4e4c7dd 100644
--- a/tools/aconfig/src/codegen_rust.rs
+++ b/tools/aconfig/src/codegen_rust.rs
@@ -108,6 +108,11 @@
             "false") == "true"
     }
 
+    /// query flag enabled_fixed_ro
+    pub fn enabled_fixed_ro(&self) -> bool {
+        true
+    }
+
     /// query flag enabled_ro
     pub fn enabled_ro(&self) -> bool {
         true
@@ -137,6 +142,12 @@
     PROVIDER.disabled_rw()
 }
 
+/// query flag enabled_fixed_ro
+#[inline(always)]
+pub fn enabled_fixed_ro() -> bool {
+    true
+}
+
 /// query flag enabled_ro
 #[inline(always)]
 pub fn enabled_ro() -> bool {
@@ -189,6 +200,18 @@
         self.overrides.insert("disabled_rw", val);
     }
 
+    /// query flag enabled_fixed_ro
+    pub fn enabled_fixed_ro(&self) -> bool {
+        self.overrides.get("enabled_fixed_ro").copied().unwrap_or(
+            true
+        )
+    }
+
+    /// set flag enabled_fixed_ro
+    pub fn set_enabled_fixed_ro(&mut self, val: bool) {
+        self.overrides.insert("enabled_fixed_ro", val);
+    }
+
     /// query flag enabled_ro
     pub fn enabled_ro(&self) -> bool {
         self.overrides.get("enabled_ro").copied().unwrap_or(
@@ -251,6 +274,18 @@
     PROVIDER.lock().unwrap().set_disabled_rw(val);
 }
 
+/// query flag enabled_fixed_ro
+#[inline(always)]
+pub fn enabled_fixed_ro() -> bool {
+    PROVIDER.lock().unwrap().enabled_fixed_ro()
+}
+
+/// set flag enabled_fixed_ro
+#[inline(always)]
+pub fn set_enabled_fixed_ro(val: bool) {
+    PROVIDER.lock().unwrap().set_enabled_fixed_ro(val);
+}
+
 /// query flag enabled_ro
 #[inline(always)]
 pub fn enabled_ro() -> bool {
diff --git a/tools/aconfig/src/commands.rs b/tools/aconfig/src/commands.rs
index ab5b0f2..e4baa82 100644
--- a/tools/aconfig/src/commands.rs
+++ b/tools/aconfig/src/commands.rs
@@ -91,11 +91,17 @@
             parsed_flag.set_description(flag_declaration.take_description());
             parsed_flag.bug.append(&mut flag_declaration.bug);
             parsed_flag.set_state(DEFAULT_FLAG_STATE);
-            parsed_flag.set_permission(default_permission);
+            let flag_permission = if flag_declaration.is_fixed_read_only() {
+                ProtoFlagPermission::READ_ONLY
+            } else {
+                default_permission
+            };
+            parsed_flag.set_permission(flag_permission);
+            parsed_flag.set_is_fixed_read_only(flag_declaration.is_fixed_read_only());
             let mut tracepoint = ProtoTracepoint::new();
             tracepoint.set_source(input.source.clone());
             tracepoint.set_state(DEFAULT_FLAG_STATE);
-            tracepoint.set_permission(default_permission);
+            tracepoint.set_permission(flag_permission);
             parsed_flag.trace.push(tracepoint);
 
             // verify ParsedFlag looks reasonable
@@ -135,6 +141,13 @@
                 continue;
             };
 
+            ensure!(
+                !parsed_flag.is_fixed_read_only()
+                    || flag_value.permission() == ProtoFlagPermission::READ_ONLY,
+                "failed to set permission of flag {}, since this flag is fixed read only flag",
+                flag_value.name()
+            );
+
             parsed_flag.set_state(flag_value.state());
             parsed_flag.set_permission(flag_value.permission());
             let mut tracepoint = ProtoTracepoint::new();
@@ -310,6 +323,7 @@
         assert_eq!(ProtoFlagState::ENABLED, enabled_ro.state());
         assert_eq!(ProtoFlagPermission::READ_ONLY, enabled_ro.permission());
         assert_eq!(3, enabled_ro.trace.len());
+        assert!(!enabled_ro.is_fixed_read_only());
         assert_eq!("tests/test.aconfig", enabled_ro.trace[0].source());
         assert_eq!(ProtoFlagState::DISABLED, enabled_ro.trace[0].state());
         assert_eq!(ProtoFlagPermission::READ_WRITE, enabled_ro.trace[0].permission());
@@ -320,8 +334,11 @@
         assert_eq!(ProtoFlagState::ENABLED, enabled_ro.trace[2].state());
         assert_eq!(ProtoFlagPermission::READ_ONLY, enabled_ro.trace[2].permission());
 
-        assert_eq!(4, parsed_flags.parsed_flag.len());
+        assert_eq!(5, parsed_flags.parsed_flag.len());
         for pf in parsed_flags.parsed_flag.iter() {
+            if pf.name() == "enabled_fixed_ro" {
+                continue;
+            }
             let first = pf.trace.first().unwrap();
             assert_eq!(DEFAULT_FLAG_STATE, first.state());
             assert_eq!(DEFAULT_FLAG_PERMISSION, first.permission());
@@ -330,6 +347,15 @@
             assert_eq!(pf.state(), last.state());
             assert_eq!(pf.permission(), last.permission());
         }
+
+        let enabled_fixed_ro =
+            parsed_flags.parsed_flag.iter().find(|pf| pf.name() == "enabled_fixed_ro").unwrap();
+        assert!(enabled_fixed_ro.is_fixed_read_only());
+        assert_eq!(ProtoFlagState::ENABLED, enabled_fixed_ro.state());
+        assert_eq!(ProtoFlagPermission::READ_ONLY, enabled_fixed_ro.permission());
+        assert_eq!(2, enabled_fixed_ro.trace.len());
+        assert_eq!(ProtoFlagPermission::READ_ONLY, enabled_fixed_ro.trace[0].permission());
+        assert_eq!(ProtoFlagPermission::READ_ONLY, enabled_fixed_ro.trace[1].permission());
     }
 
     #[test]
@@ -363,6 +389,46 @@
     }
 
     #[test]
+    fn test_parse_flags_override_fixed_read_only() {
+        let first_flag = r#"
+        package: "com.first"
+        flag {
+            name: "first"
+            namespace: "first_ns"
+            description: "This is the description of the first flag."
+            bug: "123"
+            is_fixed_read_only: true
+        }
+        "#;
+        let declaration =
+            vec![Input { source: "memory".to_string(), reader: Box::new(first_flag.as_bytes()) }];
+
+        let first_flag_value = r#"
+        flag_value {
+            package: "com.first"
+            name: "first"
+            state: DISABLED
+            permission: READ_WRITE
+        }
+        "#;
+        let value = vec![Input {
+            source: "memory".to_string(),
+            reader: Box::new(first_flag_value.as_bytes()),
+        }];
+        let error = crate::commands::parse_flags(
+            "com.first",
+            declaration,
+            value,
+            ProtoFlagPermission::READ_WRITE,
+        )
+        .unwrap_err();
+        assert_eq!(
+            format!("{:?}", error),
+            "failed to set permission of flag first, since this flag is fixed read only flag"
+        );
+    }
+
+    #[test]
     fn test_create_device_config_defaults() {
         let input = parse_test_flags_as_input();
         let bytes = create_device_config_defaults(input).unwrap();
diff --git a/tools/aconfig/src/protos.rs b/tools/aconfig/src/protos.rs
index c3911e5..b93abcc 100644
--- a/tools/aconfig/src/protos.rs
+++ b/tools/aconfig/src/protos.rs
@@ -303,6 +303,7 @@
     namespace: "second_ns"
     description: "This is the description of the second flag."
     bug: "abc"
+    is_fixed_read_only: true
 }
 "#,
         )
@@ -313,11 +314,13 @@
         assert_eq!(first.namespace(), "first_ns");
         assert_eq!(first.description(), "This is the description of the first flag.");
         assert_eq!(first.bug, vec!["123"]);
+        assert!(!first.is_fixed_read_only());
         let second = flag_declarations.flag.iter().find(|pf| pf.name() == "second").unwrap();
         assert_eq!(second.name(), "second");
         assert_eq!(second.namespace(), "second_ns");
         assert_eq!(second.description(), "This is the description of the second flag.");
         assert_eq!(second.bug, vec!["abc"]);
+        assert!(second.is_fixed_read_only());
 
         // bad input: missing package in flag declarations
         let error = flag_declarations::try_from_text_proto(
@@ -555,6 +558,7 @@
         state: ENABLED
         permission: READ_WRITE
     }
+    is_fixed_read_only: true
 }
 "#;
         let parsed_flags = try_from_binary_proto_from_text_proto(text_proto).unwrap();
@@ -574,6 +578,7 @@
         assert_eq!(second.trace[1].source(), "flags.values");
         assert_eq!(second.trace[1].state(), ProtoFlagState::ENABLED);
         assert_eq!(second.trace[1].permission(), ProtoFlagPermission::READ_WRITE);
+        assert!(second.is_fixed_read_only());
 
         // valid input: empty
         let parsed_flags = try_from_binary_proto_from_text_proto("").unwrap();
diff --git a/tools/aconfig/src/test.rs b/tools/aconfig/src/test.rs
index 6c27885..9034704 100644
--- a/tools/aconfig/src/test.rs
+++ b/tools/aconfig/src/test.rs
@@ -41,6 +41,7 @@
     state: DISABLED
     permission: READ_ONLY
   }
+  is_fixed_read_only: false
 }
 parsed_flag {
   package: "com.android.aconfig.test"
@@ -55,6 +56,27 @@
     state: DISABLED
     permission: READ_WRITE
   }
+  is_fixed_read_only: false
+}
+parsed_flag {
+  package: "com.android.aconfig.test"
+  name: "enabled_fixed_ro"
+  namespace: "aconfig_test"
+  description: "This flag is fixed READ_ONLY + ENABLED"
+  bug: ""
+  state: ENABLED
+  permission: READ_ONLY
+  trace {
+    source: "tests/test.aconfig"
+    state: DISABLED
+    permission: READ_ONLY
+  }
+  trace {
+    source: "tests/first.values"
+    state: ENABLED
+    permission: READ_ONLY
+  }
+  is_fixed_read_only: true
 }
 parsed_flag {
   package: "com.android.aconfig.test"
@@ -79,6 +101,7 @@
     state: ENABLED
     permission: READ_ONLY
   }
+  is_fixed_read_only: false
 }
 parsed_flag {
   package: "com.android.aconfig.test"
@@ -98,6 +121,7 @@
     state: ENABLED
     permission: READ_WRITE
   }
+  is_fixed_read_only: false
 }
 "#;
 
diff --git a/tools/aconfig/tests/AconfigTest.java b/tools/aconfig/tests/AconfigTest.java
index 317289d..79b5a55 100644
--- a/tools/aconfig/tests/AconfigTest.java
+++ b/tools/aconfig/tests/AconfigTest.java
@@ -1,9 +1,11 @@
 import static com.android.aconfig.test.Flags.FLAG_DISABLED_RO;
 import static com.android.aconfig.test.Flags.FLAG_DISABLED_RW;
+import static com.android.aconfig.test.Flags.FLAG_ENABLED_FIXED_RO;
 import static com.android.aconfig.test.Flags.FLAG_ENABLED_RO;
 import static com.android.aconfig.test.Flags.FLAG_ENABLED_RW;
 import static com.android.aconfig.test.Flags.disabledRo;
 import static com.android.aconfig.test.Flags.disabledRw;
+import static com.android.aconfig.test.Flags.enabledFixedRo;
 import static com.android.aconfig.test.Flags.enabledRo;
 import static com.android.aconfig.test.Flags.enabledRw;
 import static org.junit.Assert.assertEquals;
@@ -35,6 +37,14 @@
     }
 
     @Test
+    public void testEnabledFixedReadOnlyFlag() {
+        assertEquals("com.android.aconfig.test.enabled_fixed_ro", FLAG_ENABLED_FIXED_RO);
+        // TODO: change to assertTrue(enabledFixedRo()) when the build supports reading tests/*.values
+        // (currently all flags are assigned the default READ_ONLY + DISABLED)
+        assertFalse(enabledFixedRo());
+    }
+
+    @Test
     public void testDisabledReadWriteFlag() {
         assertEquals("com.android.aconfig.test.enabled_ro", FLAG_ENABLED_RO);
         assertFalse(disabledRw());
diff --git a/tools/aconfig/tests/first.values b/tools/aconfig/tests/first.values
index e524404..a450f78 100644
--- a/tools/aconfig/tests/first.values
+++ b/tools/aconfig/tests/first.values
@@ -16,3 +16,9 @@
     state: ENABLED
     permission: READ_WRITE
 }
+flag_value {
+    package: "com.android.aconfig.test"
+    name: "enabled_fixed_ro"
+    state: ENABLED
+    permission: READ_ONLY
+}
diff --git a/tools/aconfig/tests/test.aconfig b/tools/aconfig/tests/test.aconfig
index 46cf1e9..aaa6df5 100644
--- a/tools/aconfig/tests/test.aconfig
+++ b/tools/aconfig/tests/test.aconfig
@@ -40,3 +40,14 @@
     description: "This flag is DISABLED + READ_WRITE"
     bug: "456"
 }
+
+# This flag's final value calculated from:
+# - test.aconfig: DISABLED + READ_ONLY
+# - first.values: ENABLED + READ_ONLY
+flag {
+    name: "enabled_fixed_ro"
+    namespace: "aconfig_test"
+    description: "This flag is fixed READ_ONLY + ENABLED"
+    bug: ""
+    is_fixed_read_only: true
+}
diff --git a/tools/releasetools/Android.bp b/tools/releasetools/Android.bp
index c785c8e..bd347a1 100644
--- a/tools/releasetools/Android.bp
+++ b/tools/releasetools/Android.bp
@@ -165,6 +165,7 @@
         "ota_utils_lib",
     ],
     required: [
+        "apexd_host",
         "brillo_update_payload",
         "checkvintf",
         "generate_gki_certificate",
@@ -643,6 +644,7 @@
         },
     },
     required: [
+        "apexd_host",
         "deapexer",
     ],
 }
diff --git a/tools/releasetools/ota_utils.py b/tools/releasetools/ota_utils.py
index 8993da9..9b3367e 100644
--- a/tools/releasetools/ota_utils.py
+++ b/tools/releasetools/ota_utils.py
@@ -897,30 +897,7 @@
     """
     assert isinstance(payload_signer, PayloadSigner)
 
-    # 1. Generate hashes of the payload and metadata files.
-    payload_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
-    metadata_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
-    cmd = ["brillo_update_payload", "hash",
-           "--unsigned_payload", self.payload_file,
-           "--signature_size", str(payload_signer.maximum_signature_size),
-           "--metadata_hash_file", metadata_sig_file,
-           "--payload_hash_file", payload_sig_file]
-    self._Run(cmd)
-
-    # 2. Sign the hashes.
-    signed_payload_sig_file = payload_signer.SignHashFile(payload_sig_file)
-    signed_metadata_sig_file = payload_signer.SignHashFile(metadata_sig_file)
-
-    # 3. Insert the signatures back into the payload file.
-    signed_payload_file = common.MakeTempFile(prefix="signed-payload-",
-                                              suffix=".bin")
-    cmd = ["brillo_update_payload", "sign",
-           "--unsigned_payload", self.payload_file,
-           "--payload", signed_payload_file,
-           "--signature_size", str(payload_signer.maximum_signature_size),
-           "--metadata_signature_file", signed_metadata_sig_file,
-           "--payload_signature_file", signed_payload_sig_file]
-    self._Run(cmd)
+    signed_payload_file = payload_signer.SignPayload(self.payload_file)
 
     self.payload_file = signed_payload_file
 
diff --git a/tools/releasetools/payload_signer.py b/tools/releasetools/payload_signer.py
index 9933aef..bbd2896 100644
--- a/tools/releasetools/payload_signer.py
+++ b/tools/releasetools/payload_signer.py
@@ -95,11 +95,11 @@
     # 1. Generate hashes of the payload and metadata files.
     payload_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
     metadata_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
-    cmd = ["brillo_update_payload", "hash",
-           "--unsigned_payload", unsigned_payload,
-           "--signature_size", str(self.maximum_signature_size),
-           "--metadata_hash_file", metadata_sig_file,
-           "--payload_hash_file", payload_sig_file]
+    cmd = ["delta_generator",
+           "--in_file=" + unsigned_payload,
+           "--signature_size=" + str(self.maximum_signature_size),
+           "--out_metadata_hash_file=" + metadata_sig_file,
+           "--out_hash_file=" + payload_sig_file]
     self._Run(cmd)
 
     # 2. Sign the hashes.
@@ -109,16 +109,15 @@
     # 3. Insert the signatures back into the payload file.
     signed_payload_file = common.MakeTempFile(prefix="signed-payload-",
                                               suffix=".bin")
-    cmd = ["brillo_update_payload", "sign",
-           "--unsigned_payload", unsigned_payload,
-           "--payload", signed_payload_file,
-           "--signature_size", str(self.maximum_signature_size),
-           "--metadata_signature_file", signed_metadata_sig_file,
-           "--payload_signature_file", signed_payload_sig_file]
+    cmd = ["delta_generator",
+           "--in_file=" + unsigned_payload,
+           "--out_file=" + signed_payload_file,
+           "--signature_size=" + str(self.maximum_signature_size),
+           "--metadata_signature_file=" + signed_metadata_sig_file,
+           "--payload_signature_file=" + signed_payload_sig_file]
     self._Run(cmd)
     return signed_payload_file
 
-
   def SignHashFile(self, in_file):
     """Signs the given input file. Returns the output filename."""
     out_file = common.MakeTempFile(prefix="signed-", suffix=".bin")