Merge "Enable R8 by default (second attempt for Q)"
diff --git a/core/aapt2.mk b/core/aapt2.mk
index c582e30..895bd37 100644
--- a/core/aapt2.mk
+++ b/core/aapt2.mk
@@ -12,6 +12,7 @@
 # - proguard_options_file
 # - my_generated_res_dirs: Resources generated during the build process and we have to compile them in a single run of aapt2.
 # - my_generated_res_dirs_deps: the dependency to use for my_generated_res_dirs.
+# - my_generated_res_zips: Zip files containing resources
 # - my_apk_split_configs: The configurations for which to generate splits.
 # - built_apk_splits: The paths where AAPT should generate the splits.
 #
@@ -35,7 +36,7 @@
     $(eval $(call aapt2-compile-one-resource-file-rule,$(r),$(o)))\
     $(o))
 
-my_generated_resources_flata :=
+my_resources_flata :=
 # Compile generated resources
 ifneq ($(my_generated_res_dirs),)
 my_generated_resources_flata := $(my_compiled_res_base_dir)/gen_res.flata
@@ -44,12 +45,23 @@
 	@echo "AAPT2 compile $@ <- $(PRIVATE_SOURCE_RES_DIRS)"
 	$(call aapt2-compile-resource-dirs)
 
-my_generated_resources_flata += $(my_generated_resources_flata)
+my_resources_flata += $(my_generated_resources_flata)
+endif
+
+# Compile zipped resources
+ifneq ($(my_generated_res_zips),)
+my_zipped_resources_flata := $(my_compiled_res_base_dir)/zip_res.flata
+$(my_zipped_resources_flata): PRIVATE_SOURCE_RES_ZIPS := $(my_generated_res_zips)
+$(my_zipped_resources_flata) : $(my_generated_res_deps) $(AAPT2) $(EXTRACT_SRCJARS)
+	@echo "AAPT2 compile $@ <- $(PRIVATE_SOURCE_RES_ZIPS)"
+	$(call aapt2-compile-resource-zips)
+
+my_resources_flata += $(my_zipped_resources_flata)
 endif
 
 # Always set --pseudo-localize, it will be stripped out later for release
 # builds that don't want it.
-$(my_res_resources_flat) $(my_overlay_resources_flat) $(my_generated_resources_flata): \
+$(my_res_resources_flat) $(my_overlay_resources_flat) $(my_resources_flata): \
   PRIVATE_AAPT2_CFLAGS := --pseudo-localize
 
 my_static_library_resources := $(foreach l, $(call reverse-list,$(LOCAL_STATIC_ANDROID_LIBRARIES)),\
@@ -67,7 +79,7 @@
 endif
 
 $(my_res_package): PRIVATE_RES_FLAT := $(my_res_resources_flat)
-$(my_res_package): PRIVATE_OVERLAY_FLAT := $(my_static_library_resources) $(my_generated_resources_flata) $(my_overlay_resources_flat)
+$(my_res_package): PRIVATE_OVERLAY_FLAT := $(my_static_library_resources) $(my_resources_flata) $(my_overlay_resources_flat)
 $(my_res_package): PRIVATE_SHARED_ANDROID_LIBRARIES := $(my_shared_library_resources)
 $(my_res_package): PRIVATE_PROGUARD_OPTIONS_FILE := $(proguard_options_file)
 $(my_res_package): PRIVATE_ASSET_DIRS := $(my_asset_dirs)
@@ -95,7 +107,7 @@
 $(my_res_package): $(full_android_manifest) $(my_static_library_resources) $(my_shared_library_resources)
 $(my_res_package): $(my_full_asset_paths)
 $(my_res_package): $(my_res_resources_flat) $(my_overlay_resources_flat) \
-  $(my_generated_resources_flata) $(my_static_library_resources) \
+  $(my_resources_flata) $(my_static_library_resources) \
   $(AAPT2)
 	@echo "AAPT2 link $@"
 	$(call aapt2-link)
@@ -118,3 +130,4 @@
 my_apk_split_configs :=
 my_generated_res_dirs :=
 my_generated_res_dirs_deps :=
+my_generated_res_zips :=
diff --git a/core/aapt_flags.mk b/core/aapt_flags.mk
new file mode 100644
index 0000000..4e3493a
--- /dev/null
+++ b/core/aapt_flags.mk
@@ -0,0 +1,20 @@
+## AAPT Flags
+# aapt doesn't accept multiple --extra-packages flags.
+# We have to collapse them into a single --extra-packages flag here.
+LOCAL_AAPT_FLAGS := $(strip $(LOCAL_AAPT_FLAGS))
+ifdef LOCAL_AAPT_FLAGS
+  ifeq ($(filter 0 1,$(words $(filter --extra-packages,$(LOCAL_AAPT_FLAGS)))),)
+    aapt_flags := $(subst --extra-packages$(space),--extra-packages@,$(LOCAL_AAPT_FLAGS))
+    aapt_flags_extra_packages := $(patsubst --extra-packages@%,%,$(filter --extra-packages@%,$(aapt_flags)))
+    aapt_flags_extra_packages := $(sort $(subst :,$(space),$(aapt_flags_extra_packages)))
+    LOCAL_AAPT_FLAGS := $(filter-out --extra-packages@%,$(aapt_flags)) \
+        --extra-packages $(subst $(space),:,$(aapt_flags_extra_packages))
+    aapt_flags_extra_packages :=
+    aapt_flags :=
+  endif
+endif
+
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_AAPT_FLAGS := $(LOCAL_AAPT_FLAGS)
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_TARGET_AAPT_CHARACTERISTICS := $(TARGET_AAPT_CHARACTERISTICS)
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_MANIFEST_PACKAGE_NAME := $(LOCAL_MANIFEST_PACKAGE_NAME)
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_MANIFEST_INSTRUMENTATION_FOR := $(LOCAL_MANIFEST_INSTRUMENTATION_FOR)
diff --git a/core/clear_vars.mk b/core/clear_vars.mk
index 8488858..d1ba354 100644
--- a/core/clear_vars.mk
+++ b/core/clear_vars.mk
@@ -7,6 +7,7 @@
 LOCAL_AAPT2_ONLY:=
 LOCAL_AAPT_FLAGS:=
 LOCAL_AAPT_INCLUDE_ALL_RESOURCES:=
+LOCAL_AAPT_NAMESPACES:=
 LOCAL_ADDITIONAL_CERTIFICATES:=
 LOCAL_ADDITIONAL_DEPENDENCIES:=
 LOCAL_ADDITIONAL_HTML_DIR:=
@@ -125,7 +126,6 @@
 LOCAL_JAR_PROCESSOR:=
 LOCAL_JAR_PROCESSOR_ARGS:=
 LOCAL_JAVACFLAGS:=
-LOCAL_JAVAC_SHARD_SIZE:=
 LOCAL_JAVA_LANGUAGE_VERSION:=
 LOCAL_JAVA_LAYERS_FILE:=
 LOCAL_JAVA_LIBRARIES:=
diff --git a/core/definitions.mk b/core/definitions.mk
index b0b92de..bd2afac 100644
--- a/core/definitions.mk
+++ b/core/definitions.mk
@@ -2079,6 +2079,15 @@
   $(PRIVATE_AAPT2_CFLAGS) --legacy
 endef
 
+# TODO(b/74574557): use aapt2 compile --zip if it gets implemented
+define aapt2-compile-resource-zips
+@mkdir -p $(dir $@)
+rm -rf $@.contents
+mkdir -p $@.contents
+$(EXTRACT_SRCJARS) $@.contents $@.list $(PRIVATE_SOURCE_RES_ZIPS)
+$(hide) $(AAPT2) compile -o $@ --dir $@.tmp $(PRIVATE_AAPT2_CFLAGS) --legacy
+endef
+
 # Set up rule to compile one resource file with aapt2.
 # Must be called with $(eval).
 # $(1): the source file
@@ -2222,26 +2231,18 @@
 $(hide) tr ' ' '\n' < $@.tmp | $(NORMALIZE_PATH) | sort -u > $@
 endef
 
-# $(1): sharding number.
-# $(2): Java source files paths.
-define save-sharded-java-source-list
-$(java_source_list_file).shard.$(1): $(2) $$(NORMALIZE_PATH)
-	@echo "shard java source list: $$@"
-	rm -f $$@
-	$$(call dump-words-to-file,$(2),$$@.tmp)
-	$(hide) tr ' ' '\n' < $$@.tmp | $$(NORMALIZE_PATH) | sort -u > $$@
-endef
-
 # Common definition to invoke javac on the host and target.
 #
 # $(1): javac
 # $(2): classpath_libs
 define compile-java
 $(hide) rm -f $@
-$(hide) rm -rf $(PRIVATE_CLASS_INTERMEDIATES_DIR) $(PRIVATE_ANNO_INTERMEDIATES_DIR)
+$(hide) rm -rf $(PRIVATE_CLASS_INTERMEDIATES_DIR) $(PRIVATE_ANNO_INTERMEDIATES_DIR) $(if $(PRIVATE_SRCJARS),$(PRIVATE_SRCJAR_INTERMEDIATES_DIR))
 $(hide) mkdir -p $(dir $@)
-$(hide) mkdir -p $(PRIVATE_CLASS_INTERMEDIATES_DIR) $(PRIVATE_ANNO_INTERMEDIATES_DIR)
-$(hide) if [ -s $(PRIVATE_JAVA_SOURCE_LIST) ] ; then \
+$(hide) mkdir -p $(PRIVATE_CLASS_INTERMEDIATES_DIR) $(PRIVATE_ANNO_INTERMEDIATES_DIR) $(if $(PRIVATE_SRCJARS),$(PRIVATE_SRCJAR_INTERMEDIATES_DIR))
+$(if $(PRIVATE_SRCJARS),\
+    $(EXTRACT_SRCJARS) $(PRIVATE_SRCJAR_INTERMEDIATES_DIR) $(PRIVATE_SRCJAR_LIST_FILE) $(PRIVATE_SRCJARS))
+$(hide) if [ -s $(PRIVATE_JAVA_SOURCE_LIST) $(if $(PRIVATE_SRCJARS),-o -s $(PRIVATE_SRCJAR_LIST_FILE) )] ; then \
     $(SOONG_JAVAC_WRAPPER) $(JAVAC_WRAPPER) $(1) -encoding UTF-8 \
     $(if $(findstring true,$(PRIVATE_WARNINGS_ENABLE)),$(xlint_unchecked),) \
     $(if $(PRIVATE_USE_SYSTEM_MODULES), \
@@ -2260,6 +2261,7 @@
     -d $(PRIVATE_CLASS_INTERMEDIATES_DIR) -s $(PRIVATE_ANNO_INTERMEDIATES_DIR) \
     $(PRIVATE_JAVACFLAGS) \
     \@$(PRIVATE_JAVA_SOURCE_LIST) \
+    $(if $(PRIVATE_SRCJARS),\@$(PRIVATE_SRCJAR_LIST_FILE)) \
     || ( rm -rf $(PRIVATE_CLASS_INTERMEDIATES_DIR) ; exit 41 ) \
 fi
 $(if $(PRIVATE_JAVA_LAYERS_FILE), $(hide) build/make/tools/java-layers.py \
@@ -2280,51 +2282,18 @@
 $(if $(PRIVATE_EXTRA_JAR_ARGS),$(call add-java-resources-to,$@))
 endef
 
-# $(1): Javac output jar name.
-# $(2): Java source list file.
-# $(3): Java header libs.
-# $(4): Javac sharding number.
-# $(5): Javac sources deps (the arg may neeed $$ in case of containing '#')
-define create-classes-full-debug.jar
-$(1): PRIVATE_JAVACFLAGS := $$(LOCAL_JAVACFLAGS) $$(annotation_processor_flags)
-$(1): PRIVATE_JAR_EXCLUDE_FILES := $$(LOCAL_JAR_EXCLUDE_FILES)
-$(1): PRIVATE_JAR_PACKAGES := $$(LOCAL_JAR_PACKAGES)
-$(1): PRIVATE_JAR_EXCLUDE_PACKAGES := $$(LOCAL_JAR_EXCLUDE_PACKAGES)
-$(1): PRIVATE_DONT_DELETE_JAR_META_INF := $$(LOCAL_DONT_DELETE_JAR_META_INF)
-$(1): PRIVATE_JAVA_SOURCE_LIST := $(2)
-$(1): PRIVATE_ALL_JAVA_HEADER_LIBRARIES := $(3)
-$(1): PRIVATE_CLASS_INTERMEDIATES_DIR := $(intermediates.COMMON)/classes$(4)
-$(1): PRIVATE_ANNO_INTERMEDIATES_DIR := $(intermediates.COMMON)/anno$(4)
-$(1): \
-    $(2) \
-    $(3) \
-    $(5) \
-    $$(full_java_bootclasspath_libs) \
-    $$(full_java_system_modules_deps) \
-    $$(layers_file) \
-    $$(annotation_processor_deps) \
-    $$(NORMALIZE_PATH) \
-    $$(JAR_ARGS) \
-    | $$(SOONG_JAVAC_WRAPPER)
-	@echo "Target Java: $$@ ($$(PRIVATE_CLASS_INTERMEDIATES_DIR))"
-	$$(call compile-java,$$(TARGET_JAVAC),$$(PRIVATE_ALL_JAVA_HEADER_LIBRARIES))
-endef
-
 define transform-java-to-header.jar
 @echo "$($(PRIVATE_PREFIX)DISPLAY) Turbine: $(PRIVATE_MODULE)"
 @mkdir -p $(dir $@)
 @rm -rf $(dir $@)/classes-turbine
 @mkdir $(dir $@)/classes-turbine
-$(hide) if [ -s $(PRIVATE_JAVA_SOURCE_LIST) ] ; then \
+$(hide) if [ -s $(PRIVATE_JAVA_SOURCE_LIST) -o -n "$(PRIVATE_SRCJARS)" ] ; then \
     $(JAVA) -jar $(TURBINE) \
     --output $@.premerged --temp_dir $(dir $@)/classes-turbine \
-    --sources \@$(PRIVATE_JAVA_SOURCE_LIST) \
-    --javacopts $(PRIVATE_JAVACFLAGS) $(COMMON_JDK_FLAGS) \
-    $(addprefix --bootclasspath ,$(strip \
-         $(call normalize-path-list,$(PRIVATE_BOOTCLASSPATH)) \
-         $(PRIVATE_EMPTY_BOOTCLASSPATH))) \
-    $(addprefix --classpath ,$(strip \
-        $(call normalize-path-list,$(PRIVATE_ALL_JAVA_HEADER_LIBRARIES)))) \
+    --sources \@$(PRIVATE_JAVA_SOURCE_LIST) --source_jars $(PRIVATE_SRCJARS) \
+    --javacopts $(PRIVATE_JAVACFLAGS) $(COMMON_JDK_FLAGS) -- \
+    $(addprefix --bootclasspath ,$(strip $(PRIVATE_BOOTCLASSPATH))) \
+    $(addprefix --classpath ,$(strip $(PRIVATE_ALL_JAVA_HEADER_LIBRARIES))) \
     || ( rm -rf $(dir $@)/classes-turbine ; exit 41 ) && \
     $(MERGE_ZIPS) -j --ignore-duplicates -stripDir META-INF $@.tmp $@.premerged $(call reverse-list,$(PRIVATE_STATIC_JAVA_HEADER_LIBRARIES)) ; \
 else \
diff --git a/core/host_dalvik_java_library.mk b/core/host_dalvik_java_library.mk
index 20663d1..fc5b75c 100644
--- a/core/host_dalvik_java_library.mk
+++ b/core/host_dalvik_java_library.mk
@@ -76,6 +76,7 @@
     $(java_sources) \
     $(java_resource_sources) \
     $(proto_java_sources_file_stamp) \
+    $(LOCAL_SRCJARS) \
     $(LOCAL_ADDITIONAL_DEPENDENCIES)
 
 $(java_source_list_file): $(java_sources_deps)
@@ -86,6 +87,9 @@
 $(full_classes_compiled_jar): PRIVATE_JAR_EXCLUDE_FILES :=
 $(full_classes_compiled_jar): PRIVATE_JAR_PACKAGES :=
 $(full_classes_compiled_jar): PRIVATE_JAR_EXCLUDE_PACKAGES :=
+$(full_classes_compiled_jar): PRIVATE_SRCJARS := $(LOCAL_SRCJARS)
+$(full_classes_compiled_jar): PRIVATE_SRCJAR_LIST_FILE := $(intermediates.COMMON)/srcjar-list
+$(full_classes_compiled_jar): PRIVATE_SRCJAR_INTERMEDIATES_DIR := $(intermediates.COMMON)/srcjars
 $(full_classes_compiled_jar): \
     $(java_source_list_file) \
     $(java_sources_deps) \
@@ -95,6 +99,7 @@
     $(annotation_processor_deps) \
     $(NORMALIZE_PATH) \
     $(JAR_ARGS) \
+    $(EXTRACT_SRCJARS) \
     | $(SOONG_JAVAC_WRAPPER)
 	$(transform-host-java-to-dalvik-package)
 
@@ -102,6 +107,7 @@
 
 $(full_classes_turbine_jar): PRIVATE_JAVACFLAGS := $(LOCAL_JAVACFLAGS) $(annotation_processor_flags)
 $(full_classes_turbine_jar): PRIVATE_DONT_DELETE_JAR_META_INF := $(LOCAL_DONT_DELETE_JAR_META_INF)
+$(full_classes_turbine_jar): PRIVATE_SRCJARS := $(LOCAL_SRCJARS)
 $(full_classes_turbine_jar): \
     $(java_source_list_file) \
     $(java_sources_deps) \
diff --git a/core/host_java_library.mk b/core/host_java_library.mk
index 5176f37..47a8b02 100644
--- a/core/host_java_library.mk
+++ b/core/host_java_library.mk
@@ -63,6 +63,7 @@
     $(java_sources) \
     $(java_resource_sources) \
     $(proto_java_sources_file_stamp) \
+    $(LOCAL_SRCJARS) \
     $(LOCAL_ADDITIONAL_DEPENDENCIES)
 
 $(java_source_list_file): $(java_sources_deps)
@@ -73,6 +74,9 @@
 $(full_classes_compiled_jar): PRIVATE_JAR_EXCLUDE_FILES :=
 $(full_classes_compiled_jar): PRIVATE_JAR_PACKAGES :=
 $(full_classes_compiled_jar): PRIVATE_JAR_EXCLUDE_PACKAGES :=
+$(full_classes_compiled_jar): PRIVATE_SRCJARS := $(LOCAL_SRCJARS)
+$(full_classes_compiled_jar): PRIVATE_SRCJAR_LIST_FILE := $(intermediates.COMMON)/srcjar-list
+$(full_classes_compiled_jar): PRIVATE_SRCJAR_INTERMEDIATES_DIR := $(intermediates.COMMON)/srcjars
 $(full_classes_compiled_jar): \
     $(java_source_list_file) \
     $(java_sources_deps) \
@@ -82,6 +86,7 @@
     $(NORMALIZE_PATH) \
     $(ZIPTIME) \
     $(JAR_ARGS) \
+    $(EXTRACT_SRCJARS) \
     | $(SOONG_JAVAC_WRAPPER)
 	$(transform-host-java-to-package)
 	$(remove-timestamps-from-package)
diff --git a/core/java.mk b/core/java.mk
index 097f52c..907825c 100644
--- a/core/java.mk
+++ b/core/java.mk
@@ -108,9 +108,8 @@
 
 ###############################################################
 ## .rs files: RenderScript sources to .java files and .bc files
-## .fs files: Filterscript sources to .java files and .bc files
 ###############################################################
-renderscript_sources := $(filter %.rs %.fs,$(LOCAL_SRC_FILES))
+renderscript_sources := $(filter %.rs,$(LOCAL_SRC_FILES))
 # Because names of the java files from RenderScript are unknown until the
 # .rs file(s) are compiled, we have to depend on a timestamp file.
 RenderScript_file_stamp :=
@@ -171,7 +170,7 @@
 LOCAL_RENDERSCRIPT_INCLUDES := $(LOCAL_RENDERSCRIPT_INCLUDES_OVERRIDE)
 endif
 
-bc_files := $(patsubst %.fs,%.bc, $(patsubst %.rs,%.bc, $(notdir $(renderscript_sources))))
+bc_files := $(patsubst %.rs,%.bc, $(notdir $(renderscript_sources)))
 bc_dep_files := $(addprefix $(renderscript_intermediate.COMMON)/,$(patsubst %.bc,%.d,$(bc_files)))
 
 $(RenderScript_file_stamp): PRIVATE_RS_INCLUDES := $(LOCAL_RENDERSCRIPT_INCLUDES)
@@ -331,34 +330,6 @@
 java_intermediate_sources := $(addprefix $(TARGET_OUT_COMMON_INTERMEDIATES)/, $(filter %.java,$(LOCAL_INTERMEDIATE_SOURCES)))
 all_java_sources := $(java_sources) $(java_intermediate_sources)
 
-enable_sharding :=
-ifneq ($(TURBINE_ENABLED),false)
-ifneq ($(LOCAL_JAVAC_SHARD_SIZE),)
-ifneq ($(LOCAL_JAR_PROCESSOR),)
-$(call pretty-error,Cannot set both LOCAL_JAVAC_SHARD_SIZE and LOCAL_JAR_PROCESSOR!)
-endif # LOCAL_JAR_PROCESSOR is not empty
-enable_sharding := true
-
-num_shards := $(call int_divide,$(words $(java_sources)),$(LOCAL_JAVAC_SHARD_SIZE))
-ifneq ($(words $(java_sources)),$(call int_multiply,$(LOCAL_JAVAC_SHARD_SIZE),$(num_shards)))
-# increment number of shards by 1.
-num_shards := $(call int_plus,$(num_shards),1)
-endif
-
-shard_idx_list := $(call int_range_list,1,$(num_shards))
-sharded_java_source_list_files += $(foreach x,$(shard_idx_list),$(java_source_list_file).shard.$(x))
-sharded_jar_list += $(foreach x,$(shard_idx_list),$(full_classes_compiled_jar).shard.$(x))
-
-# always put dynamically-located .java files (generated by Proto/resource, etc) in a new final shard.
-# increment number of shards by 1.
-num_shards := $(call int_plus,$(num_shards),1)
-sharded_java_source_list_files += $(java_source_list_file).shard.$(num_shards)
-sharded_jar_list += $(full_classes_compiled_jar).shard.$(num_shards)
-LOCAL_INTERMEDIATE_TARGETS += $(sharded_java_source_list_files)
-LOCAL_INTERMEDIATE_TARGETS += $(sharded_jar_list)
-endif # LOCAL_JAVAC_SHARD_SIZE is not empty
-endif # TURBINE_ENABLED != false
-
 include $(BUILD_SYSTEM)/java_common.mk
 
 include $(BUILD_SYSTEM)/sdk_check.mk
@@ -434,56 +405,16 @@
     $(java_resource_sources) \
     $(RenderScript_file_stamp) \
     $(proto_java_sources_file_stamp) \
+    $(LOCAL_SRCJARS) \
     $(LOCAL_ADDITIONAL_DEPENDENCIES)
 
 $(java_source_list_file): $(java_sources_deps)
 	$(write-java-source-list)
 
-ifdef enable_sharding
-$(foreach x,$(shard_idx_list),\
-  $(eval $(call save-sharded-java-source-list,$(x),\
-    $(wordlist $(call int_plus,1,$(call int_multiply,$(LOCAL_JAVAC_SHARD_SIZE),$(call int_subtract,$(x),1))),\
-      $(call int_multiply,$(LOCAL_JAVAC_SHARD_SIZE),$(x)),$(sort $(java_sources))))))
-
-# always put dynamically-located .java files (generated by Proto/resource, etc) in a new final shard.
-$(java_source_list_file).shard.$(num_shards): PRIVATE_JAVA_INTERMEDIATE_SOURCES := $(java_intermediate_sources)
-$(java_source_list_file).shard.$(num_shards): $(java_resource_sources) \
-    $(RenderScript_file_stamp) \
-    $(proto_java_sources_file_stamp) \
-    $(LOCAL_ADDITIONAL_DEPENDENCIES) \
-    $(NORMALIZE_PATH)
-	$(hide) rm -f $@
-	$(call dump-words-to-file,$(PRIVATE_JAVA_INTERMEDIATE_SOURCES),$@.tmp)
-	$(call fetch-additional-java-source,$@.tmp)
-	$(hide) tr ' ' '\n' < $@.tmp | $(NORMALIZE_PATH) | sort -u > $@
-
-# Javac sharding with header libs including its own header jar as one of dependency.
-$(foreach x,$(shard_idx_list),\
-  $(eval $(call create-classes-full-debug.jar,$(full_classes_compiled_jar).shard.$(x),\
-    $(java_source_list_file).shard.$(x),\
-      $(full_java_header_libs) $(full_classes_header_jar),$(x),\
-        $(wordlist $(call int_plus,1,$(call int_multiply,$(LOCAL_JAVAC_SHARD_SIZE),$(call int_subtract,$(x),1))),\
-          $(call int_multiply,$(LOCAL_JAVAC_SHARD_SIZE),$(x)),$(sort $(java_sources))))))
-
-# Javac sharding for last shard with additional Java dependencies.
-$(eval $(call create-classes-full-debug.jar,$(full_classes_compiled_jar).shard.$(num_shards),\
-  $(java_source_list_file).shard.$(num_shards),$(full_java_header_libs) $(full_classes_header_jar),$(strip \
-    $(num_shards)),$$(java_resource_sources) $$(RenderScript_file_stamp) \
-      $$(proto_java_sources_file_stamp) $$(LOCAL_ADDITIONAL_DEPENDENCIES)))
-
-$(full_classes_compiled_jar): PRIVATE_SHARDED_JAR_LIST := $(sharded_jar_list)
-$(full_classes_compiled_jar): $(sharded_jar_list) | $(MERGE_ZIPS)
-	$(MERGE_ZIPS) -j $@ $(PRIVATE_SHARDED_JAR_LIST)
-else
-# we can't use single $ for java_sources_deps since it may contain hash '#' sign.
-$(eval $(call create-classes-full-debug.jar,$(full_classes_compiled_jar),\
-  $(java_source_list_file),$(full_java_header_libs),,$$(java_sources_deps)))
-
-endif # ifdef enable_sharding
-
 ifneq ($(TURBINE_ENABLED),false)
 
 $(full_classes_turbine_jar): PRIVATE_JAVACFLAGS := $(LOCAL_JAVACFLAGS) $(annotation_processor_flags)
+$(full_classes_turbine_jar): PRIVATE_SRCJARS := $(LOCAL_SRCJARS)
 $(full_classes_turbine_jar): PRIVATE_DONT_DELETE_JAR_META_INF := $(LOCAL_DONT_DELETE_JAR_META_INF)
 $(full_classes_turbine_jar): \
     $(java_source_list_file) \
@@ -514,6 +445,31 @@
 
 endif # TURBINE_ENABLED != false
 
+$(full_classes_compiled_jar): PRIVATE_JAVACFLAGS := $(LOCAL_JAVACFLAGS) $(annotation_processor_flags)
+$(full_classes_compiled_jar): PRIVATE_JAR_EXCLUDE_FILES := $(LOCAL_JAR_EXCLUDE_FILES)
+$(full_classes_compiled_jar): PRIVATE_JAR_PACKAGES := $(LOCAL_JAR_PACKAGES)
+$(full_classes_compiled_jar): PRIVATE_JAR_EXCLUDE_PACKAGES := $(LOCAL_JAR_EXCLUDE_PACKAGES)
+$(full_classes_compiled_jar): PRIVATE_DONT_DELETE_JAR_META_INF := $(LOCAL_DONT_DELETE_JAR_META_INF)
+$(full_classes_compiled_jar): PRIVATE_JAVA_SOURCE_LIST := $(java_source_list_file)
+$(full_classes_compiled_jar): PRIVATE_ALL_JAVA_HEADER_LIBRARIES := $(full_java_header_libs)
+$(full_classes_compiled_jar): PRIVATE_SRCJARS := $(LOCAL_SRCJARS)
+$(full_classes_compiled_jar): PRIVATE_SRCJAR_LIST_FILE := $(intermediates.COMMON)/srcjar-list
+$(full_classes_compiled_jar): PRIVATE_SRCJAR_INTERMEDIATES_DIR := $(intermediates.COMMON)/srcjars
+$(full_classes_compiled_jar): \
+    $(java_source_list_file) \
+    $(full_java_header_libs) \
+    $(java_sources_deps) \
+    $(full_java_bootclasspath_libs) \
+    $(full_java_system_modules_deps) \
+    $(layers_file) \
+    $(annotation_processor_deps) \
+    $(NORMALIZE_PATH) \
+    $(JAR_ARGS) \
+    $(EXTRACT_SRCJARS) \
+    | $(SOONG_JAVAC_WRAPPER)
+	@echo "Target Java: $@
+	$(call compile-java,$(TARGET_JAVAC),$(PRIVATE_ALL_JAVA_HEADER_LIBRARIES))
+
 javac-check : $(full_classes_compiled_jar)
 javac-check-$(LOCAL_MODULE) : $(full_classes_compiled_jar)
 
diff --git a/core/java_common.mk b/core/java_common.mk
index b94effa..dea0435 100644
--- a/core/java_common.mk
+++ b/core/java_common.mk
@@ -177,7 +177,7 @@
 #####################################
 ## Warn if there is unrecognized file in LOCAL_SRC_FILES.
 my_unknown_src_files := $(filter-out \
-  %.java %.aidl %.proto %.logtags %.fs %.rs, \
+  %.java %.aidl %.proto %.logtags %.rs, \
   $(LOCAL_SRC_FILES) $(LOCAL_INTERMEDIATE_SOURCES) $(LOCAL_GENERATED_SOURCES))
 ifneq ($(my_unknown_src_files),)
 $(warning $(LOCAL_MODULE_MAKEFILE): $(LOCAL_MODULE): Unused source files: $(my_unknown_src_files))
@@ -188,7 +188,7 @@
 # LOCAL_SOURCE_FILES_ALL_GENERATED is set only if the module does not have static source files,
 # but generated source files in its LOCAL_INTERMEDIATE_SOURCE_DIR.
 # You have to set up the dependency in some other way.
-need_compile_java := $(strip $(all_java_sources)$(all_res_assets)$(java_resource_sources))$(LOCAL_STATIC_JAVA_LIBRARIES)$(filter true,$(LOCAL_SOURCE_FILES_ALL_GENERATED))
+need_compile_java := $(strip $(all_java_sources)$(LOCAL_SRCJARS)$(all_res_assets)$(java_resource_sources))$(LOCAL_STATIC_JAVA_LIBRARIES)$(filter true,$(LOCAL_SOURCE_FILES_ALL_GENERATED))
 ifdef need_compile_java
 
 annotation_processor_flags :=
@@ -411,35 +411,6 @@
 endif
 
 ##########################################################
-ifndef LOCAL_IS_HOST_MODULE
-## AAPT Flags
-# aapt doesn't accept multiple --extra-packages flags.
-# We have to collapse them into a single --extra-packages flag here.
-LOCAL_AAPT_FLAGS := $(strip $(LOCAL_AAPT_FLAGS))
-ifdef LOCAL_AAPT_FLAGS
-ifeq ($(filter 0 1,$(words $(filter --extra-packages,$(LOCAL_AAPT_FLAGS)))),)
-aapt_flags := $(subst --extra-packages$(space),--extra-packages@,$(LOCAL_AAPT_FLAGS))
-aapt_flags_extra_packages := $(patsubst --extra-packages@%,%,$(filter --extra-packages@%,$(aapt_flags)))
-aapt_flags_extra_packages := $(sort $(subst :,$(space),$(aapt_flags_extra_packages)))
-LOCAL_AAPT_FLAGS := $(filter-out --extra-packages@%,$(aapt_flags)) \
-    --extra-packages $(subst $(space),:,$(aapt_flags_extra_packages))
-aapt_flags_extra_packages :=
-aapt_flags :=
-endif
-endif
-
-$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_AAPT_FLAGS := $(LOCAL_AAPT_FLAGS)
-$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_TARGET_AAPT_CHARACTERISTICS := $(TARGET_AAPT_CHARACTERISTICS)
-$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_MANIFEST_PACKAGE_NAME := $(LOCAL_MANIFEST_PACKAGE_NAME)
-$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_MANIFEST_INSTRUMENTATION_FOR := $(LOCAL_MANIFEST_INSTRUMENTATION_FOR)
-
-ifdef aidl_sources
-ALL_MODULES.$(my_register_name).AIDL_FILES := $(aidl_sources)
-endif
-ifdef renderscript_sources
-ALL_MODULES.$(my_register_name).RS_FILES := $(renderscript_sources_fullpath)
-endif
-endif  # !LOCAL_IS_HOST_MODULE
 
 full_java_libs := $(full_shared_java_libs) $(full_static_java_libs) $(LOCAL_CLASSPATH)
 full_java_header_libs := $(full_shared_java_header_libs) $(full_static_java_header_libs)
diff --git a/core/package_internal.mk b/core/package_internal.mk
index 0938c99..858a1bf 100644
--- a/core/package_internal.mk
+++ b/core/package_internal.mk
@@ -274,7 +274,7 @@
 
 ifeq (true,$(LOCAL_EMMA_INSTRUMENT))
 ifeq (true,$(EMMA_INSTRUMENT_STATIC))
-ifneq ($(LOCAL_SRC_FILES)$(LOCAL_STATIC_JAVA_LIBRARIES)$(LOCAL_SOURCE_FILES_ALL_GENERATED),)
+ifneq ($(LOCAL_SRC_FILES)$(LOCAL_SRCJARS)$(LOCAL_STATIC_JAVA_LIBRARIES)$(LOCAL_SOURCE_FILES_ALL_GENERATED),)
 # Only add jacocoagent if the package contains some java code
 LOCAL_STATIC_JAVA_LIBRARIES += jacocoagent
 # Exclude jacoco classes from proguard
@@ -361,12 +361,13 @@
 # Make sure the data-binding process happens before javac and generation of R.java.
 $(R_file_stamp): $(data_binding_stamp)
 $(java_source_list_file): $(data_binding_stamp)
-$(foreach x,$(sharded_java_source_list_files),$(eval $(x): $(data_binding_stamp)))
 $(full_classes_compiled_jar): $(data_binding_stamp)
 endif  # LOCAL_DATA_BINDING
 
 resource_export_package :=
 
+include $(BUILD_SYSTEM)/aapt_flags.mk
+
 ifeq ($(need_compile_res),true)
 
 ###############################
@@ -407,8 +408,13 @@
 endif  # renderscript_target_api is set
 my_asset_dirs := $(LOCAL_ASSET_DIR)
 my_full_asset_paths := $(all_assets)
+
 # Add AAPT2 link specific flags.
-$(my_res_package): PRIVATE_AAPT_FLAGS := $(LOCAL_AAPT_FLAGS) --no-static-lib-packages
+$(my_res_package): PRIVATE_AAPT_FLAGS := $(LOCAL_AAPT_FLAGS)
+ifndef LOCAL_AAPT_NAMESPACES
+  $(my_res_package): PRIVATE_AAPT_FLAGS += --no-static-lib-packages
+endif
+
 include $(BUILD_SYSTEM)/aapt2.mk
 else  # LOCAL_USE_AAPT2
 
@@ -460,7 +466,6 @@
 # The R.java file must exist by the time the java source
 # list is generated
 $(java_source_list_file): $(R_file_stamp)
-$(foreach x,$(sharded_java_source_list_files),$(eval $(x): $(R_file_stamp)))
 
 endif  # need_compile_res
 
diff --git a/core/static_java_library.mk b/core/static_java_library.mk
index 77bb498..64e16c2 100644
--- a/core/static_java_library.mk
+++ b/core/static_java_library.mk
@@ -128,10 +128,15 @@
 import_proguard_flag_files :=
 endif
 
+include $(BUILD_SYSTEM)/aapt_flags.mk
+
 # add --non-constant-id to prevent inlining constants.
 # AAR needs text symbol file R.txt.
 ifdef LOCAL_USE_AAPT2
-$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_AAPT_FLAGS := $(LOCAL_AAPT_FLAGS) --static-lib --no-static-lib-packages
+$(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_AAPT_FLAGS := $(LOCAL_AAPT_FLAGS) --static-lib
+ifndef LOCAL_AAPT_NAMESPACES
+  $(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_AAPT_FLAGS += --no-static-lib-packages
+endif
 $(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_PRODUCT_AAPT_CONFIG :=
 $(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_PRODUCT_AAPT_PREF_CONFIG :=
 $(LOCAL_INTERMEDIATE_TARGETS): PRIVATE_TARGET_AAPT_CHARACTERISTICS :=
@@ -182,7 +187,6 @@
 
 $(LOCAL_BUILT_MODULE): $(R_file_stamp)
 $(java_source_list_file): $(R_file_stamp)
-$(foreach x,$(sharded_java_source_list_files),$(eval $(x): $(R_file_stamp)))
 $(full_classes_compiled_jar): $(R_file_stamp)
 $(full_classes_turbine_jar): $(R_file_stamp)
 
diff --git a/target/board/generic/BoardConfig.mk b/target/board/generic/BoardConfig.mk
index 67d019f..70c78a8 100644
--- a/target/board/generic/BoardConfig.mk
+++ b/target/board/generic/BoardConfig.mk
@@ -68,3 +68,5 @@
 # Enable A/B update
 TARGET_NO_RECOVERY := true
 BOARD_BUILD_SYSTEM_ROOT_IMAGE := true
+
+BOARD_VNDK_VERSION := current
\ No newline at end of file
diff --git a/target/board/generic_arm64/BoardConfig.mk b/target/board/generic_arm64/BoardConfig.mk
index e066e3a..be8ea39 100644
--- a/target/board/generic_arm64/BoardConfig.mk
+++ b/target/board/generic_arm64/BoardConfig.mk
@@ -99,3 +99,5 @@
 # Enable A/B update
 TARGET_NO_RECOVERY := true
 BOARD_BUILD_SYSTEM_ROOT_IMAGE := true
+
+BOARD_VNDK_VERSION := current
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index 3a0a788..7ce1ec8 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -159,6 +159,7 @@
 import os.path
 import shlex
 import shutil
+import struct
 import subprocess
 import sys
 import tempfile
@@ -955,8 +956,15 @@
   return metadata
 
 
-class StreamingPropertyFiles(object):
-  """Computes the ota-streaming-property-files string for streaming A/B OTA.
+class PropertyFiles(object):
+  """A class that computes the property-files string for an OTA package.
+
+  A property-files string is a comma-separated string that contains the
+  offset/size info for an OTA package. The entries, which must be ZIP_STORED,
+  can be fetched directly with the package URL along with the offset/size info.
+  These strings can be used for streaming A/B OTAs, or allowing an updater to
+  download package metadata entry directly, without paying the cost of
+  downloading entire package.
 
   Computing the final property-files string requires two passes. Because doing
   the whole package signing (with signapk.jar) will possibly reorder the ZIP
@@ -966,7 +974,7 @@
   This class provides functions to be called for each pass. The general flow is
   as follows.
 
-    property_files = StreamingPropertyFiles()
+    property_files = PropertyFiles()
     # The first pass, which writes placeholders before doing initial signing.
     property_files.Compute()
     SignOutput()
@@ -981,17 +989,9 @@
   """
 
   def __init__(self):
-    self.required = (
-        # payload.bin and payload_properties.txt must exist.
-        'payload.bin',
-        'payload_properties.txt',
-    )
-    self.optional = (
-        # care_map.txt is available only if dm-verity is enabled.
-        'care_map.txt',
-        # compatibility.zip is available only if target supports Treble.
-        'compatibility.zip',
-    )
+    self.name = None
+    self.required = ()
+    self.optional = ()
 
   def Compute(self, input_zip):
     """Computes and returns a property-files string with placeholders.
@@ -1064,6 +1064,7 @@
       return '%s:%d:%d' % (os.path.basename(name), offset, size)
 
     tokens = []
+    tokens.extend(self._GetPrecomputed(zip_file))
     for entry in self.required:
       tokens.append(ComputeEntryOffsetSize(entry))
     for entry in self.optional:
@@ -1082,8 +1083,127 @@
 
     return ','.join(tokens)
 
+  def _GetPrecomputed(self, input_zip):
+    """Computes the additional tokens to be included into the property-files.
 
-def FinalizeMetadata(metadata, input_file, output_file):
+    This applies to tokens without actual ZIP entries, such as
+    payload_metadadata.bin. We want to expose the offset/size to updaters, so
+    that they can download the payload metadata directly with the info.
+
+    Args:
+      input_zip: The input zip file.
+
+    Returns:
+      A list of strings (tokens) to be added to the property-files string.
+    """
+    # pylint: disable=no-self-use
+    # pylint: disable=unused-argument
+    return []
+
+
+class StreamingPropertyFiles(PropertyFiles):
+  """A subclass for computing the property-files for streaming A/B OTAs."""
+
+  def __init__(self):
+    super(StreamingPropertyFiles, self).__init__()
+    self.name = 'ota-streaming-property-files'
+    self.required = (
+        # payload.bin and payload_properties.txt must exist.
+        'payload.bin',
+        'payload_properties.txt',
+    )
+    self.optional = (
+        # care_map.txt is available only if dm-verity is enabled.
+        'care_map.txt',
+        # compatibility.zip is available only if target supports Treble.
+        'compatibility.zip',
+    )
+
+
+class AbOtaPropertyFiles(StreamingPropertyFiles):
+  """The property-files for A/B OTA that includes payload_metadata.bin info.
+
+  Since P, we expose one more token (aka property-file), in addition to the ones
+  for streaming A/B OTA, for a virtual entry of 'payload_metadata.bin'.
+  'payload_metadata.bin' is the header part of a payload ('payload.bin'), which
+  doesn't exist as a separate ZIP entry, but can be used to verify if the
+  payload can be applied on the given device.
+
+  For backward compatibility, we keep both of the 'ota-streaming-property-files'
+  and the newly added 'ota-property-files' in P. The new token will only be
+  available in 'ota-property-files'.
+  """
+
+  def __init__(self):
+    super(AbOtaPropertyFiles, self).__init__()
+    self.name = 'ota-property-files'
+
+  def _GetPrecomputed(self, input_zip):
+    offset, size = self._GetPayloadMetadataOffsetAndSize(input_zip)
+    return ['payload_metadata.bin:{}:{}'.format(offset, size)]
+
+  @staticmethod
+  def _GetPayloadMetadataOffsetAndSize(input_zip):
+    """Computes the offset and size of the payload metadata for a given package.
+
+    (From system/update_engine/update_metadata.proto)
+    A delta update file contains all the deltas needed to update a system from
+    one specific version to another specific version. The update format is
+    represented by this struct pseudocode:
+
+    struct delta_update_file {
+      char magic[4] = "CrAU";
+      uint64 file_format_version;
+      uint64 manifest_size;  // Size of protobuf DeltaArchiveManifest
+
+      // Only present if format_version > 1:
+      uint32 metadata_signature_size;
+
+      // The Bzip2 compressed DeltaArchiveManifest
+      char manifest[metadata_signature_size];
+
+      // The signature of the metadata (from the beginning of the payload up to
+      // this location, not including the signature itself). This is a
+      // serialized Signatures message.
+      char medatada_signature_message[metadata_signature_size];
+
+      // Data blobs for files, no specific format. The specific offset
+      // and length of each data blob is recorded in the DeltaArchiveManifest.
+      struct {
+        char data[];
+      } blobs[];
+
+      // These two are not signed:
+      uint64 payload_signatures_message_size;
+      char payload_signatures_message[];
+    };
+
+    'payload-metadata.bin' contains all the bytes from the beginning of the
+    payload, till the end of 'medatada_signature_message'.
+    """
+    payload_info = input_zip.getinfo('payload.bin')
+    payload_offset = payload_info.header_offset + len(payload_info.FileHeader())
+    payload_size = payload_info.file_size
+
+    with input_zip.open('payload.bin', 'r') as payload_fp:
+      header_bin = payload_fp.read(24)
+
+    # network byte order (big-endian)
+    header = struct.unpack("!IQQL", header_bin)
+
+    # 'CrAU'
+    magic = header[0]
+    assert magic == 0x43724155, "Invalid magic: {:x}".format(magic)
+
+    manifest_size = header[2]
+    metadata_signature_size = header[3]
+    metadata_total = 24 + manifest_size + metadata_signature_size
+    assert metadata_total < payload_size
+
+    return (payload_offset, metadata_total)
+
+
+def FinalizeMetadata(metadata, input_file, output_file, needed_property_files):
   """Finalizes the metadata and signs an A/B OTA package.
 
   In order to stream an A/B OTA package, we need 'ota-streaming-property-files'
@@ -1101,14 +1221,14 @@
     input_file: The input ZIP filename that doesn't contain the package METADATA
         entry yet.
     output_file: The final output ZIP filename.
+    needed_property_files: The list of PropertyFiles' to be generated.
   """
   output_zip = zipfile.ZipFile(
       input_file, 'a', compression=zipfile.ZIP_DEFLATED)
 
-  property_files = StreamingPropertyFiles()
-
   # Write the current metadata entry with placeholders.
-  metadata['ota-streaming-property-files'] = property_files.Compute(output_zip)
+  for property_files in needed_property_files:
+    metadata[property_files.name] = property_files.Compute(output_zip)
   WriteMetadata(metadata, output_zip)
   common.ZipClose(output_zip)
 
@@ -1122,14 +1242,14 @@
 
   # Open the signed zip. Compute the final metadata that's needed for streaming.
   with zipfile.ZipFile(prelim_signing, 'r') as prelim_signing_zip:
-    expected_length = len(metadata['ota-streaming-property-files'])
-    metadata['ota-streaming-property-files'] = property_files.Finalize(
-        prelim_signing_zip, expected_length)
+    for property_files in needed_property_files:
+      metadata[property_files.name] = property_files.Finalize(
+          prelim_signing_zip, len(metadata[property_files.name]))
 
   # Replace the METADATA entry.
   common.ZipDelete(prelim_signing, METADATA_NAME)
-  output_zip = zipfile.ZipFile(prelim_signing, 'a',
-                               compression=zipfile.ZIP_DEFLATED)
+  output_zip = zipfile.ZipFile(
+      prelim_signing, 'a', compression=zipfile.ZIP_DEFLATED)
   WriteMetadata(metadata, output_zip)
   common.ZipClose(output_zip)
 
@@ -1138,8 +1258,8 @@
 
   # Reopen the final signed zip to double check the streaming metadata.
   with zipfile.ZipFile(output_file, 'r') as output_zip:
-    property_files.Verify(
-        output_zip, metadata['ota-streaming-property-files'].strip())
+    for property_files in needed_property_files:
+      property_files.Verify(output_zip, metadata[property_files.name].strip())
 
 
 def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
@@ -1555,7 +1675,15 @@
   # FinalizeMetadata().
   common.ZipClose(output_zip)
 
-  FinalizeMetadata(metadata, staging_file, output_file)
+  # AbOtaPropertyFiles intends to replace StreamingPropertyFiles, as it covers
+  # all the info of the latter. However, system updaters and OTA servers need to
+  # take time to switch to the new flag. We keep both of the flags for
+  # P-timeframe, and will remove StreamingPropertyFiles in later release.
+  needed_property_files = (
+      AbOtaPropertyFiles(),
+      StreamingPropertyFiles(),
+  )
+  FinalizeMetadata(metadata, staging_file, output_file, needed_property_files)
 
 
 def main(argv):
diff --git a/tools/releasetools/test_ota_from_target_files.py b/tools/releasetools/test_ota_from_target_files.py
index c8e87bf..4c0b890 100644
--- a/tools/releasetools/test_ota_from_target_files.py
+++ b/tools/releasetools/test_ota_from_target_files.py
@@ -17,17 +17,18 @@
 import copy
 import os
 import os.path
+import subprocess
 import unittest
 import zipfile
 
 import common
 import test_utils
 from ota_from_target_files import (
-    _LoadOemDicts, BuildInfo, GetPackageMetadata,
+    _LoadOemDicts, AbOtaPropertyFiles, BuildInfo, GetPackageMetadata,
     GetTargetFilesZipForSecondaryImages,
     GetTargetFilesZipWithoutPostinstallConfig,
-    Payload, PayloadSigner, POSTINSTALL_CONFIG, StreamingPropertyFiles,
-    WriteFingerprintAssertion)
+    Payload, PayloadSigner, POSTINSTALL_CONFIG, PropertyFiles,
+    StreamingPropertyFiles, WriteFingerprintAssertion)
 
 
 def construct_target_files(secondary=False):
@@ -590,7 +591,23 @@
       self.assertNotIn(POSTINSTALL_CONFIG, verify_zip.namelist())
 
 
-class StreamingPropertyFilesTest(unittest.TestCase):
+class TestPropertyFiles(PropertyFiles):
+  """A class that extends PropertyFiles for testing purpose."""
+
+  def __init__(self):
+    super(TestPropertyFiles, self).__init__()
+    self.name = 'ota-test-property-files'
+    self.required = (
+        'required-entry1',
+        'required-entry2',
+    )
+    self.optional = (
+        'optional-entry1',
+        'optional-entry2',
+    )
+
+
+class PropertyFilesTest(unittest.TestCase):
 
   def tearDown(self):
     common.Cleanup()
@@ -607,7 +624,7 @@
     return zip_file
 
   @staticmethod
-  def _parse_streaming_metadata_string(data):
+  def _parse_property_files_string(data):
     result = {}
     for token in data.split(','):
       name, info = token.split(':', 1)
@@ -627,47 +644,57 @@
 
   def test_Compute(self):
     entries = (
-        'payload.bin',
-        'payload_properties.txt',
+        'required-entry1',
+        'required-entry2',
     )
     zip_file = self._construct_zip_package(entries)
-    property_files = StreamingPropertyFiles()
+    property_files = TestPropertyFiles()
     with zipfile.ZipFile(zip_file, 'r') as zip_fp:
-      streaming_metadata = property_files.Compute(zip_fp)
+      property_files_string = property_files.Compute(zip_fp)
 
-    tokens = self._parse_streaming_metadata_string(streaming_metadata)
+    tokens = self._parse_property_files_string(property_files_string)
     self.assertEqual(3, len(tokens))
     self._verify_entries(zip_file, tokens, entries)
 
-  def test_Compute_withCareMapTxtAndCompatibilityZip(self):
+  def test_Compute_withOptionalEntries(self):
     entries = (
-        'payload.bin',
-        'payload_properties.txt',
-        'care_map.txt',
-        'compatibility.zip',
+        'required-entry1',
+        'required-entry2',
+        'optional-entry1',
+        'optional-entry2',
     )
     zip_file = self._construct_zip_package(entries)
-    property_files = StreamingPropertyFiles()
+    property_files = TestPropertyFiles()
     with zipfile.ZipFile(zip_file, 'r') as zip_fp:
-      streaming_metadata = property_files.Compute(zip_fp)
+      property_files_string = property_files.Compute(zip_fp)
 
-    tokens = self._parse_streaming_metadata_string(streaming_metadata)
+    tokens = self._parse_property_files_string(property_files_string)
     self.assertEqual(5, len(tokens))
     self._verify_entries(zip_file, tokens, entries)
 
+  def test_Compute_missingRequiredEntry(self):
+    entries = (
+        'required-entry2',
+    )
+    zip_file = self._construct_zip_package(entries)
+    property_files = TestPropertyFiles()
+    with zipfile.ZipFile(zip_file, 'r') as zip_fp:
+      self.assertRaises(KeyError, property_files.Compute, zip_fp)
+
   def test_Finalize(self):
     entries = [
-        'payload.bin',
-        'payload_properties.txt',
+        'required-entry1',
+        'required-entry2',
         'META-INF/com/android/metadata',
     ]
     zip_file = self._construct_zip_package(entries)
-    property_files = StreamingPropertyFiles()
+    property_files = TestPropertyFiles()
     with zipfile.ZipFile(zip_file, 'r') as zip_fp:
+      # pylint: disable=protected-access
       raw_metadata = property_files._GetPropertyFilesString(
           zip_fp, reserve_space=False)
       streaming_metadata = property_files.Finalize(zip_fp, len(raw_metadata))
-    tokens = self._parse_streaming_metadata_string(streaming_metadata)
+    tokens = self._parse_property_files_string(streaming_metadata)
 
     self.assertEqual(3, len(tokens))
     # 'META-INF/com/android/metadata' will be key'd as 'metadata' in the
@@ -677,15 +704,17 @@
 
   def test_Finalize_assertReservedLength(self):
     entries = (
-        'payload.bin',
-        'payload_properties.txt',
-        'care_map.txt',
+        'required-entry1',
+        'required-entry2',
+        'optional-entry1',
+        'optional-entry2',
         'META-INF/com/android/metadata',
     )
     zip_file = self._construct_zip_package(entries)
-    property_files = StreamingPropertyFiles()
+    property_files = TestPropertyFiles()
     with zipfile.ZipFile(zip_file, 'r') as zip_fp:
       # First get the raw metadata string (i.e. without padding space).
+      # pylint: disable=protected-access
       raw_metadata = property_files._GetPropertyFilesString(
           zip_fp, reserve_space=False)
       raw_length = len(raw_metadata)
@@ -710,15 +739,17 @@
 
   def test_Verify(self):
     entries = (
-        'payload.bin',
-        'payload_properties.txt',
-        'care_map.txt',
+        'required-entry1',
+        'required-entry2',
+        'optional-entry1',
+        'optional-entry2',
         'META-INF/com/android/metadata',
     )
     zip_file = self._construct_zip_package(entries)
-    property_files = StreamingPropertyFiles()
+    property_files = TestPropertyFiles()
     with zipfile.ZipFile(zip_file, 'r') as zip_fp:
       # First get the raw metadata string (i.e. without padding space).
+      # pylint: disable=protected-access
       raw_metadata = property_files._GetPropertyFilesString(
           zip_fp, reserve_space=False)
 
@@ -730,6 +761,235 @@
           AssertionError, property_files.Verify, zip_fp, raw_metadata + 'x')
 
 
+class StreamingPropertyFilesTest(PropertyFilesTest):
+  """Additional sanity checks specialized for StreamingPropertyFiles."""
+
+  def test_init(self):
+    property_files = StreamingPropertyFiles()
+    self.assertEqual('ota-streaming-property-files', property_files.name)
+    self.assertEqual(
+        (
+            'payload.bin',
+            'payload_properties.txt',
+        ),
+        property_files.required)
+    self.assertEqual(
+        (
+            'care_map.txt',
+            'compatibility.zip',
+        ),
+        property_files.optional)
+
+  def test_Compute(self):
+    entries = (
+        'payload.bin',
+        'payload_properties.txt',
+        'care_map.txt',
+        'compatibility.zip',
+    )
+    zip_file = self._construct_zip_package(entries)
+    property_files = StreamingPropertyFiles()
+    with zipfile.ZipFile(zip_file, 'r') as zip_fp:
+      property_files_string = property_files.Compute(zip_fp)
+
+    tokens = self._parse_property_files_string(property_files_string)
+    self.assertEqual(5, len(tokens))
+    self._verify_entries(zip_file, tokens, entries)
+
+  def test_Finalize(self):
+    entries = [
+        'payload.bin',
+        'payload_properties.txt',
+        'care_map.txt',
+        'compatibility.zip',
+        'META-INF/com/android/metadata',
+    ]
+    zip_file = self._construct_zip_package(entries)
+    property_files = StreamingPropertyFiles()
+    with zipfile.ZipFile(zip_file, 'r') as zip_fp:
+      # pylint: disable=protected-access
+      raw_metadata = property_files._GetPropertyFilesString(
+          zip_fp, reserve_space=False)
+      streaming_metadata = property_files.Finalize(zip_fp, len(raw_metadata))
+    tokens = self._parse_property_files_string(streaming_metadata)
+
+    self.assertEqual(5, len(tokens))
+    # 'META-INF/com/android/metadata' will be key'd as 'metadata' in the
+    # streaming metadata.
+    entries[4] = 'metadata'
+    self._verify_entries(zip_file, tokens, entries)
+
+  def test_Verify(self):
+    entries = (
+        'payload.bin',
+        'payload_properties.txt',
+        'care_map.txt',
+        'compatibility.zip',
+        'META-INF/com/android/metadata',
+    )
+    zip_file = self._construct_zip_package(entries)
+    property_files = StreamingPropertyFiles()
+    with zipfile.ZipFile(zip_file, 'r') as zip_fp:
+      # First get the raw metadata string (i.e. without padding space).
+      # pylint: disable=protected-access
+      raw_metadata = property_files._GetPropertyFilesString(
+          zip_fp, reserve_space=False)
+
+      # Should pass the test if verification passes.
+      property_files.Verify(zip_fp, raw_metadata)
+
+      # Or raise on verification failure.
+      self.assertRaises(
+          AssertionError, property_files.Verify, zip_fp, raw_metadata + 'x')
+
+
+class AbOtaPropertyFilesTest(PropertyFilesTest):
+  """Additional sanity checks specialized for AbOtaPropertyFiles."""
+
+  # The size for payload and metadata signature size.
+  SIGNATURE_SIZE = 256
+
+  def setUp(self):
+    self.testdata_dir = test_utils.get_testdata_dir()
+    self.assertTrue(os.path.exists(self.testdata_dir))
+
+    common.OPTIONS.wipe_user_data = False
+    common.OPTIONS.payload_signer = None
+    common.OPTIONS.payload_signer_args = None
+    common.OPTIONS.package_key = os.path.join(self.testdata_dir, 'testkey')
+    common.OPTIONS.key_passwords = {
+        common.OPTIONS.package_key : None,
+    }
+
+  def test_init(self):
+    property_files = AbOtaPropertyFiles()
+    self.assertEqual('ota-property-files', property_files.name)
+    self.assertEqual(
+        (
+            'payload.bin',
+            'payload_properties.txt',
+        ),
+        property_files.required)
+    self.assertEqual(
+        (
+            'care_map.txt',
+            'compatibility.zip',
+        ),
+        property_files.optional)
+
+  def test_GetPayloadMetadataOffsetAndSize(self):
+    target_file = construct_target_files()
+    payload = Payload()
+    payload.Generate(target_file)
+
+    payload_signer = PayloadSigner()
+    payload.Sign(payload_signer)
+
+    output_file = common.MakeTempFile(suffix='.zip')
+    with zipfile.ZipFile(output_file, 'w') as output_zip:
+      payload.WriteToZip(output_zip)
+
+    # Find out the payload metadata offset and size.
+    property_files = AbOtaPropertyFiles()
+    with zipfile.ZipFile(output_file) as input_zip:
+      # pylint: disable=protected-access
+      payload_offset, metadata_total = (
+          property_files._GetPayloadMetadataOffsetAndSize(input_zip))
+
+    # Read in the metadata signature directly.
+    with open(output_file, 'rb') as verify_fp:
+      verify_fp.seek(payload_offset + metadata_total - self.SIGNATURE_SIZE)
+      metadata_signature = verify_fp.read(self.SIGNATURE_SIZE)
+
+    # Now we extract the metadata hash via brillo_update_payload script, which
+    # will serve as the oracle result.
+    payload_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
+    metadata_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin")
+    cmd = ['brillo_update_payload', 'hash',
+           '--unsigned_payload', payload.payload_file,
+           '--signature_size', str(self.SIGNATURE_SIZE),
+           '--metadata_hash_file', metadata_sig_file,
+           '--payload_hash_file', payload_sig_file]
+    proc = common.Run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+    stdoutdata, _ = proc.communicate()
+    self.assertEqual(
+        0, proc.returncode,
+        'Failed to run brillo_update_payload: {}'.format(stdoutdata))
+
+    signed_metadata_sig_file = payload_signer.Sign(metadata_sig_file)
+
+    # Finally we can compare the two signatures.
+    with open(signed_metadata_sig_file, 'rb') as verify_fp:
+      self.assertEqual(verify_fp.read(), metadata_signature)
+
+  @staticmethod
+  def _construct_zip_package_withValidPayload(with_metadata=False):
+    # Cannot use _construct_zip_package() since we need a "valid" payload.bin.
+    target_file = construct_target_files()
+    payload = Payload()
+    payload.Generate(target_file)
+
+    payload_signer = PayloadSigner()
+    payload.Sign(payload_signer)
+
+    zip_file = common.MakeTempFile(suffix='.zip')
+    with zipfile.ZipFile(zip_file, 'w') as zip_fp:
+      # 'payload.bin',
+      payload.WriteToZip(zip_fp)
+
+      # Other entries.
+      entries = ['care_map.txt', 'compatibility.zip']
+
+      # Put META-INF/com/android/metadata if needed.
+      if with_metadata:
+        entries.append('META-INF/com/android/metadata')
+
+      for entry in entries:
+        zip_fp.writestr(
+            entry, entry.replace('.', '-').upper(), zipfile.ZIP_STORED)
+
+    return zip_file
+
+  def test_Compute(self):
+    zip_file = self._construct_zip_package_withValidPayload()
+    property_files = AbOtaPropertyFiles()
+    with zipfile.ZipFile(zip_file, 'r') as zip_fp:
+      property_files_string = property_files.Compute(zip_fp)
+
+    tokens = self._parse_property_files_string(property_files_string)
+    # "6" indcludes the four entries above, one metadata entry, and one entry
+    # for payload-metadata.bin.
+    self.assertEqual(6, len(tokens))
+    self._verify_entries(
+        zip_file, tokens, ('care_map.txt', 'compatibility.zip'))
+
+  def test_Finalize(self):
+    zip_file = self._construct_zip_package_withValidPayload(with_metadata=True)
+    property_files = AbOtaPropertyFiles()
+    with zipfile.ZipFile(zip_file, 'r') as zip_fp:
+      # pylint: disable=protected-access
+      raw_metadata = property_files._GetPropertyFilesString(
+          zip_fp, reserve_space=False)
+      property_files_string = property_files.Finalize(zip_fp, len(raw_metadata))
+
+    tokens = self._parse_property_files_string(property_files_string)
+    # "6" indcludes the four entries above, one metadata entry, and one entry
+    # for payload-metadata.bin.
+    self.assertEqual(6, len(tokens))
+    self._verify_entries(
+        zip_file, tokens, ('care_map.txt', 'compatibility.zip'))
+
+  def test_Verify(self):
+    zip_file = self._construct_zip_package_withValidPayload(with_metadata=True)
+    property_files = AbOtaPropertyFiles()
+    with zipfile.ZipFile(zip_file, 'r') as zip_fp:
+      # pylint: disable=protected-access
+      raw_metadata = property_files._GetPropertyFilesString(
+          zip_fp, reserve_space=False)
+
+      property_files.Verify(zip_fp, raw_metadata)
+
+
 class PayloadSignerTest(unittest.TestCase):
 
   SIGFILE = 'sigfile.bin'