Merge "Set BUILD_FROM_SOURCE_STUB=true for finalization" into main
diff --git a/core/art_config.mk b/core/art_config.mk
index 1ea05db..f47a8e2 100644
--- a/core/art_config.mk
+++ b/core/art_config.mk
@@ -44,3 +44,17 @@
 endif
 
 ADDITIONAL_PRODUCT_PROPERTIES += ro.dalvik.vm.enable_uffd_gc=$(ENABLE_UFFD_GC)
+
+# Create APEX_BOOT_JARS_EXCLUDED which is a list of jars to be removed from
+# ApexBoorJars when built from mainline prebuilts.
+# soong variables indicate whether the prebuilt is enabled:
+# - $(m)_module/source_build for art and TOGGLEABLE_PREBUILT_MODULES
+# - ANDROID/module_build_from_source for other mainline modules
+APEX_BOOT_JARS_EXCLUDED :=
+$(foreach pair, $(PRODUCT_APEX_BOOT_JARS_FOR_SOURCE_BUILD_ONLY),\
+  $(eval m := $(subst com.android.,,$(call word-colon,1,$(pair)))) \
+  $(if $(call soong_config_get,$(m)_module,source_build), \
+    $(if $(filter true,$(call soong_config_get,$(m)_module,source_build)),, \
+      $(eval APEX_BOOT_JARS_EXCLUDED += $(pair))), \
+    $(if $(filter true,$(call soong_config_get,ANDROID,module_build_from_source)),, \
+      $(eval APEX_BOOT_JARS_EXCLUDED += $(pair)))))
diff --git a/core/board_config.mk b/core/board_config.mk
index ba887ce..537fb73 100644
--- a/core/board_config.mk
+++ b/core/board_config.mk
@@ -989,6 +989,21 @@
 endif
 
 ###########################################
+# BOARD_API_LEVEL for vendor API surface
+ifdef RELEASE_BOARD_API_LEVEL
+  ifdef BOARD_API_LEVEL
+    $(error BOARD_API_LEVEL must not set manully. The build system automatically sets this value.)
+  endif
+  BOARD_API_LEVEL := $(RELEASE_BOARD_API_LEVEL)
+  .KATI_READONLY := BOARD_API_LEVEL
+
+  ifdef RELEASE_BOARD_API_LEVEL_FROZEN
+    BOARD_API_LEVEL_FROZEN := true
+    .KATI_READONLY := BOARD_API_LEVEL_FROZEN
+  endif
+endif
+
+###########################################
 # Handle BUILD_BROKEN_USES_BUILD_*
 
 $(foreach m,$(DEFAULT_WARNING_BUILD_MODULE_TYPES),\
diff --git a/core/dex_preopt_config.mk b/core/dex_preopt_config.mk
index badf189..10fbe8f 100644
--- a/core/dex_preopt_config.mk
+++ b/core/dex_preopt_config.mk
@@ -94,7 +94,7 @@
   $(call add_json_bool, DisableGenerateProfile,                  $(filter false,$(WITH_DEX_PREOPT_GENERATE_PROFILE)))
   $(call add_json_str,  ProfileDir,                              $(PRODUCT_DEX_PREOPT_PROFILE_DIR))
   $(call add_json_list, BootJars,                                $(PRODUCT_BOOT_JARS))
-  $(call add_json_list, ApexBootJars,                            $(PRODUCT_APEX_BOOT_JARS))
+  $(call add_json_list, ApexBootJars,                            $(filter-out $(APEX_BOOT_JARS_EXCLUDED), $(PRODUCT_APEX_BOOT_JARS)))
   $(call add_json_list, ArtApexJars,                             $(filter $(PRODUCT_BOOT_JARS),$(ART_APEX_JARS)))
   $(call add_json_list, TestOnlyArtBootImageJars,                $(PRODUCT_TEST_ONLY_ART_BOOT_IMAGE_JARS))
   $(call add_json_list, SystemServerJars,                        $(PRODUCT_SYSTEM_SERVER_JARS))
diff --git a/core/main.mk b/core/main.mk
index c30f1d0..367b5bf 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -293,16 +293,22 @@
 
 # Vendors with GRF must define BOARD_SHIPPING_API_LEVEL for the vendor API level.
 # This must not be defined for the non-GRF devices.
+# The values of the GRF properties will be verified by post_process_props.py
 ifdef BOARD_SHIPPING_API_LEVEL
 ADDITIONAL_VENDOR_PROPERTIES += \
     ro.board.first_api_level=$(BOARD_SHIPPING_API_LEVEL)
+endif
 
-# To manually set the vendor API level of the vendor modules, BOARD_API_LEVEL can be used.
-# The values of the GRF properties will be verified by post_process_props.py
+# Build system set BOARD_API_LEVEL to show the api level of the vendor API surface.
+# This must not be altered outside of build system.
 ifdef BOARD_API_LEVEL
 ADDITIONAL_VENDOR_PROPERTIES += \
     ro.board.api_level=$(BOARD_API_LEVEL)
 endif
+# BOARD_API_LEVEL_FROZEN is true when the vendor API surface is frozen.
+ifdef BOARD_API_LEVEL_FROZEN
+ADDITIONAL_VENDOR_PROPERTIES += \
+    ro.board.api_frozen=$(BOARD_API_LEVEL_FROZEN)
 endif
 
 # Set build prop. This prop is read by ota_from_target_files when generating OTA,
diff --git a/core/release_config.mk b/core/release_config.mk
index 6428b0d..68dd876 100644
--- a/core/release_config.mk
+++ b/core/release_config.mk
@@ -82,28 +82,32 @@
 )
 FLAG_DECLARATION_FILES :=
 
-# If TARGET_RELEASE is set, fail if there is no matching release config
-# If it isn't set, no release config files will be included and all flags
-# will get their default values.
-ifneq ($(TARGET_RELEASE),)
+ifeq ($(TARGET_RELEASE),)
+    # We allow some internal paths to explicitly set TARGET_RELEASE to the
+    # empty string.  For the most part, 'make' treats unset and empty string as
+    # the same.  But the following line differentiates, and will only assign
+    # if the variable was completely unset.
+    TARGET_RELEASE ?= was_unset
+    ifeq ($(TARGET_RELEASE),was_unset)
+        $(error No release config set for target; please set TARGET_RELEASE, or if building on the command line use 'lunch <target>-<release>-<build_type>', where release is one of: $(_all_release_configs))
+    endif
+    # Instead of leaving this string empty, we want to default to a valid
+    # setting.  Full builds coming through this path is a bug, but in case
+    # of such a bug, we want to at least get consistent, valid results.
+    TARGET_RELEASE = trunk_staging
+endif
+
 ifeq ($(filter $(_all_release_configs), $(TARGET_RELEASE)),)
     $(error No release config found for TARGET_RELEASE: $(TARGET_RELEASE). Available releases are: $(_all_release_configs))
-else
-    # Choose flag files
-    # Don't sort this, use it in the order they gave us.
-    # Do allow duplicate entries, retaining only the first usage.
-    flag_value_files :=
-    $(foreach f,$(_all_release_configs.$(TARGET_RELEASE).FILES), \
-      $(if $(filter $(f),$(flag_value_files)),,$(eval flag_value_files += $(f)))\
-    )
 endif
-else
-# Useful for finding scripts etc that aren't passing or setting TARGET_RELEASE
-ifneq ($(FAIL_IF_NO_RELEASE_CONFIG),)
-    $(error FAIL_IF_NO_RELEASE_CONFIG was set and TARGET_RELEASE was not)
-endif
+
+# Choose flag files
+# Don't sort this, use it in the order they gave us.
+# Do allow duplicate entries, retaining only the first usage.
 flag_value_files :=
-endif
+$(foreach f,$(_all_release_configs.$(TARGET_RELEASE).FILES), \
+  $(if $(filter $(f),$(flag_value_files)),,$(eval flag_value_files += $(f)))\
+)
 
 # Unset variables so they can't use them
 define declare-release-config
diff --git a/core/soong_cc_rust_prebuilt.mk b/core/soong_cc_rust_prebuilt.mk
index 143931b..94e1115 100644
--- a/core/soong_cc_rust_prebuilt.mk
+++ b/core/soong_cc_rust_prebuilt.mk
@@ -129,8 +129,13 @@
   ifdef LOCAL_SHARED_LIBRARIES
     my_shared_libraries := $(LOCAL_SHARED_LIBRARIES)
     ifdef LOCAL_USE_VNDK
-      my_shared_libraries := $(foreach l,$(my_shared_libraries),\
-        $(if $(SPLIT_VENDOR.SHARED_LIBRARIES.$(l)),$(l).vendor,$(l)))
+      ifdef LOCAL_USE_VNDK_PRODUCT
+        my_shared_libraries := $(foreach l,$(my_shared_libraries),\
+          $(if $(SPLIT_PRODUCT.SHARED_LIBRARIES.$(l)),$(l).product,$(l)))
+      else
+        my_shared_libraries := $(foreach l,$(my_shared_libraries),\
+          $(if $(SPLIT_VENDOR.SHARED_LIBRARIES.$(l)),$(l).vendor,$(l)))
+      endif
     endif
     $(LOCAL_2ND_ARCH_VAR_PREFIX)$(my_prefix)DEPENDENCIES_ON_SHARED_LIBRARIES += \
       $(my_register_name):$(LOCAL_INSTALLED_MODULE):$(subst $(space),$(comma),$(my_shared_libraries))
@@ -139,8 +144,13 @@
     my_dylibs := $(LOCAL_DYLIB_LIBRARIES)
     # Treat these as shared library dependencies for installation purposes.
     ifdef LOCAL_USE_VNDK
-      my_dylibs := $(foreach l,$(my_dylibs),\
-        $(if $(SPLIT_VENDOR.SHARED_LIBRARIES.$(l)),$(l).vendor,$(l)))
+      ifdef LOCAL_USE_VNDK_PRODUCT
+        my_dylibs := $(foreach l,$(my_dylibs),\
+          $(if $(SPLIT_PRODUCT.SHARED_LIBRARIES.$(l)),$(l).product,$(l)))
+      else
+        my_dylibs := $(foreach l,$(my_dylibs),\
+          $(if $(SPLIT_VENDOR.SHARED_LIBRARIES.$(l)),$(l).vendor,$(l)))
+      endif
     endif
     $(LOCAL_2ND_ARCH_VAR_PREFIX)$(my_prefix)DEPENDENCIES_ON_SHARED_LIBRARIES += \
       $(my_register_name):$(LOCAL_INSTALLED_MODULE):$(subst $(space),$(comma),$(my_dylibs))
diff --git a/core/soong_config.mk b/core/soong_config.mk
index e39f2fa..08e9a65 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -164,7 +164,7 @@
 $(call add_json_list, ModulesLoadedByPrivilegedModules,  $(PRODUCT_LOADED_BY_PRIVILEGED_MODULES))
 
 $(call add_json_list, BootJars,                          $(PRODUCT_BOOT_JARS))
-$(call add_json_list, ApexBootJars,                      $(PRODUCT_APEX_BOOT_JARS))
+$(call add_json_list, ApexBootJars,                      $(filter-out $(APEX_BOOT_JARS_EXCLUDED), $(PRODUCT_APEX_BOOT_JARS)))
 
 $(call add_json_bool, VndkUseCoreVariant,                $(TARGET_VNDK_USE_CORE_VARIANT))
 $(call add_json_bool, VndkSnapshotBuildArtifacts,        $(VNDK_SNAPSHOT_BUILD_ARTIFACTS))
diff --git a/target/product/base_system.mk b/target/product/base_system.mk
index e3ebaa3..69a2abf 100644
--- a/target/product/base_system.mk
+++ b/target/product/base_system.mk
@@ -53,7 +53,6 @@
     com.android.btservices \
     com.android.configinfrastructure \
     com.android.conscrypt \
-    com.android.crashrecovery \
     com.android.devicelock \
     com.android.extservices \
     com.android.healthfitness \
diff --git a/target/product/default_art_config.mk b/target/product/default_art_config.mk
index f7c92aa..bc11fea 100644
--- a/target/product/default_art_config.mk
+++ b/target/product/default_art_config.mk
@@ -56,6 +56,8 @@
     ims-common
 
 # APEX boot jars. Keep the list sorted by module names and then library names.
+# Note: If the existing apex introduces the new jar, also add it to
+# PRODUCT_APEX_BOOT_JARS_FOR_SOURCE_BUILD_ONLY below.
 # Note: core-icu4j is moved back to PRODUCT_BOOT_JARS in product_config.mk at a later stage.
 # Note: For modules available in Q, DO NOT add new entries here.
 PRODUCT_APEX_BOOT_JARS := \
@@ -65,7 +67,6 @@
     com.android.btservices:framework-bluetooth \
     com.android.configinfrastructure:framework-configinfrastructure \
     com.android.conscrypt:conscrypt \
-    com.android.crashrecovery:framework-crashrecovery \
     com.android.devicelock:framework-devicelock \
     com.android.healthfitness:framework-healthfitness \
     com.android.i18n:core-icu4j \
@@ -85,6 +86,12 @@
     com.android.virt:framework-virtualization \
     com.android.wifi:framework-wifi \
 
+# TODO(b/308174306): Adjust this after multiple prebuilts version is supported.
+# APEX boot jars that are not in prebuilt apexes.
+# Keep the list sorted by module names and then library names.
+PRODUCT_APEX_BOOT_JARS_FOR_SOURCE_BUILD_ONLY := \
+    com.android.mediaprovider:framework-pdf \
+
 # List of system_server classpath jars delivered via apex.
 # Keep the list sorted by module names and then library names.
 # Note: For modules available in Q, DO NOT add new entries here.
@@ -94,7 +101,6 @@
     com.android.appsearch:service-appsearch \
     com.android.art:service-art \
     com.android.configinfrastructure:service-configinfrastructure \
-    com.android.crashrecovery:service-crashrecovery \
     com.android.healthfitness:service-healthfitness \
     com.android.media:service-media-s \
     com.android.ondevicepersonalization:service-ondevicepersonalization \
diff --git a/tools/aconfig/Android.bp b/tools/aconfig/Android.bp
index 1ad9053..e2fadb0 100644
--- a/tools/aconfig/Android.bp
+++ b/tools/aconfig/Android.bp
@@ -58,6 +58,7 @@
         "libaconfig_protos",
         "libanyhow",
         "libclap",
+        "libitertools",
         "libprotobuf",
         "libserde",
         "libserde_json",
diff --git a/tools/aconfig/Cargo.toml b/tools/aconfig/Cargo.toml
index 941b30d..2edf4b8 100644
--- a/tools/aconfig/Cargo.toml
+++ b/tools/aconfig/Cargo.toml
@@ -11,6 +11,7 @@
 [dependencies]
 anyhow = "1.0.69"
 clap = { version = "4.1.8", features = ["derive"] }
+itertools = "0.10.5"
 paste = "1.0.11"
 protobuf = "3.2.0"
 serde = { version = "1.0.152", features = ["derive"] }
diff --git a/tools/aconfig/src/codegen_java.rs b/tools/aconfig/src/codegen_java.rs
index 05ee0d7..954eccc 100644
--- a/tools/aconfig/src/codegen_java.rs
+++ b/tools/aconfig/src/codegen_java.rs
@@ -15,6 +15,7 @@
  */
 
 use anyhow::Result;
+use itertools::Itertools;
 use serde::Serialize;
 use std::collections::BTreeSet;
 use std::path::PathBuf;
@@ -34,12 +35,18 @@
 {
     let flag_elements: Vec<FlagElement> =
         parsed_flags_iter.map(|pf| create_flag_element(package, pf)).collect();
+    let namespace_set: BTreeSet<String> = flag_elements
+        .iter()
+        .unique_by(|f| &f.device_config_namespace)
+        .map(|f| f.device_config_namespace.clone())
+        .collect();
     let properties_set: BTreeSet<String> =
         flag_elements.iter().map(|fe| format_property_name(&fe.device_config_namespace)).collect();
     let is_read_write = flag_elements.iter().any(|elem| elem.is_read_write);
     let is_test_mode = codegen_mode == CodegenMode::Test;
     let context = Context {
         flag_elements,
+        namespace_set,
         is_test_mode,
         is_read_write,
         properties_set,
@@ -75,6 +82,7 @@
 #[derive(Serialize)]
 struct Context {
     pub flag_elements: Vec<FlagElement>,
+    pub namespace_set: BTreeSet<String>,
     pub is_test_mode: bool,
     pub is_read_write: bool,
     pub properties_set: BTreeSet<String>,
@@ -289,7 +297,31 @@
         import android.provider.DeviceConfig.Properties;
         /** @hide */
         public final class FeatureFlagsImpl implements FeatureFlags {
-            private Properties mPropertiesAconfigTest;
+            private static boolean aconfig_test_is_cached = false;
+            private static boolean disabledRw = false;
+            private static boolean enabledRw = true;
+
+
+            private void load_overrides_aconfig_test() {
+                try {
+                    Properties properties = DeviceConfig.getProperties("aconfig_test");
+                    disabledRw =
+                        properties.getBoolean("com.android.aconfig.test.disabled_rw", false);
+                    enabledRw =
+                        properties.getBoolean("com.android.aconfig.test.enabled_rw", true);
+                } catch (NullPointerException e) {
+                    throw new RuntimeException(
+                        "Cannot read value from namespace aconfig_test "
+                        + "from DeviceConfig. It could be that the code using flag "
+                        + "executed before SettingsProvider initialization. Please use "
+                        + "fixed read-only flag by adding is_fixed_read_only: true in "
+                        + "flag declaration.",
+                        e
+                    );
+                }
+                aconfig_test_is_cached = true;
+            }
+
             @Override
             @UnsupportedAppUsage
             public boolean disabledRo() {
@@ -298,18 +330,10 @@
             @Override
             @UnsupportedAppUsage
             public boolean disabledRw() {
-                if (mPropertiesAconfigTest == null) {
-                    mPropertiesAconfigTest =
-                        getProperties(
-                            "aconfig_test",
-                            "com.android.aconfig.test.disabled_rw"
-                        );
+                if (!aconfig_test_is_cached) {
+                    load_overrides_aconfig_test();
                 }
-                return mPropertiesAconfigTest
-                    .getBoolean(
-                        "com.android.aconfig.test.disabled_rw",
-                        false
-                    );
+                return disabledRw;
             }
             @Override
             @UnsupportedAppUsage
@@ -324,36 +348,10 @@
             @Override
             @UnsupportedAppUsage
             public boolean enabledRw() {
-                if (mPropertiesAconfigTest == null) {
-                    mPropertiesAconfigTest =
-                        getProperties(
-                            "aconfig_test",
-                            "com.android.aconfig.test.enabled_rw"
-                        );
+                if (!aconfig_test_is_cached) {
+                    load_overrides_aconfig_test();
                 }
-                return mPropertiesAconfigTest
-                    .getBoolean(
-                        "com.android.aconfig.test.enabled_rw",
-                        true
-                    );
-            }
-            private Properties getProperties(
-                String namespace,
-                String flagName) {
-                Properties properties = null;
-                try {
-                    properties = DeviceConfig.getProperties(namespace);
-                } catch (NullPointerException e) {
-                    throw new RuntimeException(
-                        "Cannot read value of flag " + flagName + " from DeviceConfig. "
-                        + "It could be that the code using flag executed "
-                        + "before SettingsProvider initialization. "
-                        + "Please use fixed read-only flag by adding "
-                        + "is_fixed_read_only: true in flag declaration.",
-                        e
-                    );
-                }
-                return properties;
+                return enabledRw;
             }
         }
         "#;
diff --git a/tools/aconfig/templates/FeatureFlagsImpl.java.template b/tools/aconfig/templates/FeatureFlagsImpl.java.template
index ff089df..87d567c 100644
--- a/tools/aconfig/templates/FeatureFlagsImpl.java.template
+++ b/tools/aconfig/templates/FeatureFlagsImpl.java.template
@@ -8,10 +8,41 @@
 {{ endif }}
 /** @hide */
 public final class FeatureFlagsImpl implements FeatureFlags \{
-{{ if is_read_write- }}
-{{ for properties in properties_set }}
-    private Properties {properties};
+{{- if is_read_write }}
+{{- for namespace in namespace_set }}
+    private static boolean {namespace}_is_cached = false;
+{{- endfor- }}
+
+{{ for flag in flag_elements }}
+{{- if flag.is_read_write }}
+    private static boolean {flag.method_name} = {flag.default_value};
+{{- endif- }}
 {{ endfor }}
+
+{{ for namespace in namespace_set }}
+    private void load_overrides_{namespace}() \{
+        try \{
+            Properties properties = DeviceConfig.getProperties("{namespace}");
+
+            {{- for flag in flag_elements }}
+            {{- if flag.is_read_write }}
+            {flag.method_name} =
+                properties.getBoolean("{flag.device_config_flag}", {flag.default_value});
+            {{- endif- }}
+            {{ endfor }}
+        } catch (NullPointerException e) \{
+            throw new RuntimeException(
+                "Cannot read value from namespace {namespace} "
+                + "from DeviceConfig. It could be that the code using flag "
+                + "executed before SettingsProvider initialization. Please use "
+                + "fixed read-only flag by adding is_fixed_read_only: true in "
+                + "flag declaration.",
+                e
+            );
+        }
+        {namespace}_is_cached = true;
+    }
+{{ endfor- }}
 {{ endif- }}
 
 {{ for flag in flag_elements }}
@@ -19,45 +50,15 @@
     @UnsupportedAppUsage
     public boolean {flag.method_name}() \{
     {{ -if flag.is_read_write }}
-        if ({flag.properties} == null) \{
-            {flag.properties} =
-                getProperties(
-                    "{flag.device_config_namespace}",
-                    "{flag.device_config_flag}"
-                );
+        if (!{flag.device_config_namespace}_is_cached) \{
+            load_overrides_{flag.device_config_namespace}();
         }
-        return {flag.properties}
-                .getBoolean(
-                    "{flag.device_config_flag}",
-                    {flag.default_value}
-                );
+        return {flag.method_name};
     {{ else }}
         return {flag.default_value};
     {{ endif- }}
     }
 {{ endfor }}
-
-{{ -if is_read_write }}
-    private Properties getProperties(
-            String namespace,
-            String flagName) \{
-        Properties properties = null;
-        try \{
-            properties = DeviceConfig.getProperties(namespace);
-        } catch (NullPointerException e) \{
-            throw new RuntimeException(
-                "Cannot read value of flag " + flagName + " from DeviceConfig. "
-                + "It could be that the code using flag executed "
-                + "before SettingsProvider initialization. "
-                + "Please use fixed read-only flag by adding "
-                + "is_fixed_read_only: true in flag declaration.",
-                e
-            );
-        }
-
-        return properties;
-    }
-{{ endif- }}
 }
 {{ else }}
 {#- Generate only stub if in test mode #}
@@ -70,6 +71,6 @@
         throw new UnsupportedOperationException(
             "Method is not implemented.");
     }
-{{ endfor }}
+{{ endfor- }}
 }
 {{ endif }}
diff --git a/tools/post_process_props.py b/tools/post_process_props.py
index 31a460d..32829c1 100755
--- a/tools/post_process_props.py
+++ b/tools/post_process_props.py
@@ -39,54 +39,26 @@
         val = val + ",adb"
       prop_list.put("persist.sys.usb.config", val)
 
-def validate_grf_props(prop_list, sdk_version):
+def validate_grf_props(prop_list):
   """Validate GRF properties if exist.
 
-  If ro.board.first_api_level is defined, check if its value is valid for the
-  sdk version. This is only for the release version.
-  Also, validate the value of ro.board.api_level if defined.
+  If ro.board.first_api_level is defined, check if its value is valid.
 
   Returns:
     True if the GRF properties are valid.
   """
   grf_api_level = prop_list.get_value("ro.board.first_api_level")
   board_api_level = prop_list.get_value("ro.board.api_level")
-  platform_version_codename = prop_list.get_value("ro.build.version.codename")
 
-  if not grf_api_level:
-    if board_api_level:
-      sys.stderr.write("error: non-GRF device must not define "
-                       "ro.board.api_level\n")
-      return False
-    # non-GRF device skips the GRF validation test
-    return True
-
-  grf_api_level = int(grf_api_level)
-  if board_api_level:
+  if grf_api_level and board_api_level:
+    grf_api_level = int(grf_api_level)
     board_api_level = int(board_api_level)
     if board_api_level < grf_api_level:
-      sys.stderr.write("error: ro.board.api_level(%d) must be greater than "
+      sys.stderr.write("error: ro.board.api_level(%d) must not be less than "
                        "ro.board.first_api_level(%d)\n"
                        % (board_api_level, grf_api_level))
       return False
 
-  # skip sdk version validation for dev-stage non-REL devices
-  if platform_version_codename != "REL":
-    return True
-
-  if grf_api_level > sdk_version:
-    sys.stderr.write("error: ro.board.first_api_level(%d) must be less than "
-                     "or equal to ro.build.version.sdk(%d)\n"
-                     % (grf_api_level, sdk_version))
-    return False
-
-  if board_api_level:
-    if board_api_level > sdk_version:
-      sys.stderr.write("error: ro.board.api_level(%d) must be less than or "
-                       "equal to ro.build.version.sdk(%d)\n"
-                       % (board_api_level, sdk_version))
-      return False
-
   return True
 
 def validate(prop_list):
@@ -271,7 +243,7 @@
   mangle_build_prop(props)
   if not override_optional_props(props, args.allow_dup):
     sys.exit(1)
-  if not validate_grf_props(props, args.sdk_version):
+  if not validate_grf_props(props):
     sys.exit(1)
   if not validate(props):
     sys.exit(1)
diff --git a/tools/test_post_process_props.py b/tools/test_post_process_props.py
index 439fc9f..2addefc 100644
--- a/tools/test_post_process_props.py
+++ b/tools/test_post_process_props.py
@@ -255,29 +255,17 @@
     stderr_redirect = io.StringIO()
     with contextlib.redirect_stderr(stderr_redirect):
       props = PropList("hello")
-      props.put("ro.board.first_api_level","25")
+      props.put("ro.board.first_api_level","202504")
       props.put("ro.build.version.codename", "REL")
 
-      # ro.board.first_api_level must be less than or equal to the sdk version
-      self.assertFalse(validate_grf_props(props, 20))
-      self.assertTrue(validate_grf_props(props, 26))
-      self.assertTrue(validate_grf_props(props, 35))
-
       # manually set ro.board.api_level to an invalid value
-      props.put("ro.board.api_level","20")
-      self.assertFalse(validate_grf_props(props, 26))
+      props.put("ro.board.api_level","202404")
+      self.assertFalse(validate_grf_props(props))
 
       props.get_all_props()[-1].make_as_comment()
       # manually set ro.board.api_level to a valid value
-      props.put("ro.board.api_level","26")
-      self.assertTrue(validate_grf_props(props, 26))
-      # ro.board.api_level must be less than or equal to the sdk version
-      self.assertFalse(validate_grf_props(props, 25))
-
-      # allow setting future api_level before release
-      props.get_all_props()[-2].make_as_comment()
-      props.put("ro.build.version.codename", "NonRel")
-      self.assertTrue(validate_grf_props(props, 24))
+      props.put("ro.board.api_level","202504")
+      self.assertTrue(validate_grf_props(props))
 
 if __name__ == '__main__':
     unittest.main(verbosity=2)