avbtool: add_hashtree_footer: Add --setup_as_rootfs_from_kernel option.

This option makes it possible to generate system.img with kernel
command-line descriptors for setting up the partition with dm-verity
as the root filesystem. This is different from the existing option
--setup_rootfs_from_kernel which takes a path to system.img and adds
the kernel command-line descriptors to e.g. vbmeta.img.

This option can be used when using chained partitions for system.img.

Also fix README.md to use --include_descriptors_from_image and not
--include_descriptors_from_footer.

Bug: 38304536
Test: New unit tests + all unit tests pass.
Change-Id: I6285877cdb3b63a7c9117c270459d1fbb93e3309
diff --git a/avbtool b/avbtool
index 7c18d46..1b459f7 100755
--- a/avbtool
+++ b/avbtool
@@ -2039,11 +2039,11 @@
     data_size += h.auxiliary_data_block_size
     return image.read(data_size)
 
-  def _get_cmdline_descriptors_for_dm_verity(self, image):
+  def _get_cmdline_descriptors_for_hashtree_descriptor(self, ht):
     """Generate kernel cmdline descriptors for dm-verity.
 
     Arguments:
-      image: An ImageHandler (vbmeta or footer) with a hashtree descriptor.
+      ht: A AvbHashtreeDescriptor
 
     Returns:
       A list with two AvbKernelCmdlineDescriptor with dm-verity kernel cmdline
@@ -2055,17 +2055,6 @@
 
     """
 
-    (_, _, descriptors, _) = self._parse_image(image)
-
-    ht = None
-    for desc in descriptors:
-      if isinstance(desc, AvbHashtreeDescriptor):
-        ht = desc
-        break
-
-    if not ht:
-      raise AvbError('No hashtree descriptor in given image')
-
     c = 'dm="1 vroot none ro 1,'
     c += '0'  # start
     c += ' {}'.format((ht.image_size / 512))  # size (# sectors)
@@ -2111,6 +2100,35 @@
 
     return [desc, desc_no_ht]
 
+  def _get_cmdline_descriptors_for_dm_verity(self, image):
+    """Generate kernel cmdline descriptors for dm-verity.
+
+    Arguments:
+      image: An ImageHandler (vbmeta or footer) with a hashtree descriptor.
+
+    Returns:
+      A list with two AvbKernelCmdlineDescriptor with dm-verity kernel cmdline
+      instructions. There is one for when hashtree is not disabled and one for
+      when it is.
+
+    Raises:
+      AvbError: If  |image| doesn't have a hashtree descriptor.
+
+    """
+
+    (_, _, descriptors, _) = self._parse_image(image)
+
+    ht = None
+    for desc in descriptors:
+      if isinstance(desc, AvbHashtreeDescriptor):
+        ht = desc
+        break
+
+    if not ht:
+      raise AvbError('No hashtree descriptor in given image')
+
+    return self._get_cmdline_descriptors_for_hashtree_descriptor(ht)
+
   def make_vbmeta_image(self, output, chain_partitions, algorithm_name,
                         key_path, public_key_metadata_path, rollback_index,
                         flags, props, props_from_file, kernel_cmdlines,
@@ -2142,10 +2160,11 @@
     """
 
     descriptors = []
+    ht_desc_to_setup = None
     vbmeta_blob = self._generate_vbmeta_blob(
         algorithm_name, key_path, public_key_metadata_path, descriptors,
         chain_partitions, rollback_index, flags, props, props_from_file,
-        kernel_cmdlines, setup_rootfs_from_kernel,
+        kernel_cmdlines, setup_rootfs_from_kernel, ht_desc_to_setup,
         include_descriptors_from_image, signing_helper, release_string,
         append_to_release_string)
 
@@ -2159,6 +2178,7 @@
                             rollback_index, flags, props, props_from_file,
                             kernel_cmdlines,
                             setup_rootfs_from_kernel,
+                            ht_desc_to_setup,
                             include_descriptors_from_image, signing_helper,
                             release_string, append_to_release_string):
     """Generates a VBMeta blob.
@@ -2184,6 +2204,8 @@
       kernel_cmdlines: Kernel cmdlines to insert (list of strings).
       setup_rootfs_from_kernel: None or file to generate
         dm-verity kernel cmdline from.
+      ht_desc_to_setup: If not None, an AvbHashtreeDescriptor to
+        generate dm-verity kernel cmdline descriptors from.
       include_descriptors_from_image: List of file objects for which
         to insert descriptors from.
       signing_helper: Program which signs a hash and return signature.
@@ -2258,7 +2280,7 @@
         desc.value = open(file_path, 'rb').read()
         encoded_descriptors.extend(desc.encode())
 
-    # Add AvbKernelCmdline descriptor for dm-verity, if requested.
+    # Add AvbKernelCmdline descriptor for dm-verity from an image, if requested.
     if setup_rootfs_from_kernel:
       image_handler = ImageHandler(
           setup_rootfs_from_kernel.name)
@@ -2266,6 +2288,13 @@
       encoded_descriptors.extend(cmdline_desc[0].encode())
       encoded_descriptors.extend(cmdline_desc[1].encode())
 
+    # Add AvbKernelCmdline descriptor for dm-verity from desc, if requested.
+    if ht_desc_to_setup:
+      cmdline_desc = self._get_cmdline_descriptors_for_hashtree_descriptor(
+          ht_desc_to_setup)
+      encoded_descriptors.extend(cmdline_desc[0].encode())
+      encoded_descriptors.extend(cmdline_desc[1].encode())
+
     # Add kernel command-lines.
     if kernel_cmdlines:
       for i in kernel_cmdlines:
@@ -2558,10 +2587,11 @@
       h_desc.digest = digest
 
       # Generate the VBMeta footer.
+      ht_desc_to_setup = None
       vbmeta_blob = self._generate_vbmeta_blob(
           algorithm_name, key_path, public_key_metadata_path, [h_desc],
           chain_partitions, rollback_index, flags, props, props_from_file,
-          kernel_cmdlines, setup_rootfs_from_kernel,
+          kernel_cmdlines, setup_rootfs_from_kernel, ht_desc_to_setup,
           include_descriptors_from_image, signing_helper, release_string,
           append_to_release_string)
 
@@ -2619,6 +2649,7 @@
                           public_key_metadata_path, rollback_index, flags,
                           props, props_from_file, kernel_cmdlines,
                           setup_rootfs_from_kernel,
+                          setup_as_rootfs_from_kernel,
                           include_descriptors_from_image,
                           calc_max_image_size, signing_helper,
                           release_string, append_to_release_string,
@@ -2648,6 +2679,8 @@
       kernel_cmdlines: Kernel cmdlines to insert (list of strings).
       setup_rootfs_from_kernel: None or file to generate
         dm-verity kernel cmdline from.
+      setup_as_rootfs_from_kernel: If True, generate dm-verity kernel
+        cmdline to set up rootfs.
       include_descriptors_from_image: List of file objects for which
         to insert descriptors from.
       calc_max_image_size: Don't store the hashtree or footer - instead
@@ -2785,12 +2818,16 @@
         ht_desc.fec_offset = fec_offset
         ht_desc.fec_size = len(fec_data)
 
+      ht_desc_to_setup = None
+      if setup_as_rootfs_from_kernel:
+        ht_desc_to_setup = ht_desc
+
       # Generate the VBMeta footer and add padding as needed.
       vbmeta_offset = tree_offset + len_hashtree_and_fec
       vbmeta_blob = self._generate_vbmeta_blob(
           algorithm_name, key_path, public_key_metadata_path, [ht_desc],
           chain_partitions, rollback_index, flags, props, props_from_file,
-          kernel_cmdlines, setup_rootfs_from_kernel,
+          kernel_cmdlines, setup_rootfs_from_kernel, ht_desc_to_setup,
           include_descriptors_from_image, signing_helper, release_string,
           append_to_release_string)
       padding_needed = (round_to_multiple(len(vbmeta_blob), image.block_size) -
@@ -3308,6 +3345,12 @@
                             help=('Do not append vbmeta struct or footer '
                                   'to the image'),
                             action='store_true')
+    # This is different from --setup_rootfs_from_kernel insofar that
+    # it doesn't take an IMAGE, the generated cmdline will be for the
+    # hashtree we're adding.
+    sub_parser.add_argument('--setup_as_rootfs_from_kernel',
+                            action='store_true',
+                            help='Adds kernel cmdline for setting up rootfs')
     self._add_common_args(sub_parser)
     sub_parser.set_defaults(func=self.add_hashtree_footer)
 
@@ -3510,6 +3553,7 @@
                                  args.prop_from_file,
                                  args.kernel_cmdline,
                                  args.setup_rootfs_from_kernel,
+                                 args.setup_as_rootfs_from_kernel,
                                  args.include_descriptors_from_image,
                                  args.calc_max_image_size, args.signing_helper,
                                  args.internal_release_string,