Merge "Extend merge_ota with extra options for signapk.jar" into main
diff --git a/ci/build_test_suites.py b/ci/build_test_suites.py
index 7602c64..cdcba5a 100644
--- a/ci/build_test_suites.py
+++ b/ci/build_test_suites.py
@@ -84,46 +84,16 @@
     packaging_commands_getters = []
     # In order to roll optimizations out differently between test suites and
     # device builds, we have separate flags.
-    if (
-        'test_suites_zip_test_discovery'
+    enable_discovery = ('test_suites_zip_test_discovery'
         in self.build_context.enabled_build_features
         and not self.args.device_build
     ) or (
         'device_zip_test_discovery'
         in self.build_context.enabled_build_features
         and self.args.device_build
-    ):
-      preliminary_build_targets = self._collect_preliminary_build_targets()
-    else:
-      preliminary_build_targets = self._legacy_collect_preliminary_build_targets()
-
-      # Keep reporting metrics when test discovery is disabled.
-      # To be removed once test discovery is fully rolled out.
-      optimization_rationale = ''
-      test_discovery_zip_regexes = set()
-      try:
-        test_discovery_zip_regexes = self._get_test_discovery_zip_regexes()
-        logging.info(f'Discovered test discovery regexes: {test_discovery_zip_regexes}')
-      except test_discovery_agent.TestDiscoveryError as e:
-        optimization_rationale = e.message
-        logging.warning(f'Unable to perform test discovery: {optimization_rationale}')
-
-      for target in self.args.extra_targets:
-        if optimization_rationale:
-          get_metrics_agent().report_unoptimized_target(target, optimization_rationale)
-          continue
-        if target in REQUIRED_BUILD_TARGETS:
-          get_metrics_agent().report_unoptimized_target(target, 'Required build target.')
-          continue
-        try:
-          regex = r'\b(%s.*)\b' % re.escape(target)
-          if any(re.search(regex, opt) for opt in test_discovery_zip_regexes):
-            get_metrics_agent().report_unoptimized_target(target, 'Test artifact used.')
-            continue
-          get_metrics_agent().report_optimized_target(target)
-        except Exception as e:
-          logging.error(f'unable to parse test discovery output: {repr(e)}')
-          get_metrics_agent().report_unoptimized_target(target, f'Error in parsing test discovery output for {target}: {repr(e)}')
+    )
+    logging.info(f'Discovery mode is enabled= {enable_discovery}')
+    preliminary_build_targets = self._collect_preliminary_build_targets(enable_discovery)
 
     for target in preliminary_build_targets:
       target_optimizer_getter = self.target_optimizations.get(target, None)
@@ -141,7 +111,7 @@
 
     return BuildPlan(build_targets, packaging_commands_getters)
 
-  def _collect_preliminary_build_targets(self):
+  def _collect_preliminary_build_targets(self, enable_discovery: bool):
     build_targets = set()
     try:
       test_discovery_zip_regexes = self._get_test_discovery_zip_regexes()
@@ -159,6 +129,10 @@
         build_targets.add(target)
         get_metrics_agent().report_unoptimized_target(target, 'Required build target.')
         continue
+      # If nothing is discovered without error, that means nothing is needed.
+      if not test_discovery_zip_regexes:
+        get_metrics_agent().report_optimized_target(target)
+        continue
 
       regex = r'\b(%s.*)\b' % re.escape(target)
       for opt in test_discovery_zip_regexes:
@@ -175,6 +149,9 @@
           get_metrics_agent().report_unoptimized_target(target, f'Error in parsing test discovery output for {target}: {repr(e)}')
           logging.error(f'unable to parse test discovery output: {repr(e)}')
           break
+    # If discovery is not enabled, return the original list
+    if not enable_discovery:
+      return self._legacy_collect_preliminary_build_targets()
 
     return build_targets
 
diff --git a/core/Makefile b/core/Makefile
index 3ba931c..a951715 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -885,11 +885,6 @@
 $(call declare-1p-target,$(SOONG_TO_CONVERT),build)
 $(call dist-for-goals,droidcore-unbundled,$(SOONG_TO_CONVERT))
 
-$(PRODUCT_OUT)/product_packages.txt:
-	@rm -f $@
-	echo "" > $@
-	$(foreach x,$(PRODUCT_PACKAGES),echo $(x) >> $@$(newline))
-
 MK2BP_CATALOG_SCRIPT := build/make/tools/mk2bp_catalog.py
 PRODUCT_PACKAGES_TXT := $(PRODUCT_OUT)/product_packages.txt
 MK2BP_REMAINING_HTML := $(PRODUCT_OUT)/mk2bp_remaining.html
diff --git a/core/soong_config.mk b/core/soong_config.mk
index ace025e..739905d 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -370,6 +370,7 @@
   $(firstword $(OVERRIDE_ENABLE_UFFD_GC) $(PRODUCT_ENABLE_UFFD_GC) default)
 $(call add_json_str, EnableUffdGc, $(_config_enable_uffd_gc))
 _config_enable_uffd_gc :=
+$(call add_json_str, BoardKernelVersion, $(BOARD_KERNEL_VERSION))
 
 $(call add_json_list, DeviceFrameworkCompatibilityMatrixFile, $(DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE))
 $(call add_json_list, DeviceProductCompatibilityMatrixFile, $(DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE))
diff --git a/target/board/generic_64bitonly_x86_64/device.mk b/target/board/generic_64bitonly_x86_64/device.mk
index bb49057..5edf5e0 100644
--- a/target/board/generic_64bitonly_x86_64/device.mk
+++ b/target/board/generic_64bitonly_x86_64/device.mk
@@ -17,8 +17,3 @@
 ifdef NET_ETH0_STARTONBOOT
   PRODUCT_PROPERTY_OVERRIDES += net.eth0.startonboot=1
 endif
-
-# Ensure we package the BIOS files too.
-PRODUCT_HOST_PACKAGES += \
-    bios.bin \
-    vgabios-cirrus.bin \
diff --git a/target/board/generic_x86/device.mk b/target/board/generic_x86/device.mk
index 60f0cc3..27fb310 100644
--- a/target/board/generic_x86/device.mk
+++ b/target/board/generic_x86/device.mk
@@ -17,8 +17,3 @@
 ifdef NET_ETH0_STARTONBOOT
   PRODUCT_VENDOR_PROPERTIES += net.eth0.startonboot=1
 endif
-
-# Ensure we package the BIOS files too.
-PRODUCT_HOST_PACKAGES += \
-	bios.bin \
-	vgabios-cirrus.bin \
diff --git a/target/product/base_system.mk b/target/product/base_system.mk
index 52498ee..b3b58d3 100644
--- a/target/product/base_system.mk
+++ b/target/product/base_system.mk
@@ -489,6 +489,7 @@
 
 PRODUCT_SYSTEM_PROPERTIES += debug.atrace.tags.enableflags=0
 PRODUCT_SYSTEM_PROPERTIES += persist.traced.enable=1
+PRODUCT_SYSTEM_PROPERTIES += ro.surface_flinger.game_default_frame_rate_override=60
 
 # Include kernel configs.
 PRODUCT_PACKAGES += \
diff --git a/target/product/full_x86.mk b/target/product/full_x86.mk
index 07f6472..a1b71ca 100644
--- a/target/product/full_x86.mk
+++ b/target/product/full_x86.mk
@@ -32,11 +32,6 @@
   PRODUCT_VENDOR_PROPERTIES += net.eth0.startonboot=1
 endif
 
-# Ensure we package the BIOS files too.
-PRODUCT_HOST_PACKAGES += \
-	bios.bin \
-	vgabios-cirrus.bin \
-
 # Enable dynamic partition size
 PRODUCT_USE_DYNAMIC_PARTITION_SIZE := true
 
diff --git a/target/product/generic/Android.bp b/target/product/generic/Android.bp
index 75af062..5d7ec9a 100644
--- a/target/product/generic/Android.bp
+++ b/target/product/generic/Android.bp
@@ -470,7 +470,6 @@
         "locksettings", // base_system
         "logcat", // base_system
         "logd", // base_system
-        "logpersist.start",
         "lpdump", // base_system
         "lshal", // base_system
         "make_f2fs", // media_system
@@ -527,7 +526,6 @@
         "sfdo", // base_system
         "sgdisk", // base_system
         "sm", // base_system
-        "snapshotctl", // base_system
         "snapuserd", // base_system
         "storaged", // base_system
         "surfaceflinger", // base_system
@@ -585,6 +583,7 @@
             "iperf3",
             "iw",
             "layertracegenerator",
+            "logpersist.start",
             "logtagd.rc",
             "ot-cli-ftd",
             "ot-ctl",
@@ -595,6 +594,7 @@
             "sanitizer-status",
             "servicedispatcher",
             "showmap",
+            "snapshotctl",
             "sqlite3",
             "ss",
             "start_with_lockagent",
@@ -911,4 +911,9 @@
         compressor: "lz4hc,9",
         compress_hints: "erofs_compress_hints.txt",
     },
+    deps: [
+        // DO NOT update this list. Instead, update the system_image_defaults to
+        // sync with the base_system.mk
+        "logpersist.start", // cf only
+    ],
 }
diff --git a/tools/aconfig/aconfig/src/codegen/cpp.rs b/tools/aconfig/aconfig/src/codegen/cpp.rs
index ae18679..d7d77c5 100644
--- a/tools/aconfig/aconfig/src/codegen/cpp.rs
+++ b/tools/aconfig/aconfig/src/codegen/cpp.rs
@@ -24,7 +24,7 @@
 
 use crate::codegen;
 use crate::codegen::CodegenMode;
-use crate::commands::OutputFile;
+use crate::commands::{should_include_flag, OutputFile};
 
 pub fn generate_cpp_code<I>(
     package: &str,
@@ -127,10 +127,7 @@
     flag_ids: HashMap<String, u16>,
     rw_count: &mut i32,
 ) -> ClassElement {
-    let no_assigned_offset =
-        (pf.container() == "system" || pf.container() == "vendor" || pf.container() == "product")
-            && pf.permission() == ProtoFlagPermission::READ_ONLY
-            && pf.state() == ProtoFlagState::DISABLED;
+    let no_assigned_offset = !should_include_flag(pf);
 
     let flag_offset = match flag_ids.get(pf.name()) {
         Some(offset) => offset,
diff --git a/tools/aconfig/aconfig/src/codegen/java.rs b/tools/aconfig/aconfig/src/codegen/java.rs
index 0d528d2..81340f2 100644
--- a/tools/aconfig/aconfig/src/codegen/java.rs
+++ b/tools/aconfig/aconfig/src/codegen/java.rs
@@ -22,7 +22,7 @@
 
 use crate::codegen;
 use crate::codegen::CodegenMode;
-use crate::commands::OutputFile;
+use crate::commands::{should_include_flag, OutputFile};
 use aconfig_protos::{ProtoFlagPermission, ProtoFlagState, ProtoParsedFlag};
 use std::collections::HashMap;
 
@@ -162,10 +162,7 @@
     let device_config_flag = codegen::create_device_config_ident(package, pf.name())
         .expect("values checked at flag parse time");
 
-    let no_assigned_offset =
-        (pf.container() == "system" || pf.container() == "vendor" || pf.container() == "product")
-            && pf.permission() == ProtoFlagPermission::READ_ONLY
-            && pf.state() == ProtoFlagState::DISABLED;
+    let no_assigned_offset = !should_include_flag(pf);
 
     let flag_offset = match flag_offsets.get(pf.name()) {
         Some(offset) => offset,
diff --git a/tools/aconfig/aconfig/src/codegen/rust.rs b/tools/aconfig/aconfig/src/codegen/rust.rs
index 2bf565a..74da1bc 100644
--- a/tools/aconfig/aconfig/src/codegen/rust.rs
+++ b/tools/aconfig/aconfig/src/codegen/rust.rs
@@ -24,7 +24,7 @@
 
 use crate::codegen;
 use crate::codegen::CodegenMode;
-use crate::commands::OutputFile;
+use crate::commands::{should_include_flag, OutputFile};
 
 pub fn generate_rust_code<I>(
     package: &str,
@@ -88,18 +88,12 @@
 impl TemplateParsedFlag {
     #[allow(clippy::nonminimal_bool)]
     fn new(package: &str, flag_offsets: HashMap<String, u16>, pf: &ProtoParsedFlag) -> Self {
-        let no_assigned_offset = (pf.container() == "system"
-            || pf.container() == "vendor"
-            || pf.container() == "product")
-            && pf.permission() == ProtoFlagPermission::READ_ONLY
-            && pf.state() == ProtoFlagState::DISABLED;
-
         let flag_offset = match flag_offsets.get(pf.name()) {
             Some(offset) => offset,
             None => {
                 // System/vendor/product RO+disabled flags have no offset in storage files.
                 // Assign placeholder value.
-                if no_assigned_offset {
+                if !should_include_flag(pf) {
                     &0
                 }
                 // All other flags _must_ have an offset.
diff --git a/tools/aconfig/aconfig/src/commands.rs b/tools/aconfig/aconfig/src/commands.rs
index 547076f..2f96015 100644
--- a/tools/aconfig/aconfig/src/commands.rs
+++ b/tools/aconfig/aconfig/src/commands.rs
@@ -221,13 +221,13 @@
     new_exported: bool,
 ) -> Result<Vec<OutputFile>> {
     let parsed_flags = input.try_parse_flags()?;
-    let modified_parsed_flags = modify_parsed_flags_based_on_mode(parsed_flags, codegen_mode)?;
+    let modified_parsed_flags =
+        modify_parsed_flags_based_on_mode(parsed_flags.clone(), codegen_mode)?;
     let Some(package) = find_unique_package(&modified_parsed_flags) else {
         bail!("no parsed flags, or the parsed flags use different packages");
     };
     let package = package.to_string();
-    let mut flag_names =
-        modified_parsed_flags.iter().map(|pf| pf.name().to_string()).collect::<Vec<_>>();
+    let mut flag_names = extract_flag_names(parsed_flags)?;
     let package_fingerprint = compute_flags_fingerprint(&mut flag_names);
     let flag_ids = assign_flag_ids(&package, modified_parsed_flags.iter())?;
     generate_java_code(
@@ -436,14 +436,7 @@
             return Err(anyhow::anyhow!("the number of flags in a package cannot exceed 65535"));
         }
 
-        // Exclude system/vendor/product flags that are RO+disabled.
-        let should_filter_container = pf.container == Some("vendor".to_string())
-            || pf.container == Some("system".to_string())
-            || pf.container == Some("product".to_string());
-        if !(should_filter_container
-            && pf.state == Some(ProtoFlagState::DISABLED.into())
-            && pf.permission == Some(ProtoFlagPermission::READ_ONLY.into()))
-        {
+        if should_include_flag(pf) {
             flag_ids.insert(pf.name().to_string(), flag_idx as u16);
             flag_idx += 1;
         }
@@ -451,10 +444,8 @@
     Ok(flag_ids)
 }
 
-#[allow(dead_code)] // TODO: b/316357686 - Use fingerprint in codegen to
-                    // protect hardcoded offset reads.
-                    // Creates a fingerprint of the flag names (which requires sorting the vector).
-                    // Fingerprint is used by both codegen and storage files.
+// Creates a fingerprint of the flag names (which requires sorting the vector).
+// Fingerprint is used by both codegen and storage files.
 pub fn compute_flags_fingerprint(flag_names: &mut Vec<String>) -> u64 {
     flag_names.sort();
 
@@ -465,11 +456,9 @@
     hasher.finish()
 }
 
-#[allow(dead_code)] // TODO: b/316357686 - Use fingerprint in codegen to
-                    // protect hardcoded offset reads.
-                    // Converts ProtoParsedFlags into a vector of strings containing all of the flag
-                    // names. Helper fn for creating fingerprint for codegen files. Flags must all
-                    // belong to the same package.
+// Converts ProtoParsedFlags into a vector of strings containing all of the flag
+// names. Helper fn for creating fingerprint for codegen files. Flags must all
+// belong to the same package.
 fn extract_flag_names(flags: ProtoParsedFlags) -> Result<Vec<String>> {
     let separated_flags: Vec<ProtoParsedFlag> = flags.parsed_flag.into_iter().collect::<Vec<_>>();
 
@@ -478,7 +467,23 @@
         bail!("No parsed flags, or the parsed flags use different packages.");
     };
 
-    Ok(separated_flags.into_iter().map(|flag| flag.name.unwrap()).collect::<Vec<_>>())
+    Ok(separated_flags
+        .into_iter()
+        .filter(should_include_flag)
+        .map(|flag| flag.name.unwrap())
+        .collect::<Vec<_>>())
+}
+
+// Exclude system/vendor/product flags that are RO+disabled.
+pub fn should_include_flag(pf: &ProtoParsedFlag) -> bool {
+    let should_filter_container = pf.container == Some("vendor".to_string())
+        || pf.container == Some("system".to_string())
+        || pf.container == Some("product".to_string());
+
+    let disabled_ro = pf.state == Some(ProtoFlagState::DISABLED.into())
+        && pf.permission == Some(ProtoFlagPermission::READ_ONLY.into());
+
+    !should_filter_container || !disabled_ro
 }
 
 #[cfg(test)]
@@ -489,7 +494,7 @@
     #[test]
     fn test_offset_fingerprint() {
         let parsed_flags = crate::test::parse_test_flags();
-        let expected_fingerprint: u64 = 5801144784618221668;
+        let expected_fingerprint: u64 = 11551379960324242360;
 
         let mut extracted_flags = extract_flag_names(parsed_flags).unwrap();
         let hash_result = compute_flags_fingerprint(&mut extracted_flags);
@@ -509,6 +514,7 @@
             .parsed_flag
             .clone()
             .into_iter()
+            .filter(should_include_flag)
             .map(|flag| flag.name.unwrap())
             .map(String::from)
             .collect::<Vec<_>>();
diff --git a/tools/aconfig/aconfig/src/storage/flag_table.rs b/tools/aconfig/aconfig/src/storage/flag_table.rs
index 3b245a7..a3b4e8f 100644
--- a/tools/aconfig/aconfig/src/storage/flag_table.rs
+++ b/tools/aconfig/aconfig/src/storage/flag_table.rs
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-use crate::commands::assign_flag_ids;
+use crate::commands::{assign_flag_ids, should_include_flag};
 use crate::storage::FlagPackage;
-use aconfig_protos::{ProtoFlagPermission, ProtoFlagState};
+use aconfig_protos::ProtoFlagPermission;
 use aconfig_storage_file::{
     get_table_size, FlagTable, FlagTableHeader, FlagTableNode, StorageFileType, StoredFlagType,
 };
@@ -64,13 +64,7 @@
     fn create_nodes(package: &FlagPackage, num_buckets: u32) -> Result<Vec<Self>> {
         // Exclude system/vendor/product flags that are RO+disabled.
         let mut filtered_package = package.clone();
-        filtered_package.boolean_flags.retain(|f| {
-            !((f.container == Some("system".to_string())
-                || f.container == Some("vendor".to_string())
-                || f.container == Some("product".to_string()))
-                && f.permission == Some(ProtoFlagPermission::READ_ONLY.into())
-                && f.state == Some(ProtoFlagState::DISABLED.into()))
-        });
+        filtered_package.boolean_flags.retain(|pf| should_include_flag(pf));
 
         let flag_ids =
             assign_flag_ids(package.package_name, filtered_package.boolean_flags.iter().copied())?;
diff --git a/tools/aconfig/aconfig/templates/cpp_source_file.template b/tools/aconfig/aconfig/templates/cpp_source_file.template
index 9be59e0..325dbdc 100644
--- a/tools/aconfig/aconfig/templates/cpp_source_file.template
+++ b/tools/aconfig/aconfig/templates/cpp_source_file.template
@@ -29,25 +29,103 @@
     private:
         std::unordered_map<std::string, bool> overrides_;
 
+    {{ if allow_instrumentation- }}
+        uint32_t boolean_start_index_;
+
+        std::unique_ptr<aconfig_storage::MappedStorageFile> flag_value_file_;
+
+        bool package_exists_in_storage_;
+    {{ -endif }}
+
     public:
+    {{ if allow_instrumentation- }}
+        flag_provider()
+            : overrides_()
+            , boolean_start_index_()
+            , flag_value_file_(nullptr)
+            , package_exists_in_storage_(true) \{
+
+            auto package_map_file = aconfig_storage::get_mapped_file(
+                 "{container}",
+                 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;
+            }
+
+            // cache package boolean flag start index
+            boolean_start_index_ = context->boolean_start_index;
+
+            // unmap package map file and free memory
+            delete *package_map_file;
+
+            auto flag_value_file = aconfig_storage::get_mapped_file(
+                "{container}",
+                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
+            flag_value_file_ = std::unique_ptr<aconfig_storage::MappedStorageFile>(
+                *flag_value_file);
+
+        }
+    {{ -else }}
         flag_provider()
             : overrides_()
         \{}
+    {{ -endif }}
 
 {{ for item in class_elements }}
         virtual bool {item.flag_name}() override \{
             auto it = overrides_.find("{item.flag_name}");
-              if (it != overrides_.end()) \{
-                  return it->second;
+            if (it != overrides_.end()) \{
+                return it->second;
             } else \{
-              {{ if item.readwrite- }}
-              return server_configurable_flags::GetServerConfigurableFlag(
+                {{ if item.readwrite- }}
+                {{ if allow_instrumentation- }}
+                if (!package_exists_in_storage_) \{
+                    return {item.default_value};
+                }
+
+                auto value = aconfig_storage::get_boolean_flag_value(
+                    *flag_value_file_,
+                    boolean_start_index_ + {item.flag_offset});
+
+                if (!value.ok()) \{
+                    ALOGE("error: failed to read flag value: %s", value.error().c_str());
+                    return {item.default_value};
+                } else \{
+                    return *value;
+                }
+                {{ -else }}
+                return server_configurable_flags::GetServerConfigurableFlag(
                   "aconfig_flags.{item.device_config_namespace}",
                   "{item.device_config_flag}",
                   "{item.default_value}") == "true";
-              {{ -else }}
-                  return {item.default_value};
-              {{ -endif }}
+                {{ -endif }}
+                {{ -else }}
+                return {item.default_value};
+                {{ -endif }}
             }
         }
 
@@ -66,15 +144,11 @@
     class flag_provider : public flag_provider_interface \{
     public:
 
-        {{ if allow_instrumentation- }}
         {{ if readwrite- }}
+        {{ if allow_instrumentation- }}
         flag_provider()
-            {{ if readwrite- }}
             : cache_({readwrite_count}, -1)
             , boolean_start_index_()
-            {{ -else- }}
-            : boolean_start_index_()
-            {{ -endif }}
             , flag_value_file_(nullptr)
             , package_exists_in_storage_(true) \{
 
@@ -138,6 +212,7 @@
 
                 if (!value.ok()) \{
                     ALOGE("error: failed to read flag value: %s", value.error().c_str());
+                    return {item.default_value};
                 }
 
                 cache_[{item.readwrite_idx}] = *value;