Merge "Support release configs: disallow_lunch_use=true" into main
diff --git a/ci/build_device_and_tests b/ci/build_device_and_tests
index 9d11268..63d3ce3 100755
--- a/ci/build_device_and_tests
+++ b/ci/build_device_and_tests
@@ -13,6 +13,7 @@
 # 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.
+set -euo pipefail
 
-build/soong/soong_ui.bash --make-mode build_test_suites || exit $?
-$(build/soong/soong_ui.bash --dumpvar-mode HOST_OUT)/bin/build_test_suites $@ || exit $?
+build/soong/soong_ui.bash --make-mode build_test_suites
+$(build/soong/soong_ui.bash --dumpvar-mode HOST_OUT)/bin/build_test_suites --device-build $@
diff --git a/ci/build_metadata b/ci/build_metadata
index cd011c8..3e9218f 100755
--- a/ci/build_metadata
+++ b/ci/build_metadata
@@ -14,15 +14,31 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-set -ex
+set -x
+
+source build/make/shell_utils.sh
 
 export TARGET_PRODUCT=aosp_arm64
 export TARGET_RELEASE=trunk_staging
 export TARGET_BUILD_VARIANT=eng
 
+import_build_vars \
+        OUT_DIR \
+        DIST_DIR \
+        HOST_OUT_EXECUTABLES \
+    || exit $?
+
 TARGETS=(
     all_teams
+    source_tree_size
     release_config_metadata
 )
 
-build/soong/bin/m dist ${TARGETS[@]}
+# Build modules
+build/soong/bin/m dist ${TARGETS[@]} || exit $?
+
+# List all source files in the tree
+( \
+    $HOST_OUT_EXECUTABLES/source_tree_size -o $DIST_DIR/all_source_tree_files.pb \
+        && gzip -fn $DIST_DIR/all_source_tree_files.pb \
+) || exit $?
diff --git a/ci/build_test_suites b/ci/build_test_suites
index 9d11268..74470a8 100755
--- a/ci/build_test_suites
+++ b/ci/build_test_suites
@@ -13,6 +13,7 @@
 # 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.
+set -euo pipefail
 
-build/soong/soong_ui.bash --make-mode build_test_suites || exit $?
-$(build/soong/soong_ui.bash --dumpvar-mode HOST_OUT)/bin/build_test_suites $@ || exit $?
+build/soong/soong_ui.bash --make-mode build_test_suites
+$(build/soong/soong_ui.bash --dumpvar-mode HOST_OUT)/bin/build_test_suites $@
diff --git a/ci/build_test_suites.py b/ci/build_test_suites.py
index 623d256..443e872 100644
--- a/ci/build_test_suites.py
+++ b/ci/build_test_suites.py
@@ -30,9 +30,12 @@
 import test_discovery_agent
 
 
-REQUIRED_ENV_VARS = frozenset(['TARGET_PRODUCT', 'TARGET_RELEASE', 'TOP'])
+REQUIRED_ENV_VARS = frozenset(['TARGET_PRODUCT', 'TARGET_RELEASE', 'TOP', 'DIST_DIR'])
 SOONG_UI_EXE_REL_PATH = 'build/soong/soong_ui.bash'
 LOG_PATH = 'logs/build_test_suites.log'
+# Currently, this prevents the removal of those tags when they exist. In the future we likely
+# want the script to supply 'dist directly
+REQUIRED_BUILD_TARGETS = frozenset(['dist', 'droid'])
 
 
 class Error(Exception):
@@ -71,36 +74,55 @@
     if 'optimized_build' not in self.build_context.enabled_build_features:
       return BuildPlan(set(self.args.extra_targets), set())
 
+    if not self.build_context.test_infos:
+      logging.warning('Build context has no test infos, skipping optimizations.')
+      for target in self.args.extra_targets:
+        get_metrics_agent().report_unoptimized_target(target, 'BUILD_CONTEXT has no test infos.')
+      return BuildPlan(set(self.args.extra_targets), set())
+
     build_targets = set()
     packaging_commands_getters = []
-    test_discovery_zip_regexes = set()
-    optimization_rationale = ''
-    try:
-      # Do not use these regexes for now, only run this to collect data on what
-      # would be optimized.
-      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)
-      else:
+    # In order to roll optimizations out differently between test suites and
+    # device builds, we have separate flags.
+    if (
+        '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
         try:
-          regex = r'\b(%s)\b' % re.escape(target)
+          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.')
-          else:
-            get_metrics_agent().report_optimized_target(target)
+            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)}')
 
-      if self._unused_target_exclusion_enabled(
-          target
-      ) and not self.build_context.build_target_used(target):
-        continue
-
+    for target in preliminary_build_targets:
       target_optimizer_getter = self.target_optimizations.get(target, None)
       if not target_optimizer_getter:
         build_targets.add(target)
@@ -116,6 +138,51 @@
 
     return BuildPlan(build_targets, packaging_commands_getters)
 
+  def _collect_preliminary_build_targets(self):
+    build_targets = 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:
+        get_metrics_agent().report_unoptimized_target(target, optimization_rationale)
+      return self._legacy_collect_preliminary_build_targets()
+
+    for target in self.args.extra_targets:
+      if target in REQUIRED_BUILD_TARGETS:
+        build_targets.add(target)
+        continue
+
+      regex = r'\b(%s.*)\b' % re.escape(target)
+      for opt in test_discovery_zip_regexes:
+        try:
+          if re.search(regex, opt):
+            get_metrics_agent().report_unoptimized_target(target, 'Test artifact used.')
+            build_targets.add(target)
+            continue
+          get_metrics_agent().report_optimized_target(target)
+        except Exception as e:
+          # In case of exception report as unoptimized
+          build_targets.add(target)
+          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)}')
+
+    return build_targets
+
+  def _legacy_collect_preliminary_build_targets(self):
+    build_targets = set()
+    for target in self.args.extra_targets:
+      if self._unused_target_exclusion_enabled(
+          target
+      ) and not self.build_context.build_target_used(target):
+        continue
+
+      build_targets.add(target)
+    return build_targets
+
   def _unused_target_exclusion_enabled(self, target: str) -> bool:
     return (
         f'{target}_unused_exclusion'
@@ -197,6 +264,11 @@
   argparser.add_argument(
       'extra_targets', nargs='*', help='Extra test suites to build.'
   )
+  argparser.add_argument(
+      '--device-build',
+      action='store_true',
+      help='Flag to indicate running a device build.',
+  )
 
   return argparser.parse_args(argv)
 
diff --git a/ci/build_test_suites_test.py b/ci/build_test_suites_test.py
index 26f4316..190740f 100644
--- a/ci/build_test_suites_test.py
+++ b/ci/build_test_suites_test.py
@@ -78,6 +78,12 @@
     with self.assert_raises_word(build_test_suites.Error, 'TOP'):
       build_test_suites.main([])
 
+  def test_missing_dist_dir_env_var_raises(self):
+    del os.environ['DIST_DIR']
+
+    with self.assert_raises_word(build_test_suites.Error, 'DIST_DIR'):
+      build_test_suites.main([])
+
   def test_invalid_arg_raises(self):
     invalid_args = ['--invalid_arg']
 
@@ -114,6 +120,9 @@
     self.soong_ui_dir = self.fake_top.joinpath('build/soong')
     self.soong_ui_dir.mkdir(parents=True, exist_ok=True)
 
+    self.logs_dir = self.fake_top.joinpath('dist/logs')
+    self.logs_dir.mkdir(parents=True, exist_ok=True)
+
     self.soong_ui = self.soong_ui_dir.joinpath('soong_ui.bash')
     self.soong_ui.touch()
 
@@ -121,6 +130,7 @@
         'TARGET_RELEASE': 'release',
         'TARGET_PRODUCT': 'product',
         'TOP': str(self.fake_top),
+        'DIST_DIR': str(self.fake_top.joinpath('dist')),
     })
 
     self.mock_subprocess_run.return_value = 0
@@ -296,7 +306,8 @@
     build_planner = self.create_build_planner(
         build_targets=build_targets,
         build_context=self.create_build_context(
-            enabled_build_features=[{'name': self.get_target_flag('target_1')}]
+            enabled_build_features=[{'name': self.get_target_flag('target_1')}],
+            test_context=self.get_test_context('target_1'),
         ),
     )
 
@@ -312,7 +323,8 @@
     build_planner = self.create_build_planner(
         build_targets=build_targets,
         build_context=self.create_build_context(
-            enabled_build_features=[{'name': self.get_target_flag('target_1')}]
+            enabled_build_features=[{'name': self.get_target_flag('target_1')}],
+            test_context=self.get_test_context('target_1'),
         ),
         packaging_commands=packaging_commands,
     )
diff --git a/core/BUILD.bazel b/core/BUILD.bazel
deleted file mode 100644
index f4869d4..0000000
--- a/core/BUILD.bazel
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright (C) 2023 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
-
-# Export tradefed templates for tests.
-exports_files(
-    glob(["*.xml"]),
-)
-
-# Export proguard flag files for r8.
-filegroup(
-    name = "global_proguard_flags",
-    srcs = [
-        "proguard.flags",
-        "proguard_basic_keeps.flags",
-    ],
-    visibility = ["//visibility:public"],
-)
diff --git a/core/Makefile b/core/Makefile
index dbb8976..1180073 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -872,6 +872,7 @@
 SOONG_CONV_DATA := $(call intermediates-dir-for,PACKAGING,soong_conversion)/soong_conv_data
 $(SOONG_CONV_DATA):
 	@rm -f $@
+	@touch $@ # This file must be present even if SOONG_CONV is empty.
 	@$(foreach s,$(SOONG_CONV),echo "$(s),$(SOONG_CONV.$(s).TYPE),$(sort $(SOONG_CONV.$(s).PROBLEMS)),$(sort $(filter-out $(SOONG_ALREADY_CONV),$(SOONG_CONV.$(s).DEPS))),$(sort $(SOONG_CONV.$(s).MAKEFILES)),$(sort $(SOONG_CONV.$(s).INSTALLED))" >>$@;)
 
 $(call declare-1p-target,$(SOONG_CONV_DATA),build)
@@ -969,27 +970,12 @@
 
 # -----------------------------------------------------------------
 
-.PHONY: event-log-tags
-
-# Produce an event logs tag file for everything we know about, in order
-# to properly allocate numbers.  Then produce a file that's filtered
-# for what's going to be installed.
-
-all_event_log_tags_file := $(TARGET_OUT_COMMON_INTERMEDIATES)/all-event-log-tags.txt
-
 event_log_tags_file := $(TARGET_OUT)/etc/event-log-tags
 
 # Include tags from all packages that we know about
 all_event_log_tags_src := \
     $(sort $(foreach m, $(ALL_MODULES), $(ALL_MODULES.$(m).EVENT_LOG_TAGS)))
 
-$(all_event_log_tags_file): PRIVATE_SRC_FILES := $(all_event_log_tags_src)
-$(all_event_log_tags_file): $(all_event_log_tags_src) $(MERGETAGS) build/make/tools/event_log_tags.py
-	$(hide) mkdir -p $(dir $@)
-	$(hide) $(MERGETAGS) -o $@ $(PRIVATE_SRC_FILES)
-
-$(call declare-0p-target,$(all_event_log_tags_file))
-
 # Include tags from all packages included in this product, plus all
 # tags that are part of the system (ie, not in a vendor/ or device/
 # directory).
@@ -1001,13 +987,13 @@
       $(filter-out vendor/% device/% out/%,$(all_event_log_tags_src)))
 
 $(event_log_tags_file): PRIVATE_SRC_FILES := $(event_log_tags_src)
-$(event_log_tags_file): PRIVATE_MERGED_FILE := $(all_event_log_tags_file)
-$(event_log_tags_file): $(event_log_tags_src) $(all_event_log_tags_file) $(MERGETAGS) build/make/tools/event_log_tags.py
+$(event_log_tags_file): $(event_log_tags_src) $(MERGETAGS)
 	$(hide) mkdir -p $(dir $@)
-	$(hide) $(MERGETAGS) -o $@ -m $(PRIVATE_MERGED_FILE) $(PRIVATE_SRC_FILES)
+	$(hide) $(MERGETAGS) -o $@ $(PRIVATE_SRC_FILES)
 
 $(eval $(call declare-0p-target,$(event_log_tags_file)))
 
+.PHONY: event-log-tags
 event-log-tags: $(event_log_tags_file)
 
 ALL_DEFAULT_INSTALLED_MODULES += $(event_log_tags_file)
@@ -2663,7 +2649,7 @@
 TARGET_PRIVATE_RES_DIRS := $(wildcard $(TARGET_DEVICE_DIR)/recovery/res)
 endif
 recovery_resource_deps := $(shell find $(recovery_resources_common) \
-  $(TARGET_PRIVATE_RES_DIRS) -type f)
+  $(TARGET_PRIVATE_RES_DIRS) -type f -not -name "*.bp")
 recovery_resource_deps += $(generated_recovery_text_files)
 
 
@@ -6677,7 +6663,7 @@
 	@# Contents of the system image
 ifneq ($(SOONG_DEFINED_SYSTEM_IMAGE_PATH),)
 	$(hide) $(call package_files-copy-root, \
-	    $(SOONG_DEFINED_SYSTEM_IMAGE_BASE)/root/system,$(zip_root)/SYSTEM)
+	    $(SOONG_DEFINED_SYSTEM_IMAGE_BASE)/system/system,$(zip_root)/SYSTEM)
 else
 	$(hide) $(call package_files-copy-root, \
 	    $(SYSTEMIMAGE_SOURCE_DIR),$(zip_root)/SYSTEM)
diff --git a/core/android_soong_config_vars.mk b/core/android_soong_config_vars.mk
index 092ddb0..6040ad3 100644
--- a/core/android_soong_config_vars.mk
+++ b/core/android_soong_config_vars.mk
@@ -202,6 +202,9 @@
 $(call soong_config_set,ANDROID,release_package_profiling_module,$(RELEASE_PACKAGE_PROFILING_MODULE))
 $(call soong_config_set,bootclasspath,release_package_profiling_module,$(RELEASE_PACKAGE_PROFILING_MODULE))
 
+# Move VCN from platform to the Tethering module; used by both platform and module
+$(call soong_config_set,ANDROID,is_vcn_in_mainline,$(RELEASE_MOVE_VCN_TO_MAINLINE))
+
 # Add perf-setup build flag to soong
 # Note: BOARD_PERFSETUP_SCRIPT location must be under platform_testing/scripts/perf-setup/.
 ifdef BOARD_PERFSETUP_SCRIPT
@@ -272,3 +275,13 @@
 $(call soong_config_set_bool,telephony,sec_cp_secure_boot,$(if $(filter true,$(SEC_CP_SECURE_BOOT)),true,false))
 $(call soong_config_set_bool,telephony,cbd_protocol_sit,$(if $(filter true,$(CBD_PROTOCOL_SIT)),true,false))
 $(call soong_config_set_bool,telephony,use_radioexternal_hal_aidl,$(if $(filter true,$(USE_RADIOEXTERNAL_HAL_AIDL)),true,false))
+
+# Variables for hwcomposer.$(TARGET_BOARD_PLATFORM)
+$(call soong_config_set_bool,google_graphics,board_uses_hwc_services,$(if $(filter true,$(BOARD_USES_HWC_SERVICES)),true,false))
+
+# Variables for controlling android.hardware.composer.hwc3-service.pixel
+$(call soong_config_set,google_graphics,board_hwc_version,$(BOARD_HWC_VERSION))
+
+# Variables for extra branches
+# TODO(b/383238397): Use bootstrap_go_package to enable extra flags.
+-include vendor/google/build/extra_soong_config_vars.mk
diff --git a/core/board_config.mk b/core/board_config.mk
index ea0d022..ad89c03 100644
--- a/core/board_config.mk
+++ b/core/board_config.mk
@@ -291,6 +291,7 @@
 include $(BUILD_SYSTEM)/board_config_wifi.mk
 
 # Set up soong config for "soong_config_value_variable".
+-include hardware/interfaces/configstore/1.1/default/surfaceflinger.mk
 -include vendor/google/build/soong/soong_config_namespace/camera.mk
 
 # Default *_CPU_VARIANT_RUNTIME to CPU_VARIANT if unspecified.
diff --git a/core/config.mk b/core/config.mk
index d62b86d..20ebeeb 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -730,8 +730,8 @@
 PROGUARD_HOME := external/proguard
 PROGUARD := $(PROGUARD_HOME)/bin/proguard.sh
 PROGUARD_DEPS := $(PROGUARD) $(PROGUARD_HOME)/lib/proguard.jar
-JAVATAGS := build/make/tools/java-event-log-tags.py
-MERGETAGS := build/make/tools/merge-event-log-tags.py
+JAVATAGS := $(HOST_OUT_EXECUTABLES)/java-event-log-tags
+MERGETAGS := $(HOST_OUT_EXECUTABLES)/merge-event-log-tags
 APPEND2SIMG := $(HOST_OUT_EXECUTABLES)/append2simg
 VERITY_SIGNER := $(HOST_OUT_EXECUTABLES)/verity_signer
 BUILD_VERITY_METADATA := $(HOST_OUT_EXECUTABLES)/build_verity_metadata
diff --git a/core/definitions.mk b/core/definitions.mk
index adb35e0..1ab6388 100644
--- a/core/definitions.mk
+++ b/core/definitions.mk
@@ -1555,7 +1555,7 @@
 define transform-logtags-to-java
 @mkdir -p $(dir $@)
 @echo "logtags: $@ <= $<"
-$(hide) $(JAVATAGS) -o $@ $< $(PRIVATE_MERGED_TAG)
+$(hide) $(JAVATAGS) -o $@ $<
 endef
 
 
diff --git a/core/java.mk b/core/java.mk
index 5fbc916..41a1b1b 100644
--- a/core/java.mk
+++ b/core/java.mk
@@ -140,8 +140,7 @@
 logtags_java_sources := $(patsubst %.logtags,%.java,$(addprefix $(intermediates.COMMON)/logtags/, $(logtags_sources)))
 logtags_sources := $(addprefix $(LOCAL_PATH)/, $(logtags_sources))
 
-$(logtags_java_sources): PRIVATE_MERGED_TAG := $(TARGET_OUT_COMMON_INTERMEDIATES)/all-event-log-tags.txt
-$(logtags_java_sources): $(intermediates.COMMON)/logtags/%.java: $(LOCAL_PATH)/%.logtags $(TARGET_OUT_COMMON_INTERMEDIATES)/all-event-log-tags.txt $(JAVATAGS) build/make/tools/event_log_tags.py
+$(logtags_java_sources): $(intermediates.COMMON)/logtags/%.java: $(LOCAL_PATH)/%.logtags $(JAVATAGS)
 	$(transform-logtags-to-java)
 
 else
diff --git a/core/main.mk b/core/main.mk
index 624df49..4b76971 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -277,10 +277,7 @@
 # Include all of the makefiles in the system
 #
 
-subdir_makefiles := \
-    $(SOONG_OUT_DIR)/installs-$(TARGET_PRODUCT)$(COVERAGE_SUFFIX).mk \
-    $(SOONG_ANDROID_MK) \
-    build/make/target/board/android-info.mk
+subdir_makefiles := $(SOONG_OUT_DIR)/installs-$(TARGET_PRODUCT)$(COVERAGE_SUFFIX).mk $(SOONG_ANDROID_MK)
 
 # Android.mk files are only used on Linux builds, Mac only supports Android.bp
 ifeq ($(HOST_OS),linux)
diff --git a/core/product_config.mk b/core/product_config.mk
index 68614ae..f93b63c 100644
--- a/core/product_config.mk
+++ b/core/product_config.mk
@@ -468,10 +468,17 @@
     $(eval SANITIZER.$(TARGET_PRODUCT).$(m).CONFIG := $(cf))))
 _psmc_modules :=
 
-# Reset ADB keys for non-debuggable builds
-ifeq (,$(filter eng userdebug,$(TARGET_BUILD_VARIANT)))
+# Reset ADB keys. If RELEASE_BUILD_USE_VARIANT_FLAGS is set look for
+# the value of a dedicated flag. Otherwise check if build variant is
+# non-debuggable.
+ifneq (,$(RELEASE_BUILD_USE_VARIANT_FLAGS))
+ifneq (,$(RELEASE_BUILD_PURGE_PRODUCT_ADB_KEYS))
   PRODUCT_ADB_KEYS :=
 endif
+else ifeq (,$(filter eng userdebug,$(TARGET_BUILD_VARIANT)))
+  PRODUCT_ADB_KEYS :=
+endif
+
 ifneq ($(filter-out 0 1,$(words $(PRODUCT_ADB_KEYS))),)
   $(error Only one file may be in PRODUCT_ADB_KEYS: $(PRODUCT_ADB_KEYS))
 endif
diff --git a/core/soong_config.mk b/core/soong_config.mk
index a007888..4485072 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -525,6 +525,22 @@
   # Used to generate recovery partition
   $(call add_json_str, TargetScreenDensity, $(TARGET_SCREEN_DENSITY))
 
+  # Used to generate /recovery/root/build.prop
+  $(call add_json_map, PrivateRecoveryUiProperties)
+    $(call add_json_str, animation_fps, $(TARGET_RECOVERY_UI_ANIMATION_FPS))
+    $(call add_json_str, margin_height, $(TARGET_RECOVERY_UI_MARGIN_HEIGHT))
+    $(call add_json_str, margin_width, $(TARGET_RECOVERY_UI_MARGIN_WIDTH))
+    $(call add_json_str, menu_unusable_rows, $(TARGET_RECOVERY_UI_MENU_UNUSABLE_ROWS))
+    $(call add_json_str, progress_bar_baseline, $(TARGET_RECOVERY_UI_PROGRESS_BAR_BASELINE))
+    $(call add_json_str, touch_low_threshold, $(TARGET_RECOVERY_UI_TOUCH_LOW_THRESHOLD))
+    $(call add_json_str, touch_high_threshold, $(TARGET_RECOVERY_UI_TOUCH_HIGH_THRESHOLD))
+    $(call add_json_str, vr_stereo_offset, $(TARGET_RECOVERY_UI_VR_STEREO_OFFSET))
+    $(call add_json_str, brightness_file, $(TARGET_RECOVERY_UI_BRIGHTNESS_FILE))
+    $(call add_json_str, max_brightness_file, $(TARGET_RECOVERY_UI_MAX_BRIGHTNESS_FILE))
+    $(call add_json_str, brightness_normal_percent, $(TARGET_RECOVERY_UI_BRIGHTNESS_NORMAL))
+    $(call add_json_str, brightness_dimmed_percent, $(TARGET_RECOVERY_UI_BRIGHTNESS_DIMMED))
+  $(call end_json_map)
+
 $(call end_json_map)
 
 # For converting vintf_data
diff --git a/core/soong_extra_config.mk b/core/soong_extra_config.mk
index 2ff83a1..8eee50a 100644
--- a/core/soong_extra_config.mk
+++ b/core/soong_extra_config.mk
@@ -80,7 +80,7 @@
 
 $(call add_json_str, ScreenDensity, $(TARGET_SCREEN_DENSITY))
 
-$(call add_json_bool, UsesVulkan, $(filter true,$(TARGET_USES_VULKAN)))
+$(call add_json_str, UsesVulkan, $(TARGET_USES_VULKAN))
 
 $(call add_json_bool, ZygoteForce64, $(filter true,$(ZYGOTE_FORCE_64)))
 
diff --git a/shell_utils.sh b/shell_utils.sh
index 9053c42..3124db5 100644
--- a/shell_utils.sh
+++ b/shell_utils.sh
@@ -214,3 +214,19 @@
     ' SIGINT SIGTERM SIGQUIT EXIT
 }
 
+# Import the build variables supplied as arguments into this shell's environment.
+# For absolute variables, prefix the variable name with a '/'. For example:
+#    import_build_vars OUT_DIR DIST_DIR /HOST_OUT_EXECUTABLES
+# Returns nonzero if the build command failed. Stderr is passed through.
+function import_build_vars()
+{
+    require_top
+    local script
+    script=$(cd $TOP && build/soong/bin/get_build_vars "$@")
+    local ret=$?
+    if [ $ret -ne 0 ] ; then
+        return $ret
+    fi
+    eval "$script"
+    return $?
+}
diff --git a/target/board/android-info.mk b/target/board/Android.mk
similarity index 100%
rename from target/board/android-info.mk
rename to target/board/Android.mk
diff --git a/target/product/base_system.mk b/target/product/base_system.mk
index b9b226b..2907e07 100644
--- a/target/product/base_system.mk
+++ b/target/product/base_system.mk
@@ -96,7 +96,6 @@
     enhanced-confirmation.xml \
     ExtShared \
     flags_health_check \
-    framework-connectivity-b \
     framework-graphics \
     framework-location \
     framework-minus-apex \
@@ -348,6 +347,13 @@
         com.android.webview.bootstrap
 endif
 
+# Only add the jar when it is not in the Tethering module. Otherwise,
+# it will be added via com.android.tethering
+ifneq ($(RELEASE_MOVE_VCN_TO_MAINLINE),true)
+    PRODUCT_PACKAGES += \
+        framework-connectivity-b
+endif
+
 ifneq (,$(RELEASE_RANGING_STACK))
     PRODUCT_PACKAGES += \
         com.android.ranging
diff --git a/target/product/default_art_config.mk b/target/product/default_art_config.mk
index 83d9215..d857e04 100644
--- a/target/product/default_art_config.mk
+++ b/target/product/default_art_config.mk
@@ -51,7 +51,6 @@
     framework-minus-apex \
     framework-graphics \
     framework-location \
-    framework-connectivity-b \
     ext \
     telephony-common \
     voip-common \
@@ -121,6 +120,17 @@
     $(call soong_config_set,bootclasspath,release_ranging_stack,true)
 endif
 
+# Check if VCN should be built into the tethering module or not
+ifeq ($(RELEASE_MOVE_VCN_TO_MAINLINE),true)
+    PRODUCT_APEX_BOOT_JARS += \
+        com.android.tethering:framework-connectivity-b \
+
+else
+    PRODUCT_BOOT_JARS += \
+        framework-connectivity-b \
+
+endif
+
 # 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.
diff --git a/target/product/generic/Android.bp b/target/product/generic/Android.bp
index 4a3d21b..66bf694 100644
--- a/target/product/generic/Android.bp
+++ b/target/product/generic/Android.bp
@@ -705,7 +705,6 @@
                 "framework-graphics", // base_system
                 "framework-location", // base_system
                 "framework-minus-apex-install-dependencies", // base_system
-                "framework-connectivity-b", // base_system
                 "framework_compatibility_matrix.device.xml",
                 "generic_system_fonts", // ok
                 "hwservicemanager_compat_symlink_module", // base_system
@@ -734,6 +733,11 @@
                     "com.android.profiling", // base_system (RELEASE_PACKAGE_PROFILING_MODULE)
                 ],
                 default: [],
+            }) + select(release_flag("RELEASE_MOVE_VCN_TO_MAINLINE"), {
+                true: [],
+                default: [
+                    "framework-connectivity-b", // base_system
+                ],
             }) + select(release_flag("RELEASE_AVATAR_PICKER_APP"), {
                 true: [
                     "AvatarPicker", // generic_system (RELEASE_AVATAR_PICKER_APP)
diff --git a/target/product/gsi/current.txt b/target/product/gsi/current.txt
index f771916..cbb8a0e 100644
--- a/target/product/gsi/current.txt
+++ b/target/product/gsi/current.txt
@@ -24,7 +24,7 @@
 VNDK-SP: android.hardware.common-V2-ndk.so
 VNDK-SP: android.hardware.common.fmq-V1-ndk.so
 VNDK-SP: android.hardware.graphics.allocator-V2-ndk.so
-VNDK-SP: android.hardware.graphics.common-V5-ndk.so
+VNDK-SP: android.hardware.graphics.common-V6-ndk.so
 VNDK-SP: android.hardware.graphics.common@1.0.so
 VNDK-SP: android.hardware.graphics.common@1.1.so
 VNDK-SP: android.hardware.graphics.common@1.2.so
diff --git a/target/product/security/Android.bp b/target/product/security/Android.bp
index ffbec06..214c009 100644
--- a/target/product/security/Android.bp
+++ b/target/product/security/Android.bp
@@ -33,7 +33,13 @@
 // image
 otacerts_zip {
     name: "otacerts",
-    recovery_available: true,
+    relative_install_path: "security",
+    filename: "otacerts.zip",
+}
+
+otacerts_zip {
+    name: "otacerts.recovery",
+    recovery: true,
     relative_install_path: "security",
     filename: "otacerts.zip",
 }
diff --git a/target/product/security/BUILD.bazel b/target/product/security/BUILD.bazel
deleted file mode 100644
index c12be79..0000000
--- a/target/product/security/BUILD.bazel
+++ /dev/null
@@ -1,8 +0,0 @@
-filegroup(
-    name = "android_certificate_directory",
-    srcs = glob([
-        "*.pk8",
-        "*.pem",
-    ]),
-    visibility = ["//visibility:public"],
-)
diff --git a/teams/Android.bp b/teams/Android.bp
index 6307f5c..a2b0d14 100644
--- a/teams/Android.bp
+++ b/teams/Android.bp
@@ -3367,6 +3367,13 @@
 }
 
 team {
+    name: "trendy_team_aaos_display_safety_triage",
+
+    // go/trendy/manage/engineers/6522093663780864
+    trendy_team_id: "6522093663780864",
+}
+
+team {
     name: "trendy_team_camera_htc_lg_qualcomm",
 
     // go/trendy/manage/engineers/6332099480911872
diff --git a/tools/Android.bp b/tools/Android.bp
index 59831a6..243cb56 100644
--- a/tools/Android.bp
+++ b/tools/Android.bp
@@ -123,3 +123,11 @@
         "merge-event-log-tags.py",
     ],
 }
+
+python_binary_host {
+    name: "java-event-log-tags",
+    srcs: [
+        "event_log_tags.py",
+        "java-event-log-tags.py",
+    ],
+}
diff --git a/tools/BUILD.bazel b/tools/BUILD.bazel
deleted file mode 100644
index 9ec0dce..0000000
--- a/tools/BUILD.bazel
+++ /dev/null
@@ -1,35 +0,0 @@
-py_library(
-    name = "event_log_tags",
-    srcs = ["event_log_tags.py"],
-    imports = ["."],
-)
-
-py_binary(
-    name = "java-event-log-tags",
-    srcs = ["java-event-log-tags.py"],
-    python_version = "PY3",
-    visibility = ["//visibility:public"],
-    deps = [":event_log_tags"],
-)
-
-py_binary(
-    name = "merge-event-log-tags",
-    srcs = ["merge-event-log-tags.py"],
-    python_version = "PY3",
-    visibility = ["//visibility:public"],
-    deps = [":event_log_tags"],
-)
-
-py_binary(
-    name = "check_elf_file",
-    srcs = ["check_elf_file.py"],
-    python_version = "PY3",
-    visibility = ["//visibility:public"],
-)
-
-py_binary(
-    name = "auto_gen_test_config",
-    srcs = ["auto_gen_test_config.py"],
-    python_version = "PY3",
-    visibility = ["//visibility:public"],
-)
diff --git a/tools/aconfig/TEST_MAPPING b/tools/aconfig/TEST_MAPPING
index 043a956..a7f0a4f 100644
--- a/tools/aconfig/TEST_MAPPING
+++ b/tools/aconfig/TEST_MAPPING
@@ -102,9 +102,7 @@
     {
       // aconfig_storage file java integration tests
       "name": "aconfig_storage_file.test.java"
-    }
-  ],
-  "postsubmit": [
+    },
     {
       // aconfig_storage read functional test
       "name": "aconfig_storage_read_functional"
diff --git a/tools/aconfig/aconfig/src/codegen/java.rs b/tools/aconfig/aconfig/src/codegen/java.rs
index 81cbcf4..0d528d2 100644
--- a/tools/aconfig/aconfig/src/codegen/java.rs
+++ b/tools/aconfig/aconfig/src/codegen/java.rs
@@ -33,6 +33,7 @@
     flag_ids: HashMap<String, u16>,
     allow_instrumentation: bool,
     package_fingerprint: u64,
+    new_exported: bool,
 ) -> Result<Vec<OutputFile>>
 where
     I: Iterator<Item = ProtoParsedFlag>,
@@ -60,6 +61,7 @@
         container,
         is_platform_container,
         package_fingerprint: format!("0x{:X}L", package_fingerprint),
+        new_exported,
     };
     let mut template = TinyTemplate::new();
     template.add_template("Flags.java", include_str!("../../templates/Flags.java.template"))?;
@@ -129,6 +131,7 @@
     pub container: String,
     pub is_platform_container: bool,
     pub package_fingerprint: String,
+    pub new_exported: bool,
 }
 
 #[derive(Serialize, Debug)]
@@ -530,6 +533,7 @@
             flag_ids,
             true,
             5801144784618221668,
+            false,
         )
         .unwrap();
         let expect_flags_content = EXPECTED_FLAG_COMMON_CONTENT.to_string()
@@ -543,7 +547,6 @@
         import android.compat.annotation.UnsupportedAppUsage;
         import android.os.Build;
         import android.os.flagging.PlatformAconfigPackageInternal;
-        import android.os.flagging.AconfigStorageReadException;
         import android.util.Log;
         /** @hide */
         public final class FeatureFlagsImpl implements FeatureFlags {
@@ -556,38 +559,16 @@
             private void init() {
                 try {
                     PlatformAconfigPackageInternal reader = PlatformAconfigPackageInternal.load("system", "com.android.aconfig.test", 0x5081CE7221C77064L);
-                    AconfigStorageReadException error = reader.getException();
-                    if (error == null) {
-                        disabledRw = reader.getBooleanFlagValue(0);
-                        disabledRwExported = reader.getBooleanFlagValue(1);
-                        enabledRw = reader.getBooleanFlagValue(7);
-                        disabledRwInOtherNamespace = reader.getBooleanFlagValue(2);
-                    } else if (Build.VERSION.SDK_INT > 35 && error.getErrorCode() == 5 /* fingerprint doesn't match*/) {
-                        disabledRw = reader.getBooleanFlagValue("disabled_rw", false);
-                        disabledRwExported = reader.getBooleanFlagValue("disabled_rw_exported", false);
-                        enabledRw = reader.getBooleanFlagValue("enabled_rw", true);
-                        disabledRwInOtherNamespace = reader.getBooleanFlagValue("disabled_rw_in_other_namespace", false);
-                    } else {
-                        if (error.getMessage() != null) {
-                            Log.e(TAG, error.getMessage());
-                        } else {
-                            Log.e(TAG, "Encountered a null AconfigStorageReadException");
-                        }
-                    }
+                    disabledRw = reader.getBooleanFlagValue(0);
+                    disabledRwExported = reader.getBooleanFlagValue(1);
+                    enabledRw = reader.getBooleanFlagValue(7);
+                    disabledRwInOtherNamespace = reader.getBooleanFlagValue(2);
                 } catch (Exception e) {
-                    if (e.getMessage() != null) {
-                        Log.e(TAG, e.getMessage());
-                    } else {
-                        Log.e(TAG, "Encountered a null Exception");
-                    }
+                    Log.e(TAG, e.toString());
                 } catch (NoClassDefFoundError e) {
                     // for mainline module running on older devices.
                     // This should be replaces to version check, after the version bump.
-                    if (e.getMessage() != null) {
-                        Log.e(TAG, e.getMessage());
-                    } else {
-                        Log.e(TAG, "Encountered a null NoClassDefFoundError");
-                    }
+                    Log.e(TAG, e.toString());
                 }
                 isCached = true;
             }
@@ -708,6 +689,7 @@
             flag_ids,
             true,
             5801144784618221668,
+            false,
         )
         .unwrap();
 
@@ -893,6 +875,195 @@
     }
 
     #[test]
+    fn test_generate_java_code_new_exported() {
+        let parsed_flags = crate::test::parse_test_flags();
+        let mode = CodegenMode::Exported;
+        let modified_parsed_flags =
+            crate::commands::modify_parsed_flags_based_on_mode(parsed_flags, mode).unwrap();
+        let flag_ids =
+            assign_flag_ids(crate::test::TEST_PACKAGE, modified_parsed_flags.iter()).unwrap();
+        let generated_files = generate_java_code(
+            crate::test::TEST_PACKAGE,
+            modified_parsed_flags.into_iter(),
+            mode,
+            flag_ids,
+            true,
+            5801144784618221668,
+            true,
+        )
+        .unwrap();
+
+        let expect_flags_content = r#"
+        package com.android.aconfig.test;
+        /** @hide */
+        public final class Flags {
+            /** @hide */
+            public static final String FLAG_DISABLED_RW_EXPORTED = "com.android.aconfig.test.disabled_rw_exported";
+            /** @hide */
+            public static final String FLAG_ENABLED_FIXED_RO_EXPORTED = "com.android.aconfig.test.enabled_fixed_ro_exported";
+            /** @hide */
+            public static final String FLAG_ENABLED_RO_EXPORTED = "com.android.aconfig.test.enabled_ro_exported";
+            public static boolean disabledRwExported() {
+                return FEATURE_FLAGS.disabledRwExported();
+            }
+            public static boolean enabledFixedRoExported() {
+                return FEATURE_FLAGS.enabledFixedRoExported();
+            }
+            public static boolean enabledRoExported() {
+                return FEATURE_FLAGS.enabledRoExported();
+            }
+            private static FeatureFlags FEATURE_FLAGS = new FeatureFlagsImpl();
+        }
+        "#;
+
+        let expect_feature_flags_content = r#"
+        package com.android.aconfig.test;
+        /** @hide */
+        public interface FeatureFlags {
+            boolean disabledRwExported();
+            boolean enabledFixedRoExported();
+            boolean enabledRoExported();
+        }
+        "#;
+
+        let expect_feature_flags_impl_content = r#"
+        package com.android.aconfig.test;
+        import android.os.flagging.AconfigPackage;
+        import android.util.Log;
+        /** @hide */
+        public final class FeatureFlagsImpl implements FeatureFlags {
+            private static final String TAG = "com.android.aconfig.test.FeatureFlagsImpl_exported";
+            private static volatile boolean isCached = false;
+            private static boolean disabledRwExported = false;
+            private static boolean enabledFixedRoExported = false;
+            private static boolean enabledRoExported = false;
+            private void init() {
+                try {
+                    AconfigPackage reader = AconfigPackage.load("com.android.aconfig.test");
+                    disabledRwExported = reader.getBooleanFlagValue("disabled_rw_exported", false);
+                    enabledFixedRoExported = reader.getBooleanFlagValue("enabled_fixed_ro_exported", false);
+                    enabledRoExported = reader.getBooleanFlagValue("enabled_ro_exported", false);
+                } catch (Exception e) {
+                    // pass
+                    Log.e(TAG, e.toString());
+                } catch (NoClassDefFoundError e) {
+                    // for mainline module running on older devices.
+                    // This should be replaces to version check, after the version bump.
+                    Log.e(TAG, e.toString());
+                }
+                isCached = true;
+            }
+            @Override
+            public boolean disabledRwExported() {
+                if (!isCached) {
+                    init();
+                }
+                return disabledRwExported;
+            }
+            @Override
+            public boolean enabledFixedRoExported() {
+                if (!isCached) {
+                    init();
+                }
+                return enabledFixedRoExported;
+            }
+            @Override
+            public boolean enabledRoExported() {
+                if (!isCached) {
+                    init();
+                }
+                return enabledRoExported;
+            }
+        }"#;
+
+        let expect_custom_feature_flags_content = r#"
+        package com.android.aconfig.test;
+
+        import java.util.Arrays;
+        import java.util.HashSet;
+        import java.util.List;
+        import java.util.Set;
+        import java.util.function.BiPredicate;
+        import java.util.function.Predicate;
+
+        /** @hide */
+        public class CustomFeatureFlags implements FeatureFlags {
+
+            private BiPredicate<String, Predicate<FeatureFlags>> mGetValueImpl;
+
+            public CustomFeatureFlags(BiPredicate<String, Predicate<FeatureFlags>> getValueImpl) {
+                mGetValueImpl = getValueImpl;
+            }
+
+            @Override
+            public boolean disabledRwExported() {
+                return getValue(Flags.FLAG_DISABLED_RW_EXPORTED,
+                    FeatureFlags::disabledRwExported);
+            }
+            @Override
+            public boolean enabledFixedRoExported() {
+                return getValue(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED,
+                    FeatureFlags::enabledFixedRoExported);
+            }
+            @Override
+            public boolean enabledRoExported() {
+                return getValue(Flags.FLAG_ENABLED_RO_EXPORTED,
+                    FeatureFlags::enabledRoExported);
+            }
+
+            protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) {
+                return mGetValueImpl.test(flagName, getter);
+            }
+
+            public List<String> getFlagNames() {
+                return Arrays.asList(
+                    Flags.FLAG_DISABLED_RW_EXPORTED,
+                    Flags.FLAG_ENABLED_FIXED_RO_EXPORTED,
+                    Flags.FLAG_ENABLED_RO_EXPORTED
+                );
+            }
+
+            private Set<String> mReadOnlyFlagsSet = new HashSet<>(
+                Arrays.asList(
+                    ""
+                )
+            );
+        }
+    "#;
+
+        let mut file_set = HashMap::from([
+            ("com/android/aconfig/test/Flags.java", expect_flags_content),
+            ("com/android/aconfig/test/FeatureFlags.java", expect_feature_flags_content),
+            ("com/android/aconfig/test/FeatureFlagsImpl.java", expect_feature_flags_impl_content),
+            (
+                "com/android/aconfig/test/CustomFeatureFlags.java",
+                expect_custom_feature_flags_content,
+            ),
+            (
+                "com/android/aconfig/test/FakeFeatureFlagsImpl.java",
+                EXPECTED_FAKEFEATUREFLAGSIMPL_CONTENT,
+            ),
+        ]);
+
+        for file in generated_files {
+            let file_path = file.path.to_str().unwrap();
+            assert!(file_set.contains_key(file_path), "Cannot find {}", file_path);
+            assert_eq!(
+                None,
+                crate::test::first_significant_code_diff(
+                    file_set.get(file_path).unwrap(),
+                    &String::from_utf8(file.contents).unwrap()
+                ),
+                "File {} content is not correct",
+                file_path
+            );
+            file_set.remove(file_path);
+        }
+
+        assert!(file_set.is_empty());
+    }
+
+    #[test]
     fn test_generate_java_code_test() {
         let parsed_flags = crate::test::parse_test_flags();
         let mode = CodegenMode::Test;
@@ -907,6 +1078,7 @@
             flag_ids,
             true,
             5801144784618221668,
+            false,
         )
         .unwrap();
 
@@ -1029,6 +1201,7 @@
             flag_ids,
             true,
             5801144784618221668,
+            false,
         )
         .unwrap();
         let expect_featureflags_content = r#"
diff --git a/tools/aconfig/aconfig/src/commands.rs b/tools/aconfig/aconfig/src/commands.rs
index 3f869de..4c06462 100644
--- a/tools/aconfig/aconfig/src/commands.rs
+++ b/tools/aconfig/aconfig/src/commands.rs
@@ -218,6 +218,7 @@
     mut input: Input,
     codegen_mode: CodegenMode,
     allow_instrumentation: bool,
+    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)?;
@@ -236,6 +237,7 @@
         flag_ids,
         allow_instrumentation,
         package_fingerprint,
+        new_exported,
     )
 }
 
diff --git a/tools/aconfig/aconfig/src/main.rs b/tools/aconfig/aconfig/src/main.rs
index c390288..288786b 100644
--- a/tools/aconfig/aconfig/src/main.rs
+++ b/tools/aconfig/aconfig/src/main.rs
@@ -85,6 +85,12 @@
                         .long("allow-instrumentation")
                         .value_parser(clap::value_parser!(bool))
                         .default_value("false"),
+                )
+                .arg(
+                    Arg::new("new-exported")
+                        .long("new-exported")
+                        .value_parser(clap::value_parser!(bool))
+                        .default_value("false"),
                 ),
         )
         .subcommand(
@@ -267,8 +273,10 @@
             let mode = get_required_arg::<CodegenMode>(sub_matches, "mode")?;
             let allow_instrumentation =
                 get_required_arg::<bool>(sub_matches, "allow-instrumentation")?;
-            let generated_files = commands::create_java_lib(cache, *mode, *allow_instrumentation)
-                .context("failed to create java lib")?;
+            let new_exported = get_required_arg::<bool>(sub_matches, "new-exported")?;
+            let generated_files =
+                commands::create_java_lib(cache, *mode, *allow_instrumentation, *new_exported)
+                    .context("failed to create java lib")?;
             let dir = PathBuf::from(get_required_arg::<String>(sub_matches, "out")?);
             generated_files
                 .iter()
diff --git a/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template b/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
index 3fc444a..8b3d3e1 100644
--- a/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
+++ b/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
@@ -11,7 +11,6 @@
 {{ -else }}
 import android.os.flagging.AconfigPackageInternal;
 {{ -endif }}
-import android.os.flagging.AconfigStorageReadException;
 import android.util.Log;
 {{ -endif }}
 /** @hide */
@@ -32,44 +31,19 @@
 {{ -else }}
             AconfigPackageInternal reader = AconfigPackageInternal.load("{container}", "{package_name}", {package_fingerprint});
 {{ -endif }}
-            AconfigStorageReadException error = reader.getException();
-            if (error == null) \{
-            {{ for namespace_with_flags in namespace_flags }}
-            {{ -for flag in namespace_with_flags.flags }}
-            {{ -if flag.is_read_write }}
-                {flag.method_name} = reader.getBooleanFlagValue({flag.flag_offset});
-            {{ endif }}
-            {{ -endfor }}
-            {{ -endfor }}
-            } else if (Build.VERSION.SDK_INT > 35 && error.getErrorCode() == 5 /* fingerprint doesn't match*/) \{
-            {{ for namespace_with_flags in namespace_flags }}
-            {{ -for flag in namespace_with_flags.flags }}
-            {{ -if flag.is_read_write }}
-                {flag.method_name} = reader.getBooleanFlagValue("{flag.flag_name}", {flag.default_value});
-            {{ -endif }}
-            {{ -endfor }}
-            {{ -endfor }}
-            } else \{
-                if (error.getMessage() != null) \{
-                    Log.e(TAG, error.getMessage());
-                } else \{
-                    Log.e(TAG, "Encountered a null AconfigStorageReadException");
-                }
-            }
+        {{ -for namespace_with_flags in namespace_flags }}
+        {{ -for flag in namespace_with_flags.flags }}
+        {{ -if flag.is_read_write }}
+            {flag.method_name} = reader.getBooleanFlagValue({flag.flag_offset});
+        {{ -endif }}
+        {{ -endfor }}
+        {{ -endfor }}
         } catch (Exception e) \{
-            if (e.getMessage() != null) \{
-                Log.e(TAG, e.getMessage());
-            } else \{
-                Log.e(TAG, "Encountered a null Exception");
-            }
+            Log.e(TAG, e.toString());
         } catch (NoClassDefFoundError e) \{
             // for mainline module running on older devices.
             // This should be replaces to version check, after the version bump.
-            if (e.getMessage() != null) \{
-                Log.e(TAG, e.getMessage());
-            } else \{
-                Log.e(TAG, "Encountered a null NoClassDefFoundError");
-            }
+            Log.e(TAG, e.toString());
         }
         isCached = true;
     }
@@ -91,6 +65,45 @@
 {{ endfor }}
 }
 {{ -else- }}{#- device config for exproted mode #}
+{{ -if new_exported }}
+import android.os.flagging.AconfigPackage;
+import android.util.Log;
+/** @hide */
+public final class FeatureFlagsImpl implements FeatureFlags \{
+    private static final String TAG = "{package_name}.FeatureFlagsImpl_exported";
+    private static volatile boolean isCached = false;
+{{ for flag in flag_elements }}
+    private static boolean {flag.method_name} = {flag.default_value};
+{{ -endfor }}
+    private void init() \{
+        try \{
+            AconfigPackage reader = AconfigPackage.load("{package_name}");
+            {{ -for namespace_with_flags in namespace_flags }}
+            {{ -for flag in namespace_with_flags.flags }}
+            {flag.method_name} = reader.getBooleanFlagValue("{flag.flag_name}", {flag.default_value});
+            {{ -endfor }}
+            {{ -endfor }}
+        } catch (Exception e) \{
+            // pass
+            Log.e(TAG, e.toString());
+        } catch (NoClassDefFoundError e) \{
+            // for mainline module running on older devices.
+            // This should be replaces to version check, after the version bump.
+            Log.e(TAG, e.toString());
+        }
+        isCached = true;
+    }
+{{ -for flag in flag_elements }}
+    @Override
+    public boolean {flag.method_name}() \{
+        if (!isCached) \{
+            init();
+        }
+        return {flag.method_name};
+    }
+{{ endfor }}
+}
+{{ else }}
 import android.os.Binder;
 import android.provider.DeviceConfig;
 import android.provider.DeviceConfig.Properties;
@@ -142,6 +155,7 @@
     }
 {{ endfor }}
 }
+{{ -endif- }} {#- end new_exported mode #}
 {{ -endif- }} {#- end exported mode #}
 {{ else }} {#- else for allow_instrumentation is not enabled #}
 {{ if not library_exported- }}
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 9571568..1fbcb85 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
@@ -63,4 +63,8 @@
     public void position(int newPosition) {
         mByteBuffer.position(newPosition);
     }
+
+    public int position() {
+        return mByteBuffer.position();
+    }
 }
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 a45d12a..1e7c2ca 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
@@ -19,10 +19,16 @@
 import static java.nio.charset.StandardCharsets.UTF_8;
 
 import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Objects;
 
 public class PackageTable {
 
+    private static final int FINGERPRINT_BYTES = 8;
+    // int: mPackageId + int: mBooleanStartIndex + int: mNextOffset
+    private static final int NODE_SKIP_BYTES = 12;
+
     private Header mHeader;
     private ByteBufferReader mReader;
 
@@ -60,6 +66,18 @@
         return null;
     }
 
+    public List<String> getPackageList() {
+        List<String> list = new ArrayList<>(mHeader.mNumPackages);
+        mReader.position(mHeader.mNodeOffset);
+        int fingerprintBytes = mHeader.mVersion == 1 ? 0 : FINGERPRINT_BYTES;
+        int skipBytes = fingerprintBytes + NODE_SKIP_BYTES;
+        for (int i = 0; i < mHeader.mNumPackages; i++) {
+            list.add(mReader.readString());
+            mReader.position(mReader.position() + skipBytes);
+        }
+        return list;
+    }
+
     public Header getHeader() {
         return mHeader;
     }
diff --git a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/StorageFileProvider.java b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/StorageFileProvider.java
index f1a4e26..f75ac36 100644
--- a/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/StorageFileProvider.java
+++ b/tools/aconfig/aconfig_storage_file/srcs/android/aconfig/storage/StorageFileProvider.java
@@ -39,13 +39,15 @@
     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 static final StorageFileProvider DEFAULT_INSTANCE =
+            new StorageFileProvider(DEFAULT_MAP_PATH, DEFAULT_BOOT_PATH);
 
     private final String mMapPath;
     private final String mBootPath;
 
     /** @hide */
     public static StorageFileProvider getDefaultProvider() {
-        return new StorageFileProvider(DEFAULT_MAP_PATH, DEFAULT_BOOT_PATH);
+        return DEFAULT_INSTANCE;
     }
 
     /** @hide */
@@ -82,7 +84,9 @@
 
     /** @hide */
     public PackageTable getPackageTable(String container) {
-        return getPackageTable(Paths.get(mMapPath, container + PMAP_FILE_EXT));
+        return PackageTable.fromBytes(
+                mapStorageFile(
+                        Paths.get(mMapPath, container + PMAP_FILE_EXT), FileType.PACKAGE_MAP));
     }
 
     /** @hide */
@@ -97,11 +101,6 @@
                 mapStorageFile(Paths.get(mBootPath, container + VAL_FILE_EXT), FileType.FLAG_VAL));
     }
 
-    /** @hide */
-    public static PackageTable getPackageTable(Path path) {
-        return PackageTable.fromBytes(mapStorageFile(path, FileType.PACKAGE_MAP));
-    }
-
     // Map a storage file given file path
     private static MappedByteBuffer mapStorageFile(Path file, FileType type) {
         FileChannel channel = null;
diff --git a/tools/aconfig/aconfig_storage_file/tests/srcs/PackageTableTest.java b/tools/aconfig/aconfig_storage_file/tests/srcs/PackageTableTest.java
index 5906d8b..812ce35 100644
--- a/tools/aconfig/aconfig_storage_file/tests/srcs/PackageTableTest.java
+++ b/tools/aconfig/aconfig_storage_file/tests/srcs/PackageTableTest.java
@@ -27,6 +27,9 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
+import java.util.HashSet;
+import java.util.Set;
+
 @RunWith(JUnit4.class)
 public class PackageTableTest {
 
@@ -121,4 +124,22 @@
         assertEquals(4431940502274857964L, node2.getPackageFingerprint());
         assertEquals(-2213514155997929241L, node4.getPackageFingerprint());
     }
+
+    @Test
+    public void testPackageTable_getPackageList() throws Exception {
+        PackageTable packageTable =
+                PackageTable.fromBytes(TestDataUtils.getTestPackageMapByteBuffer(2));
+        Set<String> packages = new HashSet<>(packageTable.getPackageList());
+        assertEquals(3, packages.size());
+        assertTrue(packages.contains("com.android.aconfig.storage.test_1"));
+        assertTrue(packages.contains("com.android.aconfig.storage.test_2"));
+        assertTrue(packages.contains("com.android.aconfig.storage.test_4"));
+
+        packageTable = PackageTable.fromBytes(TestDataUtils.getTestPackageMapByteBuffer(1));
+        packages = new HashSet<>(packageTable.getPackageList());
+        assertEquals(3, packages.size());
+        assertTrue(packages.contains("com.android.aconfig.storage.test_1"));
+        assertTrue(packages.contains("com.android.aconfig.storage.test_2"));
+        assertTrue(packages.contains("com.android.aconfig.storage.test_4"));
+    }
 }
diff --git a/tools/aconfig/aconfig_storage_file/tests/srcs/StorageFileProviderTest.java b/tools/aconfig/aconfig_storage_file/tests/srcs/StorageFileProviderTest.java
index a820970..c2720f9 100644
--- a/tools/aconfig/aconfig_storage_file/tests/srcs/StorageFileProviderTest.java
+++ b/tools/aconfig/aconfig_storage_file/tests/srcs/StorageFileProviderTest.java
@@ -58,10 +58,6 @@
                 new StorageFileProvider(TestDataUtils.TESTDATA_PATH, TestDataUtils.TESTDATA_PATH);
         PackageTable pt = p.getPackageTable("mock.v1");
         assertNotNull(pt);
-        pt =
-                StorageFileProvider.getPackageTable(
-                        Paths.get(TestDataUtils.TESTDATA_PATH, "mock.v1.package.map"));
-        assertNotNull(pt);
         FlagTable f = p.getFlagTable("mock.v1");
         assertNotNull(f);
         FlagValueList v = p.getFlagValueList("mock.v1");
diff --git a/tools/aconfig/aconfig_storage_read_api/srcs/android/os/flagging/PlatformAconfigPackageInternal.java b/tools/aconfig/aconfig_storage_read_api/srcs/android/os/flagging/PlatformAconfigPackageInternal.java
index e6b6db4..d73d9eb 100644
--- a/tools/aconfig/aconfig_storage_read_api/srcs/android/os/flagging/PlatformAconfigPackageInternal.java
+++ b/tools/aconfig/aconfig_storage_read_api/srcs/android/os/flagging/PlatformAconfigPackageInternal.java
@@ -17,7 +17,6 @@
 package android.os.flagging;
 
 import android.aconfig.storage.AconfigStorageException;
-import android.aconfig.storage.FlagTable;
 import android.aconfig.storage.FlagValueList;
 import android.aconfig.storage.PackageTable;
 import android.aconfig.storage.StorageFileProvider;
@@ -41,75 +40,13 @@
  */
 public class PlatformAconfigPackageInternal {
 
-    private final FlagTable mFlagTable;
     private final FlagValueList mFlagValueList;
-    private final int mPackageId;
     private final int mPackageBooleanStartOffset;
-    private final AconfigStorageReadException mException;
 
     private PlatformAconfigPackageInternal(
-            FlagValueList flagValueList,
-            FlagTable flagTable,
-            int packageBooleanStartOffset,
-            int packageId,
-            AconfigStorageReadException exception) {
+            FlagValueList flagValueList, int packageBooleanStartOffset) {
         this.mFlagValueList = flagValueList;
-        this.mFlagTable = flagTable;
         this.mPackageBooleanStartOffset = packageBooleanStartOffset;
-        this.mPackageId = packageId;
-        this.mException = exception;
-    }
-
-    /**
-     * Loads an Aconfig Package from platform Aconfig Storage.
-     *
-     * <p>This method is intended for internal use only and may be changed or removed without
-     * notice.
-     *
-     * <p>This method loads the specified Aconfig Package from the given container.
-     *
-     * <p>AconfigStorageException will be stored if there is an error reading from Aconfig Storage.
-     * The specific error code can be got using {@link #getException()}.
-     *
-     * @param container The name of the container.
-     * @param packageName The name of the Aconfig package to load.
-     * @return An instance of {@link PlatformAconfigPackageInternal}
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public static PlatformAconfigPackageInternal load(String container, String packageName) {
-        return load(container, packageName, StorageFileProvider.getDefaultProvider());
-    }
-
-    /** @hide */
-    public static PlatformAconfigPackageInternal load(
-            String container, String packageName, StorageFileProvider fileProvider) {
-        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-        try {
-            PackageTable.Node pNode = fileProvider.getPackageTable(container).get(packageName);
-
-            if (pNode == null) {
-                return createExceptionInstance(
-                        AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
-                        "package "
-                                + packageName
-                                + " in container "
-                                + container
-                                + " cannot be found on the device");
-            }
-
-            return new PlatformAconfigPackageInternal(
-                    fileProvider.getFlagValueList(container),
-                    fileProvider.getFlagTable(container),
-                    pNode.getBooleanStartIndex(),
-                    pNode.getPackageId(),
-                    null);
-
-        } catch (AconfigStorageException e) {
-            return createExceptionInstance(e.getErrorCode(), e.getMessage());
-        } finally {
-            StrictMode.setThreadPolicy(oldPolicy);
-        }
     }
 
     /**
@@ -118,9 +55,6 @@
      * <p>This method is intended for internal use only and may be changed or removed without
      * notice.
      *
-     * <p>AconfigStorageException will be stored if there is an error reading from Aconfig Storage.
-     * The specific error code can be got using {@link #getException()}.
-     *
      * @param container The name of the container.
      * @param packageName The name of the Aconfig package.
      * @param packageFingerprint The expected fingerprint of the package.
@@ -145,48 +79,40 @@
             long packageFingerprint,
             StorageFileProvider fileProvider) {
         StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+        PackageTable.Node pNode = null;
+        FlagValueList vList = null;
         try {
-            PackageTable.Node pNode = fileProvider.getPackageTable(container).get(packageName);
-
-            if (pNode == null) {
-                return createExceptionInstance(
-                        AconfigStorageReadException.ERROR_PACKAGE_NOT_FOUND,
-                        "package "
-                                + packageName
-                                + " in container "
-                                + container
-                                + " cannot be found on the device");
-            }
-
-            if (pNode.hasPackageFingerprint()
-                    && packageFingerprint != pNode.getPackageFingerprint()) {
-                return new PlatformAconfigPackageInternal(
-                        fileProvider.getFlagValueList(container),
-                        fileProvider.getFlagTable(container),
-                        pNode.getBooleanStartIndex(),
-                        pNode.getPackageId(),
-                        new AconfigStorageReadException(
-                                AconfigStorageException.ERROR_FILE_FINGERPRINT_MISMATCH,
-                                "The fingerprint provided for the Aconfig package "
-                                        + packageName
-                                        + " in container "
-                                        + container
-                                        + " does not match"
-                                        + " the fingerprint of the package found on the device."));
-            }
-
-            return new PlatformAconfigPackageInternal(
-                    fileProvider.getFlagValueList(container),
-                    null,
-                    pNode.getBooleanStartIndex(),
-                    0,
-                    null);
-
+            pNode = fileProvider.getPackageTable(container).get(packageName);
+            vList = fileProvider.getFlagValueList(container);
         } catch (AconfigStorageException e) {
-            return createExceptionInstance(e.getErrorCode(), e.getMessage());
+            throw new AconfigStorageReadException(e.getErrorCode(), e.toString());
         } finally {
             StrictMode.setThreadPolicy(oldPolicy);
         }
+
+        if (pNode == null || vList == null) {
+            throw new AconfigStorageReadException(
+                    AconfigStorageReadException.ERROR_PACKAGE_NOT_FOUND,
+                    String.format(
+                            "package "
+                                    + packageName
+                                    + " in container "
+                                    + container
+                                    + " cannot be found on the device"));
+        }
+
+        if (pNode.hasPackageFingerprint() && packageFingerprint != pNode.getPackageFingerprint()) {
+            throw new AconfigStorageReadException(
+                    5, // AconfigStorageReadException.ERROR_FILE_FINGERPRINT_MISMATCH,
+                    String.format(
+                            "package "
+                                    + packageName
+                                    + " in container "
+                                    + container
+                                    + " cannot be found on the device"));
+        }
+
+        return new PlatformAconfigPackageInternal(vList, pNode.getBooleanStartIndex());
     }
 
     /**
@@ -198,10 +124,6 @@
      * <p>This method retrieves the value of a flag within the loaded Aconfig package using its
      * index. The index is generated at build time and may vary between builds.
      *
-     * <p>To ensure you are using the correct index, verify that the package's fingerprint matches
-     * the expected fingerprint before calling this method. If the fingerprints do not match, use
-     * {@link #getBooleanFlagValue(String, boolean)} instead.
-     *
      * @param index The index of the flag within the package.
      * @return The boolean value of the flag.
      * @hide
@@ -210,55 +132,4 @@
     public boolean getBooleanFlagValue(int index) {
         return mFlagValueList.getBoolean(index + mPackageBooleanStartOffset);
     }
-
-    /**
-     * Retrieves the value of a boolean flag using its name.
-     *
-     * <p>This method is intended for internal use only and may be changed or removed without
-     * notice.
-     *
-     * <p>This method retrieves the value of a flag within the loaded Aconfig package using its
-     * name.
-     *
-     * @param flagName The name of the flag.
-     * @param defaultValue The default value to return if the flag is not found.
-     * @return The boolean value of the flag.
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public boolean getBooleanFlagValue(String flagName, boolean defaultValue) {
-        FlagTable.Node fNode = mFlagTable.get(mPackageId, flagName);
-        if (fNode == null) {
-            return defaultValue;
-        }
-        return mFlagValueList.getBoolean(fNode.getFlagIndex() + mPackageBooleanStartOffset);
-    }
-
-    /**
-     * Returns any exception that occurred during the loading of the Aconfig package.
-     *
-     * <p>This method is intended for internal use only and may be changed or removed without
-     * notice.
-     *
-     * @return The exception that occurred, or {@code null} if no exception occurred.
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public AconfigStorageReadException getException() {
-        return mException;
-    }
-
-    /**
-     * Creates a new {@link PlatformAconfigPackageInternal} instance with an {@link
-     * AconfigStorageException}.
-     *
-     * @param errorCode The error code for the exception.
-     * @param message The error message for the exception.
-     * @return A new {@link PlatformAconfigPackageInternal} instance with the specified exception.
-     */
-    private static PlatformAconfigPackageInternal createExceptionInstance(
-            int errorCode, String message) {
-        return new PlatformAconfigPackageInternal(
-                null, null, 0, 0, new AconfigStorageReadException(errorCode, message));
-    }
 }
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/PlatformAconfigPackageInternalTest.java b/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/PlatformAconfigPackageInternalTest.java
index c4a5560..69e224b 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/PlatformAconfigPackageInternalTest.java
+++ b/tools/aconfig/aconfig_storage_read_api/tests/functional/srcs/PlatformAconfigPackageInternalTest.java
@@ -16,18 +16,17 @@
 
 package android.aconfig.storage.test;
 
-import static android.aconfig.nano.Aconfig.ENABLED;
-
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
 
 import android.aconfig.DeviceProtos;
+import android.aconfig.nano.Aconfig;
 import android.aconfig.nano.Aconfig.parsed_flag;
-import android.aconfig.storage.AconfigStorageException;
 import android.aconfig.storage.FlagTable;
 import android.aconfig.storage.FlagValueList;
 import android.aconfig.storage.PackageTable;
 import android.aconfig.storage.StorageFileProvider;
+import android.os.flagging.AconfigStorageReadException;
 import android.os.flagging.PlatformAconfigPackageInternal;
 
 import org.junit.Test;
@@ -52,41 +51,9 @@
         StorageFileProvider fp = StorageFileProvider.getDefaultProvider();
 
         for (parsed_flag flag : flags) {
-
-            String container = flag.container;
-            String packageName = flag.package_;
-            String flagName = flag.name;
-            if (!PLATFORM_CONTAINERS.contains(container)) continue;
-
-            PackageTable pTable = fp.getPackageTable(container);
-            PackageTable.Node pNode = pTable.get(packageName);
-            FlagTable fTable = fp.getFlagTable(container);
-            FlagTable.Node fNode = fTable.get(pNode.getPackageId(), flagName);
-            FlagValueList fList = fp.getFlagValueList(container);
-
-            int index = pNode.getBooleanStartIndex() + fNode.getFlagIndex();
-            boolean rVal = fList.getBoolean(index);
-
-            PlatformAconfigPackageInternal reader = readerMap.get(packageName);
-            if (reader == null) {
-                reader = PlatformAconfigPackageInternal.load(container, packageName);
-                assertNull(reader.getException());
-                readerMap.put(packageName, reader);
+            if (flag.permission == Aconfig.READ_ONLY && flag.state == Aconfig.DISABLED) {
+                continue;
             }
-            boolean jVal = reader.getBooleanFlagValue(flagName, !rVal);
-
-            assertEquals(rVal, jVal);
-        }
-    }
-
-    @Test
-    public void testPlatformAconfigPackageInternal_load_with_fingerprint() throws IOException {
-        List<parsed_flag> flags = DeviceProtos.loadAndParseFlagProtos();
-        Map<String, PlatformAconfigPackageInternal> readerMap = new HashMap<>();
-        StorageFileProvider fp = StorageFileProvider.getDefaultProvider();
-
-        for (parsed_flag flag : flags) {
-
             String container = flag.container;
             String packageName = flag.package_;
             String flagName = flag.name;
@@ -106,7 +73,6 @@
             PlatformAconfigPackageInternal reader = readerMap.get(packageName);
             if (reader == null) {
                 reader = PlatformAconfigPackageInternal.load(container, packageName, fingerprint);
-                assertNull(reader.getException());
                 readerMap.put(packageName, reader);
             }
             boolean jVal = reader.getBooleanFlagValue(fNode.getFlagIndex());
@@ -118,17 +84,20 @@
     @Test
     public void testAconfigPackage_load_withError() throws IOException {
         // container not found fake_container
-        PlatformAconfigPackageInternal aPackage =
-                PlatformAconfigPackageInternal.load("fake_container", "fake_package", 0);
-        assertEquals(
-                AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
-                aPackage.getException().getErrorCode());
+        AconfigStorageReadException e =
+                assertThrows(
+                        AconfigStorageReadException.class,
+                        () ->
+                                PlatformAconfigPackageInternal.load(
+                                        "fake_container", "fake_package", 0));
+        assertEquals(AconfigStorageReadException.ERROR_CANNOT_READ_STORAGE_FILE, e.getErrorCode());
 
         // package not found
-        aPackage = PlatformAconfigPackageInternal.load("system", "fake_container", 0);
-        assertEquals(
-                AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
-                aPackage.getException().getErrorCode());
+        e =
+                assertThrows(
+                        AconfigStorageReadException.class,
+                        () -> PlatformAconfigPackageInternal.load("system", "fake_container", 0));
+        assertEquals(AconfigStorageReadException.ERROR_PACKAGE_NOT_FOUND, e.getErrorCode());
 
         // fingerprint doesn't match
         List<parsed_flag> flags = DeviceProtos.loadAndParseFlagProtos();
@@ -138,18 +107,22 @@
 
         String container = flag.container;
         String packageName = flag.package_;
-        boolean value = flag.state == ENABLED;
+        boolean value = flag.state == Aconfig.ENABLED;
 
         PackageTable pTable = fp.getPackageTable(container);
         PackageTable.Node pNode = pTable.get(packageName);
 
         if (pNode.hasPackageFingerprint()) {
             long fingerprint = pNode.getPackageFingerprint();
-            aPackage = PlatformAconfigPackageInternal.load(container, packageName, fingerprint + 1);
+            e =
+                    assertThrows(
+                            AconfigStorageReadException.class,
+                            () ->
+                                    PlatformAconfigPackageInternal.load(
+                                            container, packageName, fingerprint + 1));
             assertEquals(
                     // AconfigStorageException.ERROR_FILE_FINGERPRINT_MISMATCH,
-                    5, aPackage.getException().getErrorCode());
-            assertEquals(aPackage.getBooleanFlagValue(flag.name, !value), value);
+                    5, e.getErrorCode());
         }
     }
 }
diff --git a/tools/aconfig/aconfig_storage_read_api/tests/unit/srcs/PlatformAconfigPackageInternalTest.java b/tools/aconfig/aconfig_storage_read_api/tests/unit/srcs/PlatformAconfigPackageInternalTest.java
index ce3786a..961f0ea 100644
--- a/tools/aconfig/aconfig_storage_read_api/tests/unit/srcs/PlatformAconfigPackageInternalTest.java
+++ b/tools/aconfig/aconfig_storage_read_api/tests/unit/srcs/PlatformAconfigPackageInternalTest.java
@@ -18,12 +18,12 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 
-import android.aconfig.storage.AconfigStorageException;
 import android.aconfig.storage.PackageTable;
 import android.aconfig.storage.StorageFileProvider;
+import android.os.flagging.AconfigStorageReadException;
 import android.os.flagging.PlatformAconfigPackageInternal;
 
 import org.junit.Before;
@@ -46,137 +46,101 @@
 
     @Test
     public void testLoad_container_package() throws Exception {
+        PackageTable packageTable = pr.getPackageTable("mockup");
+
+        PackageTable.Node node1 = packageTable.get("com.android.aconfig.storage.test_1");
+
+        long fingerprint = node1.getPackageFingerprint();
         PlatformAconfigPackageInternal p =
                 PlatformAconfigPackageInternal.load(
-                        "mockup", "com.android.aconfig.storage.test_1", pr);
-        assertNull(p.getException());
+                        "mockup", "com.android.aconfig.storage.test_1", fingerprint, pr);
     }
 
     @Test
     public void testLoad_container_package_error() throws Exception {
+        PackageTable packageTable = pr.getPackageTable("mockup");
+        PackageTable.Node node1 = packageTable.get("com.android.aconfig.storage.test_1");
+        long fingerprint = node1.getPackageFingerprint();
         // cannot find package
-        PlatformAconfigPackageInternal p =
-                PlatformAconfigPackageInternal.load(
-                        "mockup", "com.android.aconfig.storage.test_10", pr);
-
-        assertEquals(
-                AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
-                p.getException().getErrorCode());
+        AconfigStorageReadException e =
+                assertThrows(
+                        AconfigStorageReadException.class,
+                        () ->
+                                PlatformAconfigPackageInternal.load(
+                                        "mockup",
+                                        "com.android.aconfig.storage.test_10",
+                                        fingerprint,
+                                        pr));
+        assertEquals(AconfigStorageReadException.ERROR_PACKAGE_NOT_FOUND, e.getErrorCode());
 
         // cannot find container
-        p = PlatformAconfigPackageInternal.load(null, "com.android.aconfig.storage.test_1", pr);
-        assertEquals(
-                AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
-                p.getException().getErrorCode());
-        p = PlatformAconfigPackageInternal.load("test", "com.android.aconfig.storage.test_1", pr);
-        assertEquals(
-                AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
-                p.getException().getErrorCode());
+        e =
+                assertThrows(
+                        AconfigStorageReadException.class,
+                        () ->
+                                PlatformAconfigPackageInternal.load(
+                                        null,
+                                        "com.android.aconfig.storage.test_1",
+                                        fingerprint,
+                                        pr));
+        assertEquals(AconfigStorageReadException.ERROR_CANNOT_READ_STORAGE_FILE, e.getErrorCode());
 
-        // new storage doesn't exist
-        pr = new StorageFileProvider("fake/path/", "fake/path/");
-        p = PlatformAconfigPackageInternal.load("mockup", "com.android.aconfig.storage.test_1", pr);
-        assertEquals(
-                AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
-                p.getException().getErrorCode());
+        e =
+                assertThrows(
+                        AconfigStorageReadException.class,
+                        () ->
+                                PlatformAconfigPackageInternal.load(
+                                        "test",
+                                        "com.android.aconfig.storage.test_1",
+                                        fingerprint,
+                                        pr));
+        assertEquals(AconfigStorageReadException.ERROR_CANNOT_READ_STORAGE_FILE, e.getErrorCode());
 
-        // file read issue
-        pr = new StorageFileProvider(TESTDATA_PATH, "fake/path/");
-        p = PlatformAconfigPackageInternal.load("mockup", "com.android.aconfig.storage.test_1", pr);
-        assertEquals(
-                AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
-                p.getException().getErrorCode());
-    }
-
-    @Test
-    public void testLoad_container_package_fingerprint() throws Exception {
-        PackageTable packageTable = pr.getPackageTable("mockup");
-
-        PackageTable.Node node1 = packageTable.get("com.android.aconfig.storage.test_1");
-
-        long fingerprint = node1.getPackageFingerprint();
-        PlatformAconfigPackageInternal p =
-                PlatformAconfigPackageInternal.load(
-                        "mockup", "com.android.aconfig.storage.test_1", fingerprint, pr);
-        assertNull(p.getException());
-    }
-
-    @Test
-    public void testLoad_container_package_fingerprint_error() throws Exception {
-
-        PackageTable packageTable = pr.getPackageTable("mockup");
-
-        PackageTable.Node node1 = packageTable.get("com.android.aconfig.storage.test_1");
-
-        long fingerprint = node1.getPackageFingerprint();
-
-        // cannot find package
-        PlatformAconfigPackageInternal p =
-                PlatformAconfigPackageInternal.load(
-                        "mockup", "com.android.aconfig.storage.test_10", fingerprint, pr);
-
-        assertEquals(
-                AconfigStorageException.ERROR_PACKAGE_NOT_FOUND,
-                p.getException().getErrorCode());
-
-        // cannot find container
-        p =
-                PlatformAconfigPackageInternal.load(
-                        null, "com.android.aconfig.storage.test_1", fingerprint, pr);
-        assertEquals(
-                AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
-                p.getException().getErrorCode());
-        p =
-                PlatformAconfigPackageInternal.load(
-                        "test", "com.android.aconfig.storage.test_1", fingerprint, pr);
-        assertEquals(
-                AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
-                p.getException().getErrorCode());
         // fingerprint doesn't match
-        p =
-                PlatformAconfigPackageInternal.load(
-                        "mockup", "com.android.aconfig.storage.test_1", fingerprint + 1, pr);
+        e =
+                assertThrows(
+                        AconfigStorageReadException.class,
+                        () ->
+                                PlatformAconfigPackageInternal.load(
+                                        "mockup",
+                                        "com.android.aconfig.storage.test_1",
+                                        fingerprint + 1,
+                                        pr));
         assertEquals(
                 // AconfigStorageException.ERROR_FILE_FINGERPRINT_MISMATCH,
-                5, p.getException().getErrorCode());
+                5, e.getErrorCode());
 
         // new storage doesn't exist
         pr = new StorageFileProvider("fake/path/", "fake/path/");
-        p =
-                PlatformAconfigPackageInternal.load(
-                        "mockup", "com.android.aconfig.storage.test_1", fingerprint, pr);
-        assertEquals(
-                AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
-                p.getException().getErrorCode());
+        e =
+                assertThrows(
+                        AconfigStorageReadException.class,
+                        () ->
+                                PlatformAconfigPackageInternal.load(
+                                        "mockup",
+                                        "com.android.aconfig.storage.test_1",
+                                        fingerprint,
+                                        pr));
+        assertEquals(AconfigStorageReadException.ERROR_CANNOT_READ_STORAGE_FILE, e.getErrorCode());
 
         // file read issue
         pr = new StorageFileProvider(TESTDATA_PATH, "fake/path/");
-        p =
-                PlatformAconfigPackageInternal.load(
-                        "mockup", "com.android.aconfig.storage.test_1", fingerprint, pr);
-        assertEquals(
-                AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
-                p.getException().getErrorCode());
-    }
-
-    @Test
-    public void testGetBooleanFlagValue_flagName() throws Exception {
-        PlatformAconfigPackageInternal p =
-                PlatformAconfigPackageInternal.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));
+        e =
+                assertThrows(
+                        AconfigStorageReadException.class,
+                        () ->
+                                PlatformAconfigPackageInternal.load(
+                                        "mockup",
+                                        "com.android.aconfig.storage.test_1",
+                                        fingerprint,
+                                        pr));
+        assertEquals(AconfigStorageReadException.ERROR_CANNOT_READ_STORAGE_FILE, e.getErrorCode());
     }
 
     @Test
     public void testGetBooleanFlagValue_index() throws Exception {
-
         PackageTable packageTable = pr.getPackageTable("mockup");
-
         PackageTable.Node node1 = packageTable.get("com.android.aconfig.storage.test_1");
-
         long fingerprint = node1.getPackageFingerprint();
         PlatformAconfigPackageInternal p =
                 PlatformAconfigPackageInternal.load(
diff --git a/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigPackageInternal.java b/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigPackageInternal.java
index 5f066a8..d084048 100644
--- a/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigPackageInternal.java
+++ b/tools/aconfig/fake_device_config/src/android/os/flagging/AconfigPackageInternal.java
@@ -21,10 +21,6 @@
  */
 public class AconfigPackageInternal {
 
-    public static AconfigPackageInternal load(String container, String packageName) {
-        throw new UnsupportedOperationException("Stub!");
-    }
-
     public static AconfigPackageInternal load(
             String container, String packageName, long packageFingerprint) {
         throw new UnsupportedOperationException("Stub!");
@@ -33,12 +29,4 @@
     public boolean getBooleanFlagValue(int index) {
         throw new UnsupportedOperationException("Stub!");
     }
-
-    public boolean getBooleanFlagValue(String flagName, boolean defaultValue) {
-        throw new UnsupportedOperationException("Stub!");
-    }
-
-    public AconfigStorageReadException getException() {
-        throw new UnsupportedOperationException("Stub!");
-    }
 }
diff --git a/tools/aconfig/fake_device_config/src/android/os/flagging/PlatformAconfigPackageInternal.java b/tools/aconfig/fake_device_config/src/android/os/flagging/PlatformAconfigPackageInternal.java
index c1bc19b..283b251 100644
--- a/tools/aconfig/fake_device_config/src/android/os/flagging/PlatformAconfigPackageInternal.java
+++ b/tools/aconfig/fake_device_config/src/android/os/flagging/PlatformAconfigPackageInternal.java
@@ -21,10 +21,6 @@
  */
 public class PlatformAconfigPackageInternal {
 
-    public static PlatformAconfigPackageInternal load(String container, String packageName) {
-        throw new UnsupportedOperationException("Stub!");
-    }
-
     public static PlatformAconfigPackageInternal load(
             String container, String packageName, long packageFingerprint) {
         throw new UnsupportedOperationException("Stub!");
@@ -33,12 +29,4 @@
     public boolean getBooleanFlagValue(int index) {
         throw new UnsupportedOperationException("Stub!");
     }
-
-    public boolean getBooleanFlagValue(String flagName, boolean defaultValue) {
-        throw new UnsupportedOperationException("Stub!");
-    }
-
-    public AconfigStorageReadException getException() {
-        throw new UnsupportedOperationException("Stub!");
-    }
 }
diff --git a/tools/edit_monitor/daemon_manager.py b/tools/edit_monitor/daemon_manager.py
index a352e30..7d666fe 100644
--- a/tools/edit_monitor/daemon_manager.py
+++ b/tools/edit_monitor/daemon_manager.py
@@ -13,6 +13,8 @@
 # limitations under the License.
 
 
+import errno
+import fcntl
 import getpass
 import hashlib
 import logging
@@ -100,16 +102,32 @@
       logging.warning("Edit monitor for cog is not supported, exiting...")
       return
 
-    try:
-      self._stop_any_existing_instance()
-      self._write_pid_to_pidfile()
-      self._start_daemon_process()
-    except Exception as e:
-      logging.exception("Failed to start daemon manager with error %s", e)
-      self._send_error_event_to_clearcut(
-          edit_event_pb2.EditEvent.FAILED_TO_START_EDIT_MONITOR
-      )
-      raise e
+    setup_lock_file = pathlib.Path(tempfile.gettempdir()).joinpath(
+        self.pid_file_path.name + ".setup"
+    )
+    logging.info("setup lock file: %s", setup_lock_file)
+    with open(setup_lock_file, "w") as f:
+      try:
+        # Acquire an exclusive lock
+        fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
+        self._stop_any_existing_instance()
+        self._write_pid_to_pidfile()
+        self._start_daemon_process()
+      except Exception as e:
+        if (
+            isinstance(e, IOError) and e.errno == errno.EAGAIN
+        ):  # Failed to acquire the file lock.
+          logging.warning("Another edit monitor is starting, exitinng...")
+          return
+        else:
+          logging.exception("Failed to start daemon manager with error %s", e)
+          self._send_error_event_to_clearcut(
+              edit_event_pb2.EditEvent.FAILED_TO_START_EDIT_MONITOR
+          )
+          raise e
+      finally:
+        # Release the lock
+        fcntl.flock(f, fcntl.LOCK_UN)
 
   def monitor_daemon(
       self,
@@ -413,13 +431,19 @@
   def _find_all_instances_pids(self) -> list[int]:
     pids = []
 
-    for file in os.listdir(self.pid_file_path.parent):
-      if file.endswith(".lock"):
-        try:
-          with open(self.pid_file_path.parent.joinpath(file), "r") as f:
-            pids.append(int(f.read().strip()))
-        except (FileNotFoundError, IOError, ValueError, TypeError):
-          logging.exception("Failed to get pid from file path: %s", file)
+    try:
+      output = subprocess.check_output(["ps", "-ef", "--no-headers"], text=True)
+      for line in output.splitlines():
+        parts = line.split()
+        process_path = parts[7]
+        if pathlib.Path(process_path).name == "edit_monitor":
+          pid = int(parts[1])
+          if pid != self.pid:  # exclude the current process
+            pids.append(pid)
+    except Exception:
+      logging.exception(
+          "Failed to get pids of existing edit monitors from ps command."
+      )
 
     return pids
 
diff --git a/tools/edit_monitor/daemon_manager_test.py b/tools/edit_monitor/daemon_manager_test.py
index 350739d..be28965 100644
--- a/tools/edit_monitor/daemon_manager_test.py
+++ b/tools/edit_monitor/daemon_manager_test.py
@@ -14,6 +14,7 @@
 
 """Unittests for DaemonManager."""
 
+import fcntl
 import logging
 import multiprocessing
 import os
@@ -82,7 +83,8 @@
     # tests will be cleaned.
     tempfile.tempdir = self.working_dir.name
     self.patch = mock.patch.dict(
-        os.environ, {'ENABLE_ANDROID_EDIT_MONITOR': 'true'})
+        os.environ, {'ENABLE_ANDROID_EDIT_MONITOR': 'true'}
+    )
     self.patch.start()
 
   def tearDown(self):
@@ -102,6 +104,7 @@
     p = self._create_fake_deamon_process()
 
     self.assert_run_simple_daemon_success()
+    self.assert_no_subprocess_running()
 
   def test_start_success_with_existing_instance_already_dead(self):
     # Create a pidfile with pid that does not exist.
@@ -137,7 +140,9 @@
     # Verify no daemon process is started.
     self.assertIsNone(dm.daemon_process)
 
-  @mock.patch.dict(os.environ, {'ENABLE_ANDROID_EDIT_MONITOR': 'false'}, clear=True)
+  @mock.patch.dict(
+      os.environ, {'ENABLE_ANDROID_EDIT_MONITOR': 'false'}, clear=True
+  )
   def test_start_return_directly_if_disabled(self):
     dm = daemon_manager.DaemonManager(TEST_BINARY_FILE)
     dm.start()
@@ -154,6 +159,25 @@
     # Verify no daemon process is started.
     self.assertIsNone(dm.daemon_process)
 
+  def test_start_failed_other_instance_is_starting(self):
+    f = open(
+        pathlib.Path(self.working_dir.name).joinpath(
+            TEST_PID_FILE_PATH + '.setup'
+        ),
+        'w',
+    )
+    # Acquire an exclusive lock
+    fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
+
+    dm = daemon_manager.DaemonManager(TEST_BINARY_FILE)
+    dm.start()
+
+    # Release the lock
+    fcntl.flock(f, fcntl.LOCK_UN)
+    f.close()
+    # Verify no daemon process is started.
+    self.assertIsNone(dm.daemon_process)
+
   @mock.patch('os.kill')
   def test_start_failed_to_kill_existing_instance(self, mock_kill):
     mock_kill.side_effect = OSError('Unknown OSError')
@@ -177,6 +201,7 @@
         'edit_monitor'
     )
     pid_file_path_dir.mkdir(parents=True, exist_ok=True)
+
     # Makes the directory read-only so write pidfile will fail.
     os.chmod(pid_file_path_dir, 0o555)
 
@@ -216,7 +241,7 @@
         cclient=fake_cclient,
     )
     # set the fake total_memory_size
-    dm.total_memory_size = 100 * 1024 *1024
+    dm.total_memory_size = 100 * 1024 * 1024
     dm.start()
     dm.monitor_daemon(interval=1)
 
@@ -367,6 +392,26 @@
         fake_cclient, edit_event_pb2.EditEvent.FAILED_TO_REBOOT_EDIT_MONITOR
     )
 
+  @mock.patch('subprocess.check_output')
+  def test_cleanup_success(self, mock_check_output):
+    p = self._create_fake_deamon_process()
+    fake_cclient = FakeClearcutClient()
+    mock_check_output.return_value = f'user {p.pid} 1 1 1 1 1 edit_monitor arg'
+
+    dm = daemon_manager.DaemonManager(
+        TEST_BINARY_FILE,
+        daemon_target=long_running_daemon,
+        cclient=fake_cclient,
+    )
+    dm.cleanup()
+
+    self.assertFalse(p.is_alive())
+    self.assertTrue(
+        pathlib.Path(self.working_dir.name)
+        .joinpath(daemon_manager.BLOCK_SIGN_FILE)
+        .exists()
+    )
+
   def assert_run_simple_daemon_success(self):
     damone_output_file = tempfile.NamedTemporaryFile(
         dir=self.working_dir.name, delete=False
@@ -432,7 +477,7 @@
         pass
 
   def _create_fake_deamon_process(
-      self, name: str = ''
+      self, name: str = TEST_PID_FILE_PATH
   ) -> multiprocessing.Process:
     # Create a long running subprocess
     p = multiprocessing.Process(target=long_running_daemon)
@@ -443,7 +488,7 @@
         'edit_monitor'
     )
     pid_file_path_dir.mkdir(parents=True, exist_ok=True)
-    with open(pid_file_path_dir.joinpath(name + 'pid.lock'), 'w') as f:
+    with open(pid_file_path_dir.joinpath(name), 'w') as f:
       f.write(str(p.pid))
     return p
 
diff --git a/tools/edit_monitor/main.py b/tools/edit_monitor/main.py
index 7ca0daa..3c2d183 100644
--- a/tools/edit_monitor/main.py
+++ b/tools/edit_monitor/main.py
@@ -102,12 +102,12 @@
       daemon_args=(args.path, args.dry_run),
   )
 
-  if args.force_cleanup:
-    dm.cleanup()
-
   try:
-    dm.start()
-    dm.monitor_daemon()
+    if args.force_cleanup:
+      dm.cleanup()
+    else:
+      dm.start()
+      dm.monitor_daemon()
   except Exception:
     logging.exception('Unexpected exception raised when run daemon.')
   finally:
diff --git a/tools/event_log_tags.py b/tools/event_log_tags.py
index a6ae9f1..e859b6b 100644
--- a/tools/event_log_tags.py
+++ b/tools/event_log_tags.py
@@ -14,21 +14,21 @@
 
 """A module for reading and parsing event-log-tags files."""
 
+import dataclasses
 import re
 import sys
+from typing import Optional
 
-class Tag(object):
-  __slots__ = ["tagnum", "tagname", "description", "filename", "linenum"]
-
-  def __init__(self, tagnum, tagname, description, filename, linenum):
-    self.tagnum = tagnum
-    self.tagname = tagname
-    self.description = description
-    self.filename = filename
-    self.linenum = linenum
+@dataclasses.dataclass
+class Tag:
+  tagnum: int
+  tagname: str
+  description: Optional[str]
+  filename: str
+  linenum: int
 
 
-class TagFile(object):
+class TagFile:
   """Read an input event-log-tags file."""
   def AddError(self, msg, linenum=None):
     if linenum is None:
@@ -76,14 +76,11 @@
           self.options[parts[1]] = parts[2:]
           continue
 
-        if parts[0] == "?":
-          tag = None
-        else:
-          try:
-            tag = int(parts[0])
-          except ValueError:
-            self.AddError("\"%s\" isn't an integer tag or '?'" % (parts[0],))
-            continue
+        try:
+          tag = int(parts[0])
+        except ValueError:
+          self.AddError("\"%s\" isn't an integer tag" % (parts[0],))
+          continue
 
         tagname = parts[1]
         if len(parts) == 3:
@@ -128,8 +125,8 @@
       out = sys.stdout
       output_file = "<stdout>"
     else:
-      out = open(output_file, "wb")
-    out.write(str.encode(data))
+      out = open(output_file, "w")
+    out.write(data)
     out.close()
   except (IOError, OSError) as e:
     print("failed to write %s: %s" % (output_file, e), file=sys.stderr)
diff --git a/tools/java-event-log-tags.py b/tools/java-event-log-tags.py
index bbd65fa..e3dc07e 100755
--- a/tools/java-event-log-tags.py
+++ b/tools/java-event-log-tags.py
@@ -15,16 +15,12 @@
 # limitations under the License.
 
 """
-Usage: java-event-log-tags.py [-o output_file] <input_file> <merged_tags_file>
-
 Generate a java class containing constants for each of the event log
 tags in the given input file.
-
--h to display this usage message and exit.
 """
 
 from io import StringIO
-import getopt
+import argparse
 import os
 import os.path
 import re
@@ -32,57 +28,14 @@
 
 import event_log_tags
 
-output_file = None
+parser = argparse.ArgumentParser(description=__doc__)
+parser.add_argument('-o', dest='output_file')
+parser.add_argument('file')
+args = parser.parse_args()
 
-try:
-  opts, args = getopt.getopt(sys.argv[1:], "ho:")
-except getopt.GetoptError as err:
-  print(str(err))
-  print(__doc__)
-  sys.exit(2)
-
-for o, a in opts:
-  if o == "-h":
-    print(__doc__)
-    sys.exit(2)
-  elif o == "-o":
-    output_file = a
-  else:
-    print("unhandled option %s" % (o,), file=sys.stderr)
-    sys.exit(1)
-
-if len(args) != 1 and len(args) != 2:
-  print("need one or two input files, not %d" % (len(args),))
-  print(__doc__)
-  sys.exit(1)
-
-fn = args[0]
+fn = args.file
 tagfile = event_log_tags.TagFile(fn)
 
-if len(args) > 1:
-  # Load the merged tag file (which should have numbers assigned for all
-  # tags.  Use the numbers from the merged file to fill in any missing
-  # numbers from the input file.
-  merged_fn = args[1]
-  merged_tagfile = event_log_tags.TagFile(merged_fn)
-  merged_by_name = dict([(t.tagname, t) for t in merged_tagfile.tags])
-  for t in tagfile.tags:
-    if t.tagnum is None:
-      if t.tagname in merged_by_name:
-        t.tagnum = merged_by_name[t.tagname].tagnum
-      else:
-        # We're building something that's not being included in the
-        # product, so its tags don't appear in the merged file.  Assign
-        # them all an arbitrary number so we can emit the java and
-        # compile the (unused) package.
-        t.tagnum = 999999
-else:
-  # Not using the merged tag file, so all tags must have manually assigned
-  # numbers
-  for t in tagfile.tags:
-    if t.tagnum is None:
-      tagfilef.AddError("tag \"%s\" has no number" % (tagname,), tag.linenum)
-
 if "java_package" not in tagfile.options:
   tagfile.AddError("java_package option not specified", linenum=0)
 
@@ -141,11 +94,11 @@
 for t in tagfile.tags:
   methodName = javaName("write_" + t.tagname)
   if t.description:
-    args = [arg.strip("() ").split("|") for arg in t.description.split(",")]
+    fn_args = [arg.strip("() ").split("|") for arg in t.description.split(",")]
   else:
-    args = []
-  argTypesNames = ", ".join([javaTypes[int(arg[1])] + " " + javaName(arg[0]) for arg in args])
-  argNames = "".join([", " + javaName(arg[0]) for arg in args])
+    fn_args = []
+  argTypesNames = ", ".join([javaTypes[int(arg[1])] + " " + javaName(arg[0]) for arg in fn_args])
+  argNames = "".join([", " + javaName(arg[0]) for arg in fn_args])
   buffer.write("\n  public static void %s(%s) {" % (methodName, argTypesNames))
   buffer.write("\n    android.util.EventLog.writeEvent(%s%s);" % (t.tagname.upper(), argNames))
   buffer.write("\n  }\n")
@@ -153,8 +106,8 @@
 
 buffer.write("}\n");
 
-output_dir = os.path.dirname(output_file)
+output_dir = os.path.dirname(args.output_file)
 if not os.path.exists(output_dir):
   os.makedirs(output_dir)
 
-event_log_tags.WriteOutput(output_file, buffer)
+event_log_tags.WriteOutput(args.output_file, buffer)
diff --git a/tools/merge-event-log-tags.py b/tools/merge-event-log-tags.py
index 292604c..5730c11 100755
--- a/tools/merge-event-log-tags.py
+++ b/tools/merge-event-log-tags.py
@@ -15,22 +15,13 @@
 # limitations under the License.
 
 """
-Usage: merge-event-log-tags.py [-o output_file] [input_files...]
-
 Merge together zero or more event-logs-tags files to produce a single
 output file, stripped of comments.  Checks that no tag numbers conflict
 and fails if they do.
-
--h to display this usage message and exit.
 """
 
 from io import StringIO
-import getopt
-try:
-  import hashlib
-except ImportError:
-  import md5 as hashlib
-import struct
+import argparse
 import sys
 
 import event_log_tags
@@ -38,32 +29,10 @@
 errors = []
 warnings = []
 
-output_file = None
-pre_merged_file = None
-
-# Tags with a tag number of ? are assigned a tag in the range
-# [ASSIGN_START, ASSIGN_LIMIT).
-ASSIGN_START = 900000
-ASSIGN_LIMIT = 1000000
-
-try:
-  opts, args = getopt.getopt(sys.argv[1:], "ho:m:")
-except getopt.GetoptError as err:
-  print(str(err))
-  print(__doc__)
-  sys.exit(2)
-
-for o, a in opts:
-  if o == "-h":
-    print(__doc__)
-    sys.exit(2)
-  elif o == "-o":
-    output_file = a
-  elif o == "-m":
-    pre_merged_file = a
-  else:
-    print("unhandled option %s" % (o,), file=sys.stderr)
-    sys.exit(1)
+parser = argparse.ArgumentParser(description=__doc__)
+parser.add_argument('-o', dest='output_file')
+parser.add_argument('files', nargs='*')
+args = parser.parse_args()
 
 # Restrictions on tags:
 #
@@ -77,12 +46,7 @@
 by_tagname = {}
 by_tagnum = {}
 
-pre_merged_tags = {}
-if pre_merged_file:
-  for t in event_log_tags.TagFile(pre_merged_file).tags:
-    pre_merged_tags[t.tagname] = t
-
-for fn in args:
+for fn in args.files:
   tagfile = event_log_tags.TagFile(fn)
 
   for t in tagfile.tags:
@@ -93,12 +57,6 @@
     if t.tagname in by_tagname:
       orig = by_tagname[t.tagname]
 
-      # Allow an explicit tag number to define an implicit tag number
-      if orig.tagnum is None:
-        orig.tagnum = t.tagnum
-      elif t.tagnum is None:
-        t.tagnum = orig.tagnum
-
       if (t.tagnum == orig.tagnum and
           t.description == orig.description):
         # if the name and description are identical, issue a warning
@@ -114,7 +72,7 @@
             linenum=t.linenum)
       continue
 
-    if t.tagnum is not None and t.tagnum in by_tagnum:
+    if t.tagnum in by_tagnum:
       orig = by_tagnum[t.tagnum]
 
       if t.tagname != orig.tagname:
@@ -125,8 +83,7 @@
         continue
 
     by_tagname[t.tagname] = t
-    if t.tagnum is not None:
-      by_tagnum[t.tagnum] = t
+    by_tagnum[t.tagnum] = t
 
   errors.extend(tagfile.errors)
   warnings.extend(tagfile.warnings)
@@ -140,38 +97,6 @@
   for fn, ln, msg in warnings:
     print("%s:%d: warning: %s" % (fn, ln, msg), file=sys.stderr)
 
-# Python's hash function (a) isn't great and (b) varies between
-# versions of python.  Using md5 is overkill here but is the same from
-# platform to platform and speed shouldn't matter in practice.
-def hashname(str):
-  d = hashlib.md5(str).digest()[:4]
-  return struct.unpack("!I", d)[0]
-
-# Assign a tag number to all the entries that say they want one
-# assigned.  We do this based on a hash of the tag name so that the
-# numbers should stay relatively stable as tags are added.
-
-# If we were provided pre-merged tags (w/ the -m option), then don't
-# ever try to allocate one, just fail if we don't have a number
-
-for name, t in sorted(by_tagname.items()):
-  if t.tagnum is None:
-    if pre_merged_tags:
-      try:
-        t.tagnum = pre_merged_tags[t.tagname]
-      except KeyError:
-        print("Error: Tag number not defined for tag `%s'. Have you done a full build?" % t.tagname,
-              file=sys.stderr)
-        sys.exit(1)
-    else:
-      while True:
-        x = (hashname(name) % (ASSIGN_LIMIT - ASSIGN_START - 1)) + ASSIGN_START
-        if x not in by_tagnum:
-          t.tagnum = x
-          by_tagnum[x] = t
-          break
-        name = "_" + name
-
 # by_tagnum should be complete now; we've assigned numbers to all tags.
 
 buffer = StringIO()
@@ -181,4 +106,4 @@
   else:
     buffer.write("%d %s\n" % (t.tagnum, t.tagname))
 
-event_log_tags.WriteOutput(output_file, buffer)
+event_log_tags.WriteOutput(args.output_file, buffer)