Merge "Allow system partition to be absent"
diff --git a/libavb/avb_slot_verify.c b/libavb/avb_slot_verify.c
index 244a652..72f5091 100644
--- a/libavb/avb_slot_verify.c
+++ b/libavb/avb_slot_verify.c
@@ -1284,6 +1284,35 @@
   return io_ret;
 }
 
+static bool has_system_partition(AvbOps* ops, const char* ab_suffix) {
+  char part_name[AVB_PART_NAME_MAX_SIZE];
+  char* system_part_name = "system";
+  char guid_buf[37];
+  AvbIOResult io_ret;
+
+  if (!avb_str_concat(part_name,
+                      sizeof part_name,
+                      system_part_name,
+                      avb_strlen(system_part_name),
+                      ab_suffix,
+                      avb_strlen(ab_suffix))) {
+    avb_error("System partition name and suffix does not fit.\n");
+    return false;
+  }
+
+  io_ret = ops->get_unique_guid_for_partition(
+      ops, part_name, guid_buf, sizeof guid_buf);
+  if (io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION) {
+    avb_debug("No system partition.\n");
+    return false;
+  } else if (io_ret != AVB_IO_RESULT_OK) {
+    avb_error("Error getting unique GUID for system partition.\n");
+    return false;
+  }
+
+  return true;
+}
+
 AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
                                     const char* const* requested_partitions,
                                     const char* ab_suffix,
@@ -1407,11 +1436,16 @@
        * that the system partition is mounted.
        */
       avb_assert(slot_data->cmdline == NULL);
-      slot_data->cmdline =
-          avb_strdup("root=PARTUUID=$(ANDROID_SYSTEM_PARTUUID)");
-      if (slot_data->cmdline == NULL) {
-        ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
-        goto fail;
+      // Devices with dynamic partitions won't have system partition.
+      // Instead, it has a large super partition to accommodate *.img files.
+      // See b/119551429 for details.
+      if (has_system_partition(ops, ab_suffix)) {
+        slot_data->cmdline =
+            avb_strdup("root=PARTUUID=$(ANDROID_SYSTEM_PARTUUID)");
+        if (slot_data->cmdline == NULL) {
+          ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+          goto fail;
+        }
       }
     } else {
       /* If requested, manage dm-verity mode... */
diff --git a/test/avb_slot_verify_unittest.cc b/test/avb_slot_verify_unittest.cc
index f63e831..26bac98 100644
--- a/test/avb_slot_verify_unittest.cc
+++ b/test/avb_slot_verify_unittest.cc
@@ -48,7 +48,9 @@
 
   void CmdlineWithHashtreeVerification(bool hashtree_verification_on);
   void CmdlineWithChainedHashtreeVerification(bool hashtree_verification_on);
-  void VerificationDisabled(bool use_avbctl, bool preload);
+  void VerificationDisabled(bool use_avbctl,
+                            bool preload,
+                            bool has_system_partition);
 };
 
 TEST_F(AvbSlotVerifyTest, Basic) {
@@ -2006,7 +2008,8 @@
 }
 
 void AvbSlotVerifyTest::VerificationDisabled(bool use_avbctl,
-                                             bool preload_boot) {
+                                             bool preload_boot,
+                                             bool has_system_partition) {
   const size_t boot_part_size = 32 * 1024 * 1024;
   const size_t dtbo_part_size = 4 * 1024 * 1024;
   const size_t rootfs_size = 1028 * 1024;
@@ -2089,6 +2092,10 @@
   ops_.set_expected_public_key(
       PublicKeyAVB(base::FilePath("test/data/testkey_rsa2048.pem")));
 
+  if (!has_system_partition) {
+    ops_.set_hidden_partitions({"system", "system_a", "system_b"});
+  }
+
   // Manually set the flag the same way 'avbctl disable-verification'
   // would do it.
   if (use_avbctl) {
@@ -2131,8 +2138,13 @@
                             AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
                             &slot_data));
   EXPECT_NE(nullptr, slot_data);
-  EXPECT_EQ("root=PARTUUID=1234-fake-guid-for:system_a",
-            std::string(slot_data->cmdline));
+  if (has_system_partition) {
+    EXPECT_EQ("root=PARTUUID=1234-fake-guid-for:system_a",
+              std::string(slot_data->cmdline));
+  } else {
+    EXPECT_EQ(nullptr, slot_data->cmdline);
+  }
+
   // Also make sure that it actually loads the boot and dtbo partitions.
   EXPECT_EQ(size_t(2), slot_data->num_loaded_partitions);
   EXPECT_EQ("boot",
@@ -2156,19 +2168,39 @@
 }
 
 TEST_F(AvbSlotVerifyTest, VerificationDisabledUnmodified) {
-  VerificationDisabled(false, false);  // use_avbctl
+  VerificationDisabled(false,  // use_avbctl
+                       false,  // preload_boot
+                       true);  // has_system_partition
 }
 
 TEST_F(AvbSlotVerifyTest, VerificationDisabledModified) {
-  VerificationDisabled(true, false);  // use_avbctl
+  VerificationDisabled(true,   // use_avbctl
+                       false,  // preload_boot
+                       true);  // has_system_partition
 }
 
 TEST_F(AvbSlotVerifyTest, VerificationDisabledUnmodifiedPreloadBoot) {
-  VerificationDisabled(false, true);  // use_avbctl
+  VerificationDisabled(false,  // use_avbctl
+                       true,   // preload_boot
+                       true);  // has_system_partition
 }
 
 TEST_F(AvbSlotVerifyTest, VerificationDisabledModifiedPreloadBoot) {
-  VerificationDisabled(true, true);  // use_avbctl
+  VerificationDisabled(true,   // use_avbctl
+                       true,   // preload_boot
+                       true);  // has_system_partition
+}
+
+TEST_F(AvbSlotVerifyTest, VerificationDisabledUnmodifiedNoSystemPartition) {
+  VerificationDisabled(false,   // use_avbctl
+                       false,   // preload_boot
+                       false);  // has_system_partition
+}
+
+TEST_F(AvbSlotVerifyTest, VerificationDisabledModifiedNoSystemPartition) {
+  VerificationDisabled(true,    // use_avbctl
+                       false,   // preload_boot
+                       false);  // has_system_partition
 }
 
 // In the event that there's no vbmeta partition, we treat the vbmeta