Switch to bionic gtest in bootable/recovery

We encountered segfaults in Imgdiff host tests due to the failure to
reset states of getopt. The problem can be solved by switching to use
bionic's gtest where a new process is forked for each test.

Also modify the recovery_component_test to make sure it runs in parallel.
Changes include:
  1. Merge the writes to misc partition into one single test.
  2. Change the hard coded location "/cache/saved.file" into a configurable
  variable.

Bug: 67849209
Test: recovery tests pass

Change-Id: I165d313f32b83393fb7922c5078636ac40b50bc2
diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp
index c8b75df..2153b5f 100644
--- a/applypatch/applypatch.cpp
+++ b/applypatch/applypatch.cpp
@@ -42,6 +42,8 @@
 #include "otafault/ota_io.h"
 #include "otautil/print_sha1.h"
 
+std::string cache_temp_source = "/cache/saved.file";
+
 static int LoadPartitionContents(const std::string& filename, FileContents* file);
 static size_t FileSink(const unsigned char* data, size_t len, int fd);
 static int GenerateTarget(const FileContents& source_file, const std::unique_ptr<Value>& patch,
@@ -411,12 +413,10 @@
       (!patch_sha1_str.empty() && FindMatchingPatch(file.sha1, patch_sha1_str) < 0)) {
     printf("file \"%s\" doesn't have any of expected sha1 sums; checking cache\n", filename);
 
-    // If the source file is missing or corrupted, it might be because
-    // we were killed in the middle of patching it.  A copy of it
-    // should have been made in CACHE_TEMP_SOURCE.  If that file
-    // exists and matches the sha1 we're looking for, the check still
-    // passes.
-    if (LoadFileContents(CACHE_TEMP_SOURCE, &file) != 0) {
+    // If the source file is missing or corrupted, it might be because we were killed in the middle
+    // of patching it.  A copy of it should have been made in cache_temp_source.  If that file
+    // exists and matches the sha1 we're looking for, the check still passes.
+    if (LoadFileContents(cache_temp_source.c_str(), &file) != 0) {
       printf("failed to load cache file\n");
       return 1;
     }
@@ -539,7 +539,7 @@
   printf("source file is bad; trying copy\n");
 
   FileContents copy_file;
-  if (LoadFileContents(CACHE_TEMP_SOURCE, &copy_file) < 0) {
+  if (LoadFileContents(cache_temp_source.c_str(), &copy_file) < 0) {
     printf("failed to read copy file\n");
     return 1;
   }
@@ -634,7 +634,7 @@
     printf("not enough free space on /cache\n");
     return 1;
   }
-  if (SaveFileContents(CACHE_TEMP_SOURCE, &source_file) < 0) {
+  if (SaveFileContents(cache_temp_source.c_str(), &source_file) < 0) {
     printf("failed to back up source file\n");
     return 1;
   }
@@ -680,7 +680,7 @@
   }
 
   // Delete the backup copy of the source.
-  unlink(CACHE_TEMP_SOURCE);
+  unlink(cache_temp_source.c_str());
 
   // Success!
   return 0;
diff --git a/applypatch/freecache.cpp b/applypatch/freecache.cpp
index 331cae2..0a40baa 100644
--- a/applypatch/freecache.cpp
+++ b/applypatch/freecache.cpp
@@ -90,10 +90,9 @@
     while ((de = readdir(d.get())) != 0) {
       std::string path = std::string(dirs[i]) + "/" + de->d_name;
 
-      // We can't delete CACHE_TEMP_SOURCE; if it's there we might have
-      // restarted during installation and could be depending on it to
-      // be there.
-      if (path == CACHE_TEMP_SOURCE) {
+      // We can't delete cache_temp_source; if it's there we might have restarted during
+      // installation and could be depending on it to be there.
+      if (path == cache_temp_source) {
         continue;
       }
 
diff --git a/applypatch/include/applypatch/applypatch.h b/applypatch/include/applypatch/applypatch.h
index 2a3b3ef..bcb8a41 100644
--- a/applypatch/include/applypatch/applypatch.h
+++ b/applypatch/include/applypatch/applypatch.h
@@ -36,12 +36,11 @@
   struct stat st;
 };
 
-// When there isn't enough room on the target filesystem to hold the
-// patched version of the file, we copy the original here and delete
-// it to free up space.  If the expected source file doesn't exist, or
-// is corrupted, we look to see if this file contains the bits we want
-// and use it as the source instead.
-#define CACHE_TEMP_SOURCE "/cache/saved.file"
+// When there isn't enough room on the target filesystem to hold the patched version of the file,
+// we copy the original here and delete it to free up space.  If the expected source file doesn't
+// exist, or is corrupted, we look to see if the cached file contains the bits we want and use it as
+// the source instead.  The default location for the cached source is "/cache/saved.file".
+extern std::string cache_temp_source;
 
 using SinkFn = std::function<size_t(const unsigned char*, size_t)>;
 
diff --git a/bootloader_message/bootloader_message.cpp b/bootloader_message/bootloader_message.cpp
index f91446b..aaeffdc 100644
--- a/bootloader_message/bootloader_message.cpp
+++ b/bootloader_message/bootloader_message.cpp
@@ -159,14 +159,8 @@
 
 bool write_bootloader_message(const std::vector<std::string>& options, std::string* err) {
   bootloader_message boot = {};
-  strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
-  strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
-  for (const auto& s : options) {
-    strlcat(boot.recovery, s.c_str(), sizeof(boot.recovery));
-    if (s.back() != '\n') {
-      strlcat(boot.recovery, "\n", sizeof(boot.recovery));
-    }
-  }
+  update_bootloader_message_in_struct(&boot, options);
+
   return write_bootloader_message(boot, err);
 }
 
@@ -175,20 +169,27 @@
   if (!read_bootloader_message(&boot, err)) {
     return false;
   }
+  update_bootloader_message_in_struct(&boot, options);
 
-  // Zero out the entire fields.
-  memset(boot.command, 0, sizeof(boot.command));
-  memset(boot.recovery, 0, sizeof(boot.recovery));
+  return write_bootloader_message(boot, err);
+}
 
-  strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
-  strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
+bool update_bootloader_message_in_struct(bootloader_message* boot,
+                                         const std::vector<std::string>& options) {
+  if (!boot) return false;
+  // Replace the command & recovery fields.
+  memset(boot->command, 0, sizeof(boot->command));
+  memset(boot->recovery, 0, sizeof(boot->recovery));
+
+  strlcpy(boot->command, "boot-recovery", sizeof(boot->command));
+  strlcpy(boot->recovery, "recovery\n", sizeof(boot->recovery));
   for (const auto& s : options) {
-    strlcat(boot.recovery, s.c_str(), sizeof(boot.recovery));
+    strlcat(boot->recovery, s.c_str(), sizeof(boot->recovery));
     if (s.back() != '\n') {
-      strlcat(boot.recovery, "\n", sizeof(boot.recovery));
+      strlcat(boot->recovery, "\n", sizeof(boot->recovery));
     }
   }
-  return write_bootloader_message(boot, err);
+  return true;
 }
 
 bool write_reboot_bootloader(std::string* err) {
diff --git a/bootloader_message/include/bootloader_message/bootloader_message.h b/bootloader_message/include/bootloader_message/bootloader_message.h
index 2ffbfc9..798f3bb 100644
--- a/bootloader_message/include/bootloader_message/bootloader_message.h
+++ b/bootloader_message/include/bootloader_message/bootloader_message.h
@@ -207,6 +207,11 @@
 // only update the command and recovery fields.
 bool update_bootloader_message(const std::vector<std::string>& options, std::string* err);
 
+// Update bootloader message (boots into recovery with the |options|) in |boot|. Will only update
+// the command and recovery fields.
+bool update_bootloader_message_in_struct(bootloader_message* boot,
+                                         const std::vector<std::string>& options);
+
 // Clear BCB.
 bool clear_bootloader_message(std::string* err);
 
diff --git a/minadbd/Android.mk b/minadbd/Android.mk
index 803171d..3c9ab3a 100644
--- a/minadbd/Android.mk
+++ b/minadbd/Android.mk
@@ -46,7 +46,12 @@
 LOCAL_SRC_FILES := fuse_adb_provider_test.cpp
 LOCAL_CFLAGS := $(minadbd_cflags)
 LOCAL_C_INCLUDES := $(LOCAL_PATH) system/core/adb
-LOCAL_STATIC_LIBRARIES := libminadbd
-LOCAL_SHARED_LIBRARIES := liblog libbase libcutils
+LOCAL_STATIC_LIBRARIES := \
+    libBionicGtestMain \
+    libminadbd
+LOCAL_SHARED_LIBRARIES := \
+    liblog \
+    libbase \
+    libcutils
 
 include $(BUILD_NATIVE_TEST)
diff --git a/tests/Android.mk b/tests/Android.mk
index 8ebb603..d911c25 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -30,7 +30,8 @@
     libutils \
     libz \
     libselinux \
-    libbase
+    libbase \
+    libBionicGtestMain
 
 LOCAL_SRC_FILES := \
     unit/asn1_decoder_test.cpp \
@@ -50,7 +51,8 @@
 LOCAL_MODULE := recovery_manual_test
 LOCAL_STATIC_LIBRARIES := \
     libminui \
-    libbase
+    libbase \
+    libBionicGtestMain
 
 LOCAL_SRC_FILES := manual/recovery_test.cpp
 LOCAL_SHARED_LIBRARIES := \
@@ -163,6 +165,7 @@
     libsquashfs_utils \
     libcutils \
     libbrotli \
+    libBionicGtestMain \
     $(tune2fs_static_libraries)
 
 testdata_files := $(call find-subdir-files, testdata/*)
@@ -212,7 +215,8 @@
     libbz \
     libdivsufsort64 \
     libdivsufsort \
-    libz
+    libz \
+    libBionicGtestMain
 LOCAL_SHARED_LIBRARIES := \
     liblog
 include $(BUILD_HOST_NATIVE_TEST)
diff --git a/tests/component/applypatch_test.cpp b/tests/component/applypatch_test.cpp
index 15ec08f..21c9a52 100644
--- a/tests/component/applypatch_test.cpp
+++ b/tests/component/applypatch_test.cpp
@@ -53,8 +53,7 @@
 }
 
 static void mangle_file(const std::string& fname) {
-  std::string content;
-  content.reserve(1024);
+  std::string content(1024, '\0');
   for (size_t i = 0; i < 1024; i++) {
     content[i] = rand() % 256;
   }
@@ -63,16 +62,11 @@
 
 class ApplyPatchTest : public ::testing::Test {
  public:
-  static void SetUpTestCase() {
+  virtual void SetUp() override {
     // set up files
     old_file = from_testdata_base("old.file");
     new_file = from_testdata_base("new.file");
-    patch_file = from_testdata_base("patch.bsdiff");
-    rand_file = "/cache/applypatch_test_rand.file";
-    cache_file = "/cache/saved.file";
-
-    // write stuff to rand_file
-    ASSERT_TRUE(android::base::WriteStringToFile("hello", rand_file));
+    nonexistent_file = from_testdata_base("nonexistent.file");
 
     // set up SHA constants
     sha1sum(old_file, &old_sha1, &old_size);
@@ -82,56 +76,35 @@
     bad_sha1_b = android::base::StringPrintf("%040x", rand());
   }
 
-  static std::string old_file;
-  static std::string new_file;
-  static std::string rand_file;
-  static std::string cache_file;
-  static std::string patch_file;
+  std::string old_file;
+  std::string new_file;
+  std::string nonexistent_file;
 
-  static std::string old_sha1;
-  static std::string new_sha1;
-  static std::string bad_sha1_a;
-  static std::string bad_sha1_b;
+  std::string old_sha1;
+  std::string new_sha1;
+  std::string bad_sha1_a;
+  std::string bad_sha1_b;
 
-  static size_t old_size;
-  static size_t new_size;
+  size_t old_size;
+  size_t new_size;
 };
 
-static void cp(const std::string& src, const std::string& tgt) {
-  std::string cmd = "cp " + src + " " + tgt;
-  system(cmd.c_str());
-}
-
-static void backup_old() {
-  cp(ApplyPatchTest::old_file, ApplyPatchTest::cache_file);
-}
-
-static void restore_old() {
-  cp(ApplyPatchTest::cache_file, ApplyPatchTest::old_file);
-}
-
 class ApplyPatchCacheTest : public ApplyPatchTest {
- public:
-  virtual void SetUp() {
-    backup_old();
-  }
-
-  virtual void TearDown() {
-    restore_old();
+ protected:
+  void SetUp() override {
+    ApplyPatchTest::SetUp();
+    cache_temp_source = old_file;
   }
 };
 
-std::string ApplyPatchTest::old_file;
-std::string ApplyPatchTest::new_file;
-std::string ApplyPatchTest::rand_file;
-std::string ApplyPatchTest::patch_file;
-std::string ApplyPatchTest::cache_file;
-std::string ApplyPatchTest::old_sha1;
-std::string ApplyPatchTest::new_sha1;
-std::string ApplyPatchTest::bad_sha1_a;
-std::string ApplyPatchTest::bad_sha1_b;
-size_t ApplyPatchTest::old_size;
-size_t ApplyPatchTest::new_size;
+class ApplyPatchModesTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    cache_temp_source = cache_source.path;
+  }
+
+  TemporaryFile cache_source;
+};
 
 TEST_F(ApplyPatchTest, CheckModeSkip) {
   std::vector<std::string> sha1s;
@@ -189,43 +162,31 @@
   ASSERT_EQ(0, applypatch_check(src_file.c_str(), sha1s));
 }
 
-TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedSingle) {
-  mangle_file(old_file);
-  std::vector<std::string> sha1s = { old_sha1 };
-  ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
+TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedSourceSingle) {
+  TemporaryFile temp_file;
+  mangle_file(temp_file.path);
+  std::vector<std::string> sha1s_single = { old_sha1 };
+  ASSERT_EQ(0, applypatch_check(temp_file.path, sha1s_single));
+  ASSERT_EQ(0, applypatch_check(nonexistent_file.c_str(), sha1s_single));
 }
 
-TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedMultiple) {
-  mangle_file(old_file);
-  std::vector<std::string> sha1s = { bad_sha1_a, old_sha1, bad_sha1_b };
-  ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
+TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedSourceMultiple) {
+  TemporaryFile temp_file;
+  mangle_file(temp_file.path);
+  std::vector<std::string> sha1s_multiple = { bad_sha1_a, old_sha1, bad_sha1_b };
+  ASSERT_EQ(0, applypatch_check(temp_file.path, sha1s_multiple));
+  ASSERT_EQ(0, applypatch_check(nonexistent_file.c_str(), sha1s_multiple));
 }
 
-TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedFailure) {
-  mangle_file(old_file);
-  std::vector<std::string> sha1s = { bad_sha1_a, bad_sha1_b };
-  ASSERT_NE(0, applypatch_check(&old_file[0], sha1s));
+TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedSourceFailure) {
+  TemporaryFile temp_file;
+  mangle_file(temp_file.path);
+  std::vector<std::string> sha1s_failure = { bad_sha1_a, bad_sha1_b };
+  ASSERT_NE(0, applypatch_check(temp_file.path, sha1s_failure));
+  ASSERT_NE(0, applypatch_check(nonexistent_file.c_str(), sha1s_failure));
 }
 
-TEST_F(ApplyPatchCacheTest, CheckCacheMissingSingle) {
-  unlink(&old_file[0]);
-  std::vector<std::string> sha1s = { old_sha1 };
-  ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
-}
-
-TEST_F(ApplyPatchCacheTest, CheckCacheMissingMultiple) {
-  unlink(&old_file[0]);
-  std::vector<std::string> sha1s = { bad_sha1_a, old_sha1, bad_sha1_b };
-  ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
-}
-
-TEST_F(ApplyPatchCacheTest, CheckCacheMissingFailure) {
-  unlink(&old_file[0]);
-  std::vector<std::string> sha1s = { bad_sha1_a, bad_sha1_b };
-  ASSERT_NE(0, applypatch_check(&old_file[0], sha1s));
-}
-
-TEST(ApplyPatchModesTest, InvalidArgs) {
+TEST_F(ApplyPatchModesTest, InvalidArgs) {
   // At least two args (including the filename).
   ASSERT_EQ(2, applypatch_modes(1, (const char* []){ "applypatch" }));
 
@@ -233,7 +194,7 @@
   ASSERT_EQ(2, applypatch_modes(2, (const char* []){ "applypatch", "-x" }));
 }
 
-TEST(ApplyPatchModesTest, PatchModeEmmcTarget) {
+TEST_F(ApplyPatchModesTest, PatchModeEmmcTarget) {
   std::string boot_img = from_testdata_base("boot.img");
   size_t boot_img_size;
   std::string boot_img_sha1;
@@ -303,7 +264,7 @@
   ASSERT_EQ(0, applypatch_modes(args3.size(), args3.data()));
 }
 
-TEST(ApplyPatchModesTest, PatchModeInvalidArgs) {
+TEST_F(ApplyPatchModesTest, PatchModeInvalidArgs) {
   // Invalid bonus file.
   ASSERT_NE(0, applypatch_modes(3, (const char* []){ "applypatch", "-b", "/doesntexist" }));
 
@@ -364,11 +325,11 @@
   ASSERT_NE(0, applypatch_modes(args6.size(), args6.data()));
 }
 
-TEST(ApplyPatchModesTest, CheckModeInvalidArgs) {
+TEST_F(ApplyPatchModesTest, CheckModeInvalidArgs) {
   // Insufficient args.
   ASSERT_EQ(2, applypatch_modes(2, (const char* []){ "applypatch", "-c" }));
 }
 
-TEST(ApplyPatchModesTest, ShowLicenses) {
+TEST_F(ApplyPatchModesTest, ShowLicenses) {
   ASSERT_EQ(0, applypatch_modes(2, (const char* []){ "applypatch", "-l" }));
 }
diff --git a/tests/component/bootloader_message_test.cpp b/tests/component/bootloader_message_test.cpp
index b38bc71..6cc59a4 100644
--- a/tests/component/bootloader_message_test.cpp
+++ b/tests/component/bootloader_message_test.cpp
@@ -18,53 +18,12 @@
 #include <vector>
 
 #include <android-base/strings.h>
+#include <android-base/test_utils.h>
 #include <bootloader_message/bootloader_message.h>
 #include <gtest/gtest.h>
 
-class BootloaderMessageTest : public ::testing::Test {
- protected:
-  BootloaderMessageTest() : has_misc(true) {}
-
-  virtual void SetUp() override {
-    std::string err;
-    has_misc = !get_bootloader_message_blk_device(&err).empty();
-  }
-
-  virtual void TearDown() override {
-    // Clear the BCB.
-    if (has_misc) {
-      std::string err;
-      ASSERT_TRUE(clear_bootloader_message(&err)) << "Failed to clear BCB: " << err;
-    }
-  }
-
-  bool has_misc;
-};
-
-TEST_F(BootloaderMessageTest, clear_bootloader_message) {
-  if (!has_misc) {
-    GTEST_LOG_(INFO) << "Test skipped due to no /misc partition found on the device.";
-    return;
-  }
-
-  // Clear the BCB.
-  std::string err;
-  ASSERT_TRUE(clear_bootloader_message(&err)) << "Failed to clear BCB: " << err;
-
-  // Verify the content.
-  bootloader_message boot;
-  ASSERT_TRUE(read_bootloader_message(&boot, &err)) << "Failed to read BCB: " << err;
-
-  // All the bytes should be cleared.
-  ASSERT_EQ(std::string(sizeof(boot), '\0'),
-            std::string(reinterpret_cast<const char*>(&boot), sizeof(boot)));
-}
-
-TEST_F(BootloaderMessageTest, read_and_write_bootloader_message) {
-  if (!has_misc) {
-    GTEST_LOG_(INFO) << "Test skipped due to no /misc partition found on the device.";
-    return;
-  }
+TEST(BootloaderMessageTest, read_and_write_bootloader_message) {
+  TemporaryFile temp_misc;
 
   // Write the BCB.
   bootloader_message boot = {};
@@ -73,90 +32,71 @@
   strlcpy(boot.status, "status1", sizeof(boot.status));
 
   std::string err;
-  ASSERT_TRUE(write_bootloader_message(boot, &err)) << "Failed to write BCB: " << err;
+  ASSERT_TRUE(write_bootloader_message_to(boot, temp_misc.path, &err))
+      << "Failed to write BCB: " << err;
 
   // Read and verify.
   bootloader_message boot_verify;
-  ASSERT_TRUE(read_bootloader_message(&boot_verify, &err)) << "Failed to read BCB: " << err;
+  ASSERT_TRUE(read_bootloader_message_from(&boot_verify, temp_misc.path, &err))
+      << "Failed to read BCB: " << err;
 
   ASSERT_EQ(std::string(reinterpret_cast<const char*>(&boot), sizeof(boot)),
             std::string(reinterpret_cast<const char*>(&boot_verify), sizeof(boot_verify)));
 }
 
-TEST_F(BootloaderMessageTest, write_bootloader_message_options) {
-  if (!has_misc) {
-    GTEST_LOG_(INFO) << "Test skipped due to no /misc partition found on the device.";
-    return;
-  }
-
+TEST(BootloaderMessageTest, update_bootloader_message_in_struct) {
   // Write the options to BCB.
   std::vector<std::string> options = { "option1", "option2" };
-  std::string err;
-  ASSERT_TRUE(write_bootloader_message(options, &err)) << "Failed to write BCB: " << err;
 
-  // Inject some bytes into boot, which should be overwritten while reading.
-  bootloader_message boot;
+  bootloader_message boot = {};
+  // Inject some bytes into boot.
   strlcpy(boot.recovery, "random message", sizeof(boot.recovery));
+  strlcpy(boot.status, "status bytes", sizeof(boot.status));
+  strlcpy(boot.stage, "stage bytes", sizeof(boot.stage));
   strlcpy(boot.reserved, "reserved bytes", sizeof(boot.reserved));
 
-  ASSERT_TRUE(read_bootloader_message(&boot, &err)) << "Failed to read BCB: " << err;
+  ASSERT_TRUE(update_bootloader_message_in_struct(&boot, options));
 
   // Verify that command and recovery fields should be set.
   ASSERT_EQ("boot-recovery", std::string(boot.command));
   std::string expected = "recovery\n" + android::base::Join(options, "\n") + "\n";
   ASSERT_EQ(expected, std::string(boot.recovery));
 
-  // The rest should be cleared.
-  ASSERT_EQ(std::string(sizeof(boot.status), '\0'), std::string(boot.status, sizeof(boot.status)));
-  ASSERT_EQ(std::string(sizeof(boot.stage), '\0'), std::string(boot.stage, sizeof(boot.stage)));
-  ASSERT_EQ(std::string(sizeof(boot.reserved), '\0'),
-            std::string(boot.reserved, sizeof(boot.reserved)));
+  // The rest should be intact.
+  ASSERT_EQ("status bytes", std::string(boot.status));
+  ASSERT_EQ("stage bytes", std::string(boot.stage));
+  ASSERT_EQ("reserved bytes", std::string(boot.reserved));
 }
 
-TEST_F(BootloaderMessageTest, write_bootloader_message_options_empty) {
-  if (!has_misc) {
-    GTEST_LOG_(INFO) << "Test skipped due to no /misc partition found on the device.";
-    return;
-  }
-
+TEST(BootloaderMessageTest, update_bootloader_message_recovery_options_empty) {
   // Write empty vector.
   std::vector<std::string> options;
-  std::string err;
-  ASSERT_TRUE(write_bootloader_message(options, &err)) << "Failed to write BCB: " << err;
 
   // Read and verify.
-  bootloader_message boot;
-  ASSERT_TRUE(read_bootloader_message(&boot, &err)) << "Failed to read BCB: " << err;
+  bootloader_message boot = {};
+  ASSERT_TRUE(update_bootloader_message_in_struct(&boot, options));
 
   // command and recovery fields should be set.
   ASSERT_EQ("boot-recovery", std::string(boot.command));
   ASSERT_EQ("recovery\n", std::string(boot.recovery));
 
-  // The rest should be cleared.
+  // The rest should be empty.
   ASSERT_EQ(std::string(sizeof(boot.status), '\0'), std::string(boot.status, sizeof(boot.status)));
   ASSERT_EQ(std::string(sizeof(boot.stage), '\0'), std::string(boot.stage, sizeof(boot.stage)));
   ASSERT_EQ(std::string(sizeof(boot.reserved), '\0'),
             std::string(boot.reserved, sizeof(boot.reserved)));
 }
 
-TEST_F(BootloaderMessageTest, write_bootloader_message_options_long) {
-  if (!has_misc) {
-    GTEST_LOG_(INFO) << "Test skipped due to no /misc partition found on the device.";
-    return;
-  }
-
+TEST(BootloaderMessageTest, update_bootloader_message_recovery_options_long) {
   // Write super long message.
   std::vector<std::string> options;
   for (int i = 0; i < 100; i++) {
     options.push_back("option: " + std::to_string(i));
   }
 
-  std::string err;
-  ASSERT_TRUE(write_bootloader_message(options, &err)) << "Failed to write BCB: " << err;
-
   // Read and verify.
-  bootloader_message boot;
-  ASSERT_TRUE(read_bootloader_message(&boot, &err)) << "Failed to read BCB: " << err;
+  bootloader_message boot = {};
+  ASSERT_TRUE(update_bootloader_message_in_struct(&boot, options));
 
   // Make sure it's long enough.
   std::string expected = "recovery\n" + android::base::Join(options, "\n") + "\n";
@@ -167,40 +107,10 @@
   ASSERT_EQ(expected.substr(0, sizeof(boot.recovery) - 1), std::string(boot.recovery));
   ASSERT_EQ('\0', boot.recovery[sizeof(boot.recovery) - 1]);
 
-  // The rest should be cleared.
+  // The rest should be empty.
   ASSERT_EQ(std::string(sizeof(boot.status), '\0'), std::string(boot.status, sizeof(boot.status)));
   ASSERT_EQ(std::string(sizeof(boot.stage), '\0'), std::string(boot.stage, sizeof(boot.stage)));
   ASSERT_EQ(std::string(sizeof(boot.reserved), '\0'),
             std::string(boot.reserved, sizeof(boot.reserved)));
 }
 
-TEST_F(BootloaderMessageTest, update_bootloader_message) {
-  if (!has_misc) {
-    GTEST_LOG_(INFO) << "Test skipped due to no /misc partition found on the device.";
-    return;
-  }
-
-  // Inject some bytes into boot, which should be not overwritten later.
-  bootloader_message boot;
-  strlcpy(boot.recovery, "random message", sizeof(boot.recovery));
-  strlcpy(boot.reserved, "reserved bytes", sizeof(boot.reserved));
-  std::string err;
-  ASSERT_TRUE(write_bootloader_message(boot, &err)) << "Failed to write BCB: " << err;
-
-  // Update the BCB message.
-  std::vector<std::string> options = { "option1", "option2" };
-  ASSERT_TRUE(update_bootloader_message(options, &err)) << "Failed to update BCB: " << err;
-
-  bootloader_message boot_verify;
-  ASSERT_TRUE(read_bootloader_message(&boot_verify, &err)) << "Failed to read BCB: " << err;
-
-  // Verify that command and recovery fields should be set.
-  ASSERT_EQ("boot-recovery", std::string(boot_verify.command));
-  std::string expected = "recovery\n" + android::base::Join(options, "\n") + "\n";
-  ASSERT_EQ(expected, std::string(boot_verify.recovery));
-
-  // The rest should be intact.
-  ASSERT_EQ(std::string(boot.status), std::string(boot_verify.status));
-  ASSERT_EQ(std::string(boot.stage), std::string(boot_verify.stage));
-  ASSERT_EQ(std::string(boot.reserved), std::string(boot_verify.reserved));
-}
diff --git a/tests/component/uncrypt_test.cpp b/tests/component/uncrypt_test.cpp
index 3925236..55baca2 100644
--- a/tests/component/uncrypt_test.cpp
+++ b/tests/component/uncrypt_test.cpp
@@ -20,6 +20,7 @@
 #include <sys/un.h>
 #include <unistd.h>
 
+#include <algorithm>
 #include <string>
 
 #include <android-base/file.h>
@@ -38,43 +39,49 @@
 static const std::string INIT_SVC_UNCRYPT = "init.svc.uncrypt";
 static constexpr int SOCKET_CONNECTION_MAX_RETRY = 30;
 
+static void StopService() {
+  ASSERT_TRUE(android::base::SetProperty("ctl.stop", "setup-bcb"));
+  ASSERT_TRUE(android::base::SetProperty("ctl.stop", "clear-bcb"));
+  ASSERT_TRUE(android::base::SetProperty("ctl.stop", "uncrypt"));
+
+  bool success = false;
+  for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) {
+    std::string setup_bcb = android::base::GetProperty(INIT_SVC_SETUP_BCB, "");
+    std::string clear_bcb = android::base::GetProperty(INIT_SVC_CLEAR_BCB, "");
+    std::string uncrypt = android::base::GetProperty(INIT_SVC_UNCRYPT, "");
+    GTEST_LOG_(INFO) << "setup-bcb: [" << setup_bcb << "] clear-bcb: [" << clear_bcb
+                     << "] uncrypt: [" << uncrypt << "]";
+    if (setup_bcb != "running" && clear_bcb != "running" && uncrypt != "running") {
+      success = true;
+      break;
+    }
+    sleep(1);
+  }
+
+  ASSERT_TRUE(success) << "uncrypt service is not available.";
+}
+
 class UncryptTest : public ::testing::Test {
  protected:
   UncryptTest() : has_misc(true) {}
 
-  virtual void SetUp() override {
-    ASSERT_TRUE(android::base::SetProperty("ctl.stop", "setup-bcb"));
-    ASSERT_TRUE(android::base::SetProperty("ctl.stop", "clear-bcb"));
-    ASSERT_TRUE(android::base::SetProperty("ctl.stop", "uncrypt"));
-
-    bool success = false;
-    for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) {
-      std::string setup_bcb = android::base::GetProperty(INIT_SVC_SETUP_BCB, "");
-      std::string clear_bcb = android::base::GetProperty(INIT_SVC_CLEAR_BCB, "");
-      std::string uncrypt = android::base::GetProperty(INIT_SVC_UNCRYPT, "");
-      LOG(INFO) << "setup-bcb: [" << setup_bcb << "] clear-bcb: [" << clear_bcb << "] uncrypt: ["
-                << uncrypt << "]";
-      if (setup_bcb != "running" && clear_bcb != "running" && uncrypt != "running") {
-        success = true;
-        break;
-      }
-      sleep(1);
-    }
-
-    ASSERT_TRUE(success) << "uncrypt service is not available.";
-
+  void SetUp() override {
     std::string err;
     has_misc = !get_bootloader_message_blk_device(&err).empty();
   }
 
+  void TearDown() override {
+    // Clear the BCB.
+    if (has_misc) {
+      std::string err;
+      ASSERT_TRUE(clear_bootloader_message(&err)) << "Failed to clear BCB: " << err;
+    }
+  }
+
   void SetupOrClearBcb(bool isSetup, const std::string& message,
                        const std::string& message_in_bcb) const {
-    if (!has_misc) {
-      GTEST_LOG_(INFO) << "Test skipped due to no /misc partition found on the device.";
-      return;
-    }
-
-    // Trigger the setup-bcb service.
+    // Restart the setup-bcb service.
+    StopService();
     ASSERT_TRUE(android::base::SetProperty("ctl.start", isSetup ? "setup-bcb" : "clear-bcb"));
 
     // Test tends to be flaky if proceeding immediately ("Transport endpoint is not connected").
@@ -144,27 +151,49 @@
     }
   }
 
+  void VerifyBootloaderMessage(const std::string& expected) {
+    std::string err;
+    bootloader_message boot;
+    ASSERT_TRUE(read_bootloader_message(&boot, &err)) << "Failed to read BCB: " << err;
+
+    // Check that we have all the expected bytes.
+    ASSERT_EQ(expected, std::string(reinterpret_cast<const char*>(&boot), sizeof(boot)));
+  }
+
   bool has_misc;
 };
 
 TEST_F(UncryptTest, setup_bcb) {
+  if (!has_misc) {
+    GTEST_LOG_(INFO) << "Test skipped due to no /misc partition found on the device.";
+    return;
+  }
+
+  std::string random_data;
+  random_data.reserve(sizeof(bootloader_message));
+  generate_n(back_inserter(random_data), sizeof(bootloader_message), []() { return rand() % 128; });
+
+  bootloader_message boot;
+  memcpy(&boot, random_data.c_str(), random_data.size());
+
+  std::string err;
+  ASSERT_TRUE(write_bootloader_message(boot, &err)) << "Failed to write BCB: " << err;
+  VerifyBootloaderMessage(random_data);
+
+  ASSERT_TRUE(clear_bootloader_message(&err)) << "Failed to clear BCB: " << err;
+  VerifyBootloaderMessage(std::string(sizeof(bootloader_message), '\0'));
+
   std::string message = "--update_message=abc value";
   std::string message_in_bcb = "recovery\n--update_message=abc value\n";
   SetupOrClearBcb(true, message, message_in_bcb);
-}
 
-TEST_F(UncryptTest, clear_bcb) {
   SetupOrClearBcb(false, "", "");
-}
 
-TEST_F(UncryptTest, setup_bcb_wipe_ab) {
   TemporaryFile wipe_package;
   ASSERT_TRUE(android::base::WriteStringToFile(std::string(345, 'a'), wipe_package.path));
 
   // It's expected to store a wipe package in /misc, with the package size passed to recovery.
-  std::string message =
-      "--wipe_ab\n--wipe_package="s + wipe_package.path + "\n--reason=wipePackage"s;
-  std::string message_in_bcb =
-      "recovery\n--wipe_ab\n--wipe_package_size=345\n--reason=wipePackage\n";
+  message = "--wipe_ab\n--wipe_package="s + wipe_package.path + "\n--reason=wipePackage"s;
+  message_in_bcb = "recovery\n--wipe_ab\n--wipe_package_size=345\n--reason=wipePackage\n";
   SetupOrClearBcb(true, message, message_in_bcb);
 }