Merge "Fix Markdown formatting."
diff --git a/core/Makefile b/core/Makefile
index f7b55e6..b8fdf45 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -1691,7 +1691,7 @@
     $(BOARD_ODM_DLKMIMAGE_FILE_SYSTEM_TYPE) \
     $(BOARD_SYSTEM_DLKMIMAGE_FILE_SYSTEM_TYPE) \
   ,erofs),)
-INTERNAL_USERIMAGES_DEPS += $(MKEROFSUSERIMG)
+INTERNAL_USERIMAGES_DEPS += $(MKEROFS)
 BOARD_EROFS_COMPRESSOR ?= "lz4hc,9"
 endif
 
@@ -4657,7 +4657,6 @@
   mke2fs \
   mke2fs.conf \
   mkfs.erofs \
-  mkerofsimage.sh \
   mkf2fsuserimg.sh \
   mksquashfs \
   mksquashfsimage.sh \
diff --git a/core/config.mk b/core/config.mk
index ff522a7..5ef9211 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -598,7 +598,6 @@
 MKEXTUSERIMG := $(HOST_OUT_EXECUTABLES)/mkuserimg_mke2fs
 MKE2FS_CONF := system/extras/ext4_utils/mke2fs.conf
 MKEROFS := $(HOST_OUT_EXECUTABLES)/mkfs.erofs
-MKEROFSUSERIMG := $(HOST_OUT_EXECUTABLES)/mkerofsimage.sh
 MKSQUASHFSUSERIMG := $(HOST_OUT_EXECUTABLES)/mksquashfsimage.sh
 MKF2FSUSERIMG := $(HOST_OUT_EXECUTABLES)/mkf2fsuserimg.sh
 SIMG2IMG := $(HOST_OUT_EXECUTABLES)/simg2img$(HOST_EXECUTABLE_SUFFIX)
diff --git a/core/product_config.rbc b/core/product_config.rbc
index 469b0f7..8f27c99 100644
--- a/core/product_config.rbc
+++ b/core/product_config.rbc
@@ -479,8 +479,8 @@
 
 def _find_and_copy(pattern, from_dir, to_dir):
     """Return a copy list for the files matching the pattern."""
-    return sorted(["%s/%s:%s/%s" % (
-        from_dir, f, to_dir, f) for f in rblf_find_files(from_dir, pattern, only_files=1)])
+    return sorted([("%s/%s:%s/%s" % (from_dir, f, to_dir, f))
+        .replace("//", "/") for f in rblf_find_files(from_dir, pattern, only_files=1)])
 
 def _findstring(needle, haystack):
     """Equivalent to GNU make's $(findstring)."""
diff --git a/tools/releasetools/Android.bp b/tools/releasetools/Android.bp
index 25483f3..90adcaa 100644
--- a/tools/releasetools/Android.bp
+++ b/tools/releasetools/Android.bp
@@ -56,7 +56,9 @@
     required: [
         "blk_alloc_to_base_fs",
         "e2fsck",
-        "mkerofsimage.sh",
+        "fsck.erofs",
+        "img2simg",
+        "mkfs.erofs",
         "mkuserimg_mke2fs",
         "simg2img",
         "tune2fs",
diff --git a/tools/releasetools/build_image.py b/tools/releasetools/build_image.py
index dbd2c6f..e33b581 100755
--- a/tools/releasetools/build_image.py
+++ b/tools/releasetools/build_image.py
@@ -268,18 +268,19 @@
   """
   build_command = []
   fs_type = prop_dict.get("fs_type", "")
-  run_e2fsck = False
+  run_fsck = None
   needs_projid = prop_dict.get("needs_projid", 0)
   needs_casefold = prop_dict.get("needs_casefold", 0)
   needs_compress = prop_dict.get("needs_compress", 0)
 
   disable_sparse = "disable_sparse" in prop_dict
+  manual_sparse = False
 
   if fs_type.startswith("ext"):
     build_command = [prop_dict["ext_mkuserimg"]]
     if "extfs_sparse_flag" in prop_dict and not disable_sparse:
       build_command.append(prop_dict["extfs_sparse_flag"])
-      run_e2fsck = True
+      run_e2fsck = RunE2fsck
     build_command.extend([in_dir, out_file, fs_type,
                           prop_dict["mount_point"]])
     build_command.append(prop_dict["image_size"])
@@ -320,17 +321,8 @@
     if "selinux_fc" in prop_dict:
       build_command.append(prop_dict["selinux_fc"])
   elif fs_type.startswith("erofs"):
-    build_command = ["mkerofsimage.sh"]
-    build_command.extend([in_dir, out_file])
-    if "erofs_sparse_flag" in prop_dict and not disable_sparse:
-      build_command.extend([prop_dict["erofs_sparse_flag"]])
-    build_command.extend(["-m", prop_dict["mount_point"]])
-    if target_out:
-      build_command.extend(["-d", target_out])
-    if fs_config:
-      build_command.extend(["-C", fs_config])
-    if "selinux_fc" in prop_dict:
-      build_command.extend(["-c", prop_dict["selinux_fc"]])
+    build_command = ["mkfs.erofs"]
+
     compressor = None
     if "erofs_default_compressor" in prop_dict:
       compressor = prop_dict["erofs_default_compressor"]
@@ -338,16 +330,30 @@
       compressor = prop_dict["erofs_compressor"]
     if compressor:
       build_command.extend(["-z", compressor])
+
+    build_command.extend(["--mount-point", prop_dict["mount_point"]])
+    if target_out:
+      build_command.extend(["--product-out", target_out])
+    if fs_config:
+      build_command.extend(["--fs-config-file", fs_config])
+    if "selinux_fc" in prop_dict:
+      build_command.extend(["--file-contexts", prop_dict["selinux_fc"]])
     if "timestamp" in prop_dict:
       build_command.extend(["-T", str(prop_dict["timestamp"])])
     if "uuid" in prop_dict:
       build_command.extend(["-U", prop_dict["uuid"]])
     if "block_list" in prop_dict:
-      build_command.extend(["-B", prop_dict["block_list"]])
+      build_command.extend(["--block-list-file", prop_dict["block_list"]])
     if "erofs_pcluster_size" in prop_dict:
-      build_command.extend(["-P", prop_dict["erofs_pcluster_size"]])
+      build_command.extend(["-C", prop_dict["erofs_pcluster_size"]])
     if "erofs_share_dup_blocks" in prop_dict:
-      build_command.extend(["-k", "4096"])
+      build_command.extend(["--chunksize", "4096"])
+
+    build_command.extend([out_file, in_dir])
+    if "erofs_sparse_flag" in prop_dict and not disable_sparse:
+      manual_sparse = True
+
+    run_fsck = RunErofsFsck
   elif fs_type.startswith("squash"):
     build_command = ["mksquashfsimage.sh"]
     build_command.extend([in_dir, out_file])
@@ -436,18 +442,38 @@
               int(prop_dict["partition_size"]) // BYTES_IN_MB))
     raise
 
-  if run_e2fsck and prop_dict.get("skip_fsck") != "true":
-    unsparse_image = UnsparseImage(out_file, replace=False)
+  if run_fsck and prop_dict.get("skip_fsck") != "true":
+    run_fsck(out_file)
 
-    # Run e2fsck on the inflated image file
-    e2fsck_command = ["e2fsck", "-f", "-n", unsparse_image]
-    try:
-      common.RunAndCheckOutput(e2fsck_command)
-    finally:
-      os.remove(unsparse_image)
+  if manual_sparse:
+    temp_file = out_file + ".sparse"
+    img2simg_argv = ["img2simg", out_file, temp_file]
+    common.RunAndCheckOutput(img2simg_argv)
+    os.rename(temp_file, out_file)
 
   return mkfs_output
 
+
+def RunE2fsck(out_file):
+  unsparse_image = UnsparseImage(out_file, replace=False)
+
+  # Run e2fsck on the inflated image file
+  e2fsck_command = ["e2fsck", "-f", "-n", unsparse_image]
+  try:
+    common.RunAndCheckOutput(e2fsck_command)
+  finally:
+    os.remove(unsparse_image)
+
+
+def RunErofsFsck(out_file):
+  fsck_command = ["fsck.erofs", "--extract", out_file]
+  try:
+    common.RunAndCheckOutput(fsck_command)
+  except:
+    print("Check failed for EROFS image {}".format(out_file))
+    raise
+
+
 def BuildImage(in_dir, prop_dict, out_file, target_out=None):
   """Builds an image for the files under in_dir and writes it to out_file.
 
diff --git a/tools/releasetools/merge_target_files.py b/tools/releasetools/merge_target_files.py
index 6d3ee3f..25ed60e 100755
--- a/tools/releasetools/merge_target_files.py
+++ b/tools/releasetools/merge_target_files.py
@@ -664,36 +664,24 @@
     apex_packages.update(partition_apex_packages)
 
 
-def generate_care_map(partitions, target_files_dir):
-  """Generates a merged META/care_map.pb file in the target files dir.
+def update_care_map_image_size_props(images_dir):
+  """Sets <partition>_image_size props in misc_info.
 
-  Depends on the info dict from META/misc_info.txt, as well as built images
-  within IMAGES/.
+  add_images_to_target_files uses these props to generate META/care_map.pb.
+  Regenerated images will have this property set during regeneration.
 
-  Args:
-    partitions: A list of partitions to potentially include in the care map.
-    target_files_dir: Extracted directory of target_files, containing partition
-      directories.
+  However, images copied directly from input partial target files packages
+  need this value calculated here.
   """
-  OPTIONS.info_dict = common.LoadInfoDict(target_files_dir)
-  partition_image_map = {}
-  for partition in partitions:
-    image_path = os.path.join(target_files_dir, 'IMAGES',
-                              '{}.img'.format(partition))
+  for partition in common.PARTITIONS_WITH_CARE_MAP:
+    image_path = os.path.join(images_dir, '{}.img'.format(partition))
     if os.path.exists(image_path):
-      partition_image_map[partition] = image_path
-      # Regenerated images should have their image_size property already set.
-      image_size_prop = '{}_image_size'.format(partition)
-      if image_size_prop not in OPTIONS.info_dict:
-        # Images copied directly from input target files packages will need
-        # their image sizes calculated.
-        partition_size = sparse_img.GetImagePartitionSize(image_path)
-        image_props = build_image.ImagePropFromGlobalDict(
-            OPTIONS.info_dict, partition)
-        verity_image_builder = verity_utils.CreateVerityImageBuilder(
-            image_props)
-        image_size = verity_image_builder.CalculateMaxImageSize(partition_size)
-        OPTIONS.info_dict[image_size_prop] = image_size
+      partition_size = sparse_img.GetImagePartitionSize(image_path)
+      image_props = build_image.ImagePropFromGlobalDict(
+          OPTIONS.merged_misc_info, partition)
+      verity_image_builder = verity_utils.CreateVerityImageBuilder(image_props)
+      image_size = verity_image_builder.CalculateMaxImageSize(partition_size)
+      OPTIONS.merged_misc_info['{}_image_size'.format(partition)] = image_size
 
 
 def merge_meta_files(temp_dir, merged_dir):
@@ -737,6 +725,7 @@
         framework_meta_dir=framework_meta_dir,
         vendor_meta_dir=vendor_meta_dir,
         merged_meta_dir=merged_meta_dir)
+    update_care_map_image_size_props(images_dir=os.path.join(merged_dir, 'IMAGES'))
 
   for file_name in ('apkcerts.txt', 'apexkeys.txt'):
     merge_package_keys_txt(
@@ -1362,10 +1351,6 @@
   if not OPTIONS.output_target_files:
     return
 
-  # Create the merged META/care_map.pb if the device uses A/B updates.
-  if OPTIONS.merged_misc_info.get('ab_update') == 'true':
-    generate_care_map(partition_map.keys(), output_target_files_temp_dir)
-
   create_target_files_archive(OPTIONS.output_target_files,
                               output_target_files_temp_dir, temp_dir)
 
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index 43c39fb..522d489 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -543,8 +543,7 @@
 
   oem_dicts = []
   for oem_file in oem_source:
-    with open(oem_file) as fp:
-      oem_dicts.append(common.LoadDictionaryFromLines(fp.readlines()))
+    oem_dicts.append(common.LoadDictionaryFromFile(oem_file))
   return oem_dicts
 
 
@@ -1475,7 +1474,7 @@
                                  "enable_vabc_xor=",
                                  "force_minor_version=",
                                  "compressor_types=",
-                                 "enable_zucchin=",
+                                 "enable_zucchini=",
                                  "enable_lz4diff=",
                                  "vabc_compression_param=",
                              ], extra_option_handler=option_handler)