Merge "Add _asan suffix to ro.build.flavor for ASAN builds."
diff --git a/core/Makefile b/core/Makefile
index c26815f..2f7ebdf 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -1491,6 +1491,7 @@
 	@echo "Package target files: $@"
 	$(hide) rm -rf $@ $(zip_root)
 	$(hide) mkdir -p $(dir $@) $(zip_root)
+ifneq ($(INSTALLED_RECOVERYIMAGE_TARGET),)
 	@# Components of the recovery image
 	$(hide) mkdir -p $(zip_root)/RECOVERY
 	$(hide) $(call package_files-copy-root, \
@@ -1511,6 +1512,7 @@
 ifdef BOARD_KERNEL_PAGESIZE
 	$(hide) echo "$(BOARD_KERNEL_PAGESIZE)" > $(zip_root)/RECOVERY/pagesize
 endif
+endif
 	@# Components of the boot image
 	$(hide) mkdir -p $(zip_root)/BOOT
 ifeq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
@@ -1573,6 +1575,9 @@
 ifdef BOARD_BOOTIMAGE_PARTITION_SIZE
 	$(hide) echo "boot_size=$(BOARD_BOOTIMAGE_PARTITION_SIZE)" >> $(zip_root)/META/misc_info.txt
 endif
+ifeq ($(INSTALLED_RECOVERYIMAGE_TARGET),)
+	$(hide) echo "no_recovery=true" >> $(zip_root)/META/misc_info.txt
+endif
 ifdef BOARD_RECOVERYIMAGE_PARTITION_SIZE
 	$(hide) echo "recovery_size=$(BOARD_RECOVERYIMAGE_PARTITION_SIZE)" >> $(zip_root)/META/misc_info.txt
 endif
@@ -1637,7 +1642,9 @@
 else
 	$(hide) zipinfo -1 $@ | awk 'BEGIN { FS="BOOT/RAMDISK/" } /^BOOT\/RAMDISK\// {print $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config -C -D $(TARGET_OUT) -S $(SELINUX_FC) > $(zip_root)/META/boot_filesystem_config.txt
 endif
+ifneq ($(INSTALLED_RECOVERYIMAGE_TARGET),)
 	$(hide) zipinfo -1 $@ | awk 'BEGIN { FS="RECOVERY/RAMDISK/" } /^RECOVERY\/RAMDISK\// {print $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config -C -D $(TARGET_OUT) -S $(SELINUX_FC) > $(zip_root)/META/recovery_filesystem_config.txt
+endif
 	$(hide) (cd $(zip_root) && zip -q ../$(notdir $@) META/*filesystem_config.txt)
 	$(hide) PATH=$(foreach p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$$PATH MKBOOTIMG=$(MKBOOTIMG) \
 	    ./build/tools/releasetools/add_img_to_target_files -v -p $(HOST_OUT) $@
@@ -1970,6 +1977,8 @@
 -include $(sort $(wildcard device/*/*/build/tasks/*.mk))
 endif
 
+include $(BUILD_SYSTEM)/product-graph.mk
+
 # -----------------------------------------------------------------
 # Create SDK repository packages. Must be done after tasks/* since
 # we need the addon rules defined.
diff --git a/core/config.mk b/core/config.mk
index 680a169..10c66f5 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -113,6 +113,16 @@
 SHOW_COMMANDS:= $(filter showcommands,$(MAKECMDGOALS))
 hide := $(if $(SHOW_COMMANDS),,@)
 
+################################################################
+# Tools needed in product configuration makefiles.
+################################################################
+NORMALIZE_PATH := build/tools/normalize_path.py
+
+# $(1): the paths to be normalized
+define normalize-paths
+$(if $(1),$(shell $(NORMALIZE_PATH) $(1)))
+endef
+
 # ###############################################################
 # Set common values
 # ###############################################################
@@ -550,8 +560,6 @@
 MD5SUM:=md5sum
 endif
 
-NORMALIZE_PATH := build/tools/normalize_path.py
-
 APICHECK_CLASSPATH := $(HOST_JDK_TOOLS_JAR)
 APICHECK_CLASSPATH := $(APICHECK_CLASSPATH):$(HOST_OUT_JAVA_LIBRARIES)/doclava$(COMMON_JAVA_PACKAGE_SUFFIX)
 APICHECK_CLASSPATH := $(APICHECK_CLASSPATH):$(HOST_OUT_JAVA_LIBRARIES)/jsilver$(COMMON_JAVA_PACKAGE_SUFFIX)
diff --git a/core/main.mk b/core/main.mk
index 15b3c27..7901bd8 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -80,7 +80,8 @@
     vendorimage-nodeps \
     ramdisk-nodeps \
     bootimage-nodeps \
-    recoveryimage-nodeps
+    recoveryimage-nodeps \
+    product-graph dump-products
 
 ifneq ($(filter $(dont_bother_goals), $(MAKECMDGOALS)),)
 dont_bother := true
diff --git a/core/tasks/product-graph.mk b/core/product-graph.mk
similarity index 98%
rename from core/tasks/product-graph.mk
rename to core/product-graph.mk
index db2cf71..36e9037 100644
--- a/core/tasks/product-graph.mk
+++ b/core/product-graph.mk
@@ -34,7 +34,7 @@
 endef
 
 
-this_makefile := build/core/tasks/product-graph.mk
+this_makefile := build/core/product-graph.mk
 
 products_svg := $(OUT_DIR)/products.svg
 products_pdf := $(OUT_DIR)/products.pdf
diff --git a/core/product.mk b/core/product.mk
index f242e82..a9af325 100644
--- a/core/product.mk
+++ b/core/product.mk
@@ -133,11 +133,14 @@
 #  3. Records that we've visited this node, in ALL_PRODUCTS
 #
 define inherit-product
+  $(if $(findstring ../,$(1)),\
+    $(eval np := $(call normalize-paths,$(1))),\
+    $(eval np := $(strip $(1))))\
   $(foreach v,$(_product_var_list), \
-      $(eval $(v) := $($(v)) $(INHERIT_TAG)$(strip $(1)))) \
+      $(eval $(v) := $($(v)) $(INHERIT_TAG)$(np))) \
   $(eval inherit_var := \
       PRODUCTS.$(strip $(word 1,$(_include_stack))).INHERITS_FROM) \
-  $(eval $(inherit_var) := $(sort $($(inherit_var)) $(strip $(1)))) \
+  $(eval $(inherit_var) := $(sort $($(inherit_var)) $(np))) \
   $(eval inherit_var:=) \
   $(eval ALL_PRODUCTS := $(sort $(ALL_PRODUCTS) $(word 1,$(_include_stack))))
 endef
diff --git a/core/product_config.mk b/core/product_config.mk
index 5240ae7..ad3b518 100644
--- a/core/product_config.mk
+++ b/core/product_config.mk
@@ -213,7 +213,19 @@
 current_product_makefile := $(strip $(current_product_makefile))
 all_product_makefiles := $(strip $(all_product_makefiles))
 
-ifneq (,$(filter product-graph dump-products, $(MAKECMDGOALS)))
+load_all_product_makefiles :=
+ifneq (,$(filter product-graph, $(MAKECMDGOALS)))
+ifeq ($(ANDROID_PRODUCT_GRAPH),--all)
+load_all_product_makefiles := true
+endif
+endif
+ifneq (,$(filter dump-products,$(MAKECMDGOALS)))
+ifeq ($(ANDROID_DUMP_PRODUCTS),all)
+load_all_product_makefiles := true
+endif
+endif
+
+ifeq ($(load_all_product_makefiles),true)
 # Import all product makefiles.
 $(call import-products, $(all_product_makefiles))
 else
diff --git a/tools/normalize_path.py b/tools/normalize_path.py
index 1b3d42e..6c4d548 100755
--- a/tools/normalize_path.py
+++ b/tools/normalize_path.py
@@ -14,11 +14,16 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 """
-Normalize and output paths read from stdin.
+Normalize and output paths from arguments, or stdin if no arguments provided.
 """
 
 import os.path
 import sys
 
+if len(sys.argv) > 1:
+  for p in sys.argv[1:]:
+    print os.path.normpath(p)
+  sys.exit(0)
+
 for line in sys.stdin:
   print os.path.normpath(line.strip())
diff --git a/tools/releasetools/add_img_to_target_files.py b/tools/releasetools/add_img_to_target_files.py
index 6bdb9d1..54c7189 100755
--- a/tools/releasetools/add_img_to_target_files.py
+++ b/tools/releasetools/add_img_to_target_files.py
@@ -271,6 +271,8 @@
   output_zip = zipfile.ZipFile(filename, "a",
                                compression=zipfile.ZIP_DEFLATED)
 
+  has_recovery = (OPTIONS.info_dict.get("no_recovery") != "true")
+
   def banner(s):
     print "\n\n++++ " + s + " ++++\n\n"
 
@@ -288,19 +290,21 @@
     if boot_image:
       boot_image.AddToZip(output_zip)
 
-  banner("recovery")
   recovery_image = None
-  prebuilt_path = os.path.join(OPTIONS.input_tmp, "IMAGES", "recovery.img")
-  if os.path.exists(prebuilt_path):
-    print "recovery.img already exists in IMAGES/, no need to rebuild..."
-    if OPTIONS.rebuild_recovery:
+  if has_recovery:
+    banner("recovery")
+    prebuilt_path = os.path.join(OPTIONS.input_tmp, "IMAGES", "recovery.img")
+    if os.path.exists(prebuilt_path):
+      print "recovery.img already exists in IMAGES/, no need to rebuild..."
+      if OPTIONS.rebuild_recovery:
+        recovery_image = common.GetBootableImage(
+            "IMAGES/recovery.img", "recovery.img", OPTIONS.input_tmp,
+            "RECOVERY")
+    else:
       recovery_image = common.GetBootableImage(
           "IMAGES/recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY")
-  else:
-    recovery_image = common.GetBootableImage(
-        "IMAGES/recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY")
-    if recovery_image:
-      recovery_image.AddToZip(output_zip)
+      if recovery_image:
+        recovery_image.AddToZip(output_zip)
 
   banner("system")
   AddSystem(output_zip, recovery_img=recovery_image, boot_img=boot_image)
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index cad654a..0063d63 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -1284,7 +1284,20 @@
     else:
       ranges = self.src.care_map.subtract(self.src.clobbered_blocks)
       ranges_str = ranges.to_string_raw()
-      if self.version >= 3:
+      if self.version >= 4:
+        script.AppendExtra(('if (range_sha1("%s", "%s") == "%s" || '
+                            'block_image_verify("%s", '
+                            'package_extract_file("%s.transfer.list"), '
+                            '"%s.new.dat", "%s.patch.dat") || '
+                            '(block_image_recover("%s", "%s") && '
+                            'block_image_verify("%s", '
+                            'package_extract_file("%s.transfer.list"), '
+                            '"%s.new.dat", "%s.patch.dat"))) then') % (
+                            self.device, ranges_str, self.src.TotalSha1(),
+                            self.device, partition, partition, partition,
+                            self.device, ranges_str,
+                            self.device, partition, partition, partition))
+      elif self.version == 3:
         script.AppendExtra(('if (range_sha1("%s", "%s") == "%s" || '
                             'block_image_verify("%s", '
                             'package_extract_file("%s.transfer.list"), '
diff --git a/tools/releasetools/img_from_target_files.py b/tools/releasetools/img_from_target_files.py
index ce5808f..aa21d7e 100755
--- a/tools/releasetools/img_from_target_files.py
+++ b/tools/releasetools/img_from_target_files.py
@@ -102,10 +102,11 @@
       if boot_image:
         boot_image.AddToZip(output_zip)
 
-      recovery_image = common.GetBootableImage(
-          "recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY")
-      if recovery_image:
-        recovery_image.AddToZip(output_zip)
+      if OPTIONS.info_dict.get("no_recovery") != "true":
+        recovery_image = common.GetBootableImage(
+            "recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY")
+        if recovery_image:
+          recovery_image.AddToZip(output_zip)
 
       def banner(s):
         print "\n\n++++ " + s + " ++++\n\n"
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index 354b9ad..4e86065 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -1612,6 +1612,10 @@
   if OPTIONS.device_specific is not None:
     OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)
 
+  if OPTIONS.info_dict.get("no_recovery") == "true":
+    raise common.ExternalError(
+        "--- target build has specified no recovery ---")
+
   while True:
 
     if OPTIONS.no_signing: