Merge "fastboot: Use copy constructor to copy fastboot match callback"
diff --git a/fastboot/README.md b/fastboot/README.md
index d3b6c1a..63db5c3 100644
--- a/fastboot/README.md
+++ b/fastboot/README.md
@@ -29,20 +29,27 @@
 
 2. Client response with a single packet no greater than 256 bytes.
    The first four bytes of the response are "OKAY", "FAIL", "DATA",
-   or "INFO".  Additional bytes may contain an (ascii) informative
+   "INFO" or "TEXT".  Additional bytes may contain an (ascii) informative
    message.
 
    a. INFO -> the remaining 252 bytes are an informative message
       (providing progress or diagnostic messages).  They should
-      be displayed and then step #2 repeats
+      be displayed and then step #2 repeats. The print format is:
+      "(bootloader) " + InfoMessagePayload + '\n'
 
-   b. FAIL -> the requested command failed.  The remaining 252 bytes
+   b. TEXT -> the remaining 252 bytes are arbitrary. They should
+      be displayed and then step #2 repeats.
+      It differs from info in that no formatting is applied.
+      The payload is printed as-is with no newline at the end.
+      Payload is expected to be NULL terminated.
+
+   c. FAIL -> the requested command failed.  The remaining 252 bytes
       of the response (if present) provide a textual failure message
       to present to the user.  Stop.
 
-   c. OKAY -> the requested command completed successfully.  Go to #5
+   d. OKAY -> the requested command completed successfully.  Go to #5
 
-   d. DATA -> the requested command is ready for the data phase.
+   e. DATA -> the requested command is ready for the data phase.
       A DATA response packet will be 12 bytes long, in the form of
       DATA00000000 where the 8 digit hexadecimal number represents
       the total data size to transfer.
@@ -54,15 +61,17 @@
    in the "DATA" response above.
 
 4. Client responds with a single packet no greater than 256 bytes.
-   The first four bytes of the response are "OKAY", "FAIL", or "INFO".
-   Similar to #2:
+   The first four bytes of the response are "OKAY", "FAIL",
+   "INFO" or "TEXT". Similar to #2:
 
-   a. INFO -> display the remaining 252 bytes and return to #4
+   a. INFO -> display the formatted remaining 252 bytes and return to #4
 
-   b. FAIL -> display the remaining 252 bytes (if present) as a failure
+   b. TEXT -> display the unformatted remaining 252 bytes and return to #4
+
+   c. FAIL -> display the remaining 252 bytes (if present) as a failure
       reason and consider the command failed.  Stop.
 
-   c. OKAY -> success.  Go to #5
+   d. OKAY -> success.  Go to #5
 
 5. Success.  Stop.
 
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index c9cb228..799c9f9 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -255,6 +255,10 @@
     fprintf(stderr, "(bootloader) %s\n", info.c_str());
 }
 
+static void TextMessage(const std::string& text) {
+    fprintf(stderr, "%s", text.c_str());
+}
+
 bool ReadFileToVector(const std::string& file, std::vector<char>* out) {
     out->clear();
 
@@ -428,7 +432,7 @@
         transport = open_device(device.c_str(), false, false);
 
         if (print) {
-            PrintDevice(device.c_str(), transport == nullptr ? "offline" : "device");
+            PrintDevice(device.c_str(), transport == nullptr ? "offline" : "fastboot");
         }
 
         if (transport != nullptr) {
@@ -2305,7 +2309,9 @@
             .prolog = Status,
             .epilog = Epilog,
             .info = InfoMessage,
+            .text = TextMessage,
     };
+
     fastboot::FastBootDriver fastboot_driver(transport, driver_callbacks, false);
     fb = &fastboot_driver;
 
diff --git a/fastboot/fastboot_driver.cpp b/fastboot/fastboot_driver.cpp
index 99a4873..9770ab2 100644
--- a/fastboot/fastboot_driver.cpp
+++ b/fastboot/fastboot_driver.cpp
@@ -64,6 +64,7 @@
       prolog_(std::move(driver_callbacks.prolog)),
       epilog_(std::move(driver_callbacks.epilog)),
       info_(std::move(driver_callbacks.info)),
+      text_(std::move(driver_callbacks.text)),
       disable_checks_(no_checks) {}
 
 FastBootDriver::~FastBootDriver() {
@@ -498,6 +499,10 @@
             error_ = android::base::StringPrintf("remote: '%s'", status + strlen("FAIL"));
             set_response(input.substr(strlen("FAIL")));
             return DEVICE_FAIL;
+        } else if (android::base::StartsWith(input, "TEXT")) {
+            text_(input.substr(strlen("TEXT")));
+            // Reset timeout as many more TEXT may come
+            start = std::chrono::steady_clock::now();
         } else if (android::base::StartsWith(input, "DATA")) {
             std::string tmp = input.substr(strlen("DATA"));
             uint32_t num = strtol(tmp.c_str(), 0, 16);
diff --git a/fastboot/fastboot_driver.h b/fastboot/fastboot_driver.h
index b422c91..f60c9f1 100644
--- a/fastboot/fastboot_driver.h
+++ b/fastboot/fastboot_driver.h
@@ -60,6 +60,7 @@
     std::function<void(const std::string&)> prolog = [](const std::string&) {};
     std::function<void(int)> epilog = [](int) {};
     std::function<void(const std::string&)> info = [](const std::string&) {};
+    std::function<void(const std::string&)> text = [](const std::string&) {};
 };
 
 class FastBootDriver {
@@ -169,6 +170,7 @@
     std::function<void(const std::string&)> prolog_;
     std::function<void(int)> epilog_;
     std::function<void(const std::string&)> info_;
+    std::function<void(const std::string&)> text_;
     bool disable_checks_;
 };
 
diff --git a/fastboot/fastboot_driver_test.cpp b/fastboot/fastboot_driver_test.cpp
index e874c3a..6f6cf8c 100644
--- a/fastboot/fastboot_driver_test.cpp
+++ b/fastboot/fastboot_driver_test.cpp
@@ -58,3 +58,38 @@
     ASSERT_EQ(info.size(), size_t(1));
     ASSERT_EQ(info[0], "this is an info line");
 }
+
+TEST_F(DriverTest, TextMessage) {
+    MockTransport transport;
+    std::string text;
+
+    DriverCallbacks callbacks{[](const std::string&) {}, [](int) {}, [](const std::string&) {},
+                              [&text](const std::string& extra_text) { text += extra_text; }};
+
+    FastBootDriver driver(&transport, callbacks);
+
+    EXPECT_CALL(transport, Write(_, _))
+            .With(AllArgs(RawData("oem trusty runtest trusty.hwaes.bench")))
+            .WillOnce(ReturnArg<1>());
+    EXPECT_CALL(transport, Read(_, _)).WillOnce(Invoke(CopyData("TEXTthis is a text line")));
+    EXPECT_CALL(transport, Read(_, _))
+            .WillOnce(Invoke(
+                    CopyData("TEXT, albeit very long and split over multiple TEXT messages.")));
+    EXPECT_CALL(transport, Read(_, _))
+            .WillOnce(Invoke(CopyData("TEXT Indeed we can do that now with a TEXT message whenever "
+                                      "we feel like it.")));
+    EXPECT_CALL(transport, Read(_, _))
+            .WillOnce(Invoke(CopyData("TEXT Isn't that truly super cool?")));
+
+    EXPECT_CALL(transport, Read(_, _)).WillOnce(Invoke(CopyData("OKAY")));
+
+    std::vector<std::string> info;
+    ASSERT_EQ(driver.RawCommand("oem trusty runtest trusty.hwaes.bench", "", nullptr, &info),
+              SUCCESS)
+            << driver.Error();
+    ASSERT_EQ(text,
+              "this is a text line"
+              ", albeit very long and split over multiple TEXT messages."
+              " Indeed we can do that now with a TEXT message whenever we feel like it."
+              " Isn't that truly super cool?");
+}
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
index d670f1e..1421403 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
@@ -99,9 +99,9 @@
     bool valid_;
 };
 
-class SnapuserTest final {
+class SnapuserdTest : public ::testing::Test {
   public:
-    bool Setup();
+    bool SetupDefault();
     bool SetupOrderedOps();
     bool SetupOrderedOpsInverted();
     bool SetupCopyOverlap_1();
@@ -118,6 +118,10 @@
 
     static const uint64_t kSectorSize = 512;
 
+  protected:
+    void SetUp() override {}
+    void TearDown() override { Shutdown(); }
+
   private:
     void SetupImpl();
 
@@ -172,7 +176,7 @@
     return fd;
 }
 
-void SnapuserTest::Shutdown() {
+void SnapuserdTest::Shutdown() {
     ASSERT_TRUE(dmuser_dev_->Destroy());
 
     auto misc_device = "/dev/dm-user/" + system_device_ctrl_name_;
@@ -181,36 +185,36 @@
     ASSERT_TRUE(client_->DetachSnapuserd());
 }
 
-bool SnapuserTest::Setup() {
+bool SnapuserdTest::SetupDefault() {
     SetupImpl();
     return setup_ok_;
 }
 
-bool SnapuserTest::SetupOrderedOps() {
+bool SnapuserdTest::SetupOrderedOps() {
     CreateBaseDevice();
     CreateCowDeviceOrderedOps();
     return SetupDaemon();
 }
 
-bool SnapuserTest::SetupOrderedOpsInverted() {
+bool SnapuserdTest::SetupOrderedOpsInverted() {
     CreateBaseDevice();
     CreateCowDeviceOrderedOpsInverted();
     return SetupDaemon();
 }
 
-bool SnapuserTest::SetupCopyOverlap_1() {
+bool SnapuserdTest::SetupCopyOverlap_1() {
     CreateBaseDevice();
     CreateCowDeviceWithCopyOverlap_1();
     return SetupDaemon();
 }
 
-bool SnapuserTest::SetupCopyOverlap_2() {
+bool SnapuserdTest::SetupCopyOverlap_2() {
     CreateBaseDevice();
     CreateCowDeviceWithCopyOverlap_2();
     return SetupDaemon();
 }
 
-bool SnapuserTest::SetupDaemon() {
+bool SnapuserdTest::SetupDaemon() {
     SetDeviceControlName();
 
     StartSnapuserdDaemon();
@@ -224,7 +228,7 @@
     return setup_ok_;
 }
 
-void SnapuserTest::StartSnapuserdDaemon() {
+void SnapuserdTest::StartSnapuserdDaemon() {
     pid_t pid = fork();
     ASSERT_GE(pid, 0);
     if (pid == 0) {
@@ -238,7 +242,7 @@
     }
 }
 
-void SnapuserTest::CreateBaseDevice() {
+void SnapuserdTest::CreateBaseDevice() {
     unique_fd rnd_fd;
 
     total_base_size_ = (size_ * 5);
@@ -261,7 +265,7 @@
     ASSERT_TRUE(base_loop_->valid());
 }
 
-void SnapuserTest::ReadSnapshotDeviceAndValidate() {
+void SnapuserdTest::ReadSnapshotDeviceAndValidate() {
     unique_fd fd(open(dmuser_dev_->path().c_str(), O_RDONLY));
     ASSERT_GE(fd, 0);
     std::unique_ptr<uint8_t[]> snapuserd_buffer = std::make_unique<uint8_t[]>(size_);
@@ -292,7 +296,7 @@
     ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + (size_ * 4), size_), 0);
 }
 
-void SnapuserTest::CreateCowDeviceWithCopyOverlap_2() {
+void SnapuserdTest::CreateCowDeviceWithCopyOverlap_2() {
     std::string path = android::base::GetExecutableDirectory();
     cow_system_ = std::make_unique<TemporaryFile>(path);
 
@@ -344,7 +348,7 @@
     }
 }
 
-void SnapuserTest::CreateCowDeviceWithCopyOverlap_1() {
+void SnapuserdTest::CreateCowDeviceWithCopyOverlap_1() {
     std::string path = android::base::GetExecutableDirectory();
     cow_system_ = std::make_unique<TemporaryFile>(path);
 
@@ -387,7 +391,7 @@
               true);
 }
 
-void SnapuserTest::CreateCowDeviceOrderedOpsInverted() {
+void SnapuserdTest::CreateCowDeviceOrderedOpsInverted() {
     unique_fd rnd_fd;
     loff_t offset = 0;
 
@@ -450,7 +454,7 @@
     }
 }
 
-void SnapuserTest::CreateCowDeviceOrderedOps() {
+void SnapuserdTest::CreateCowDeviceOrderedOps() {
     unique_fd rnd_fd;
     loff_t offset = 0;
 
@@ -511,7 +515,7 @@
     }
 }
 
-void SnapuserTest::CreateCowDevice() {
+void SnapuserdTest::CreateCowDevice() {
     unique_fd rnd_fd;
     loff_t offset = 0;
 
@@ -601,13 +605,13 @@
     }
 }
 
-void SnapuserTest::InitCowDevice() {
+void SnapuserdTest::InitCowDevice() {
     uint64_t num_sectors = client_->InitDmUserCow(system_device_ctrl_name_, cow_system_->path,
                                                   base_loop_->device(), base_loop_->device());
     ASSERT_NE(num_sectors, 0);
 }
 
-void SnapuserTest::SetDeviceControlName() {
+void SnapuserdTest::SetDeviceControlName() {
     system_device_name_.clear();
     system_device_ctrl_name_.clear();
 
@@ -619,7 +623,7 @@
     system_device_ctrl_name_ = system_device_name_ + "-ctrl";
 }
 
-void SnapuserTest::CreateDmUserDevice() {
+void SnapuserdTest::CreateDmUserDevice() {
     unique_fd fd(TEMP_FAILURE_RETRY(open(base_loop_->device().c_str(), O_RDONLY | O_CLOEXEC)));
     ASSERT_TRUE(fd > 0);
 
@@ -641,12 +645,12 @@
     ASSERT_TRUE(android::fs_mgr::WaitForFile(misc_device, 10s));
 }
 
-void SnapuserTest::InitDaemon() {
+void SnapuserdTest::InitDaemon() {
     bool ok = client_->AttachDmUser(system_device_ctrl_name_);
     ASSERT_TRUE(ok);
 }
 
-void SnapuserTest::CheckMergeCompletion() {
+void SnapuserdTest::CheckMergeCompletion() {
     while (true) {
         double percentage = client_->GetMergePercent();
         if ((int)percentage == 100) {
@@ -657,7 +661,7 @@
     }
 }
 
-void SnapuserTest::SetupImpl() {
+void SnapuserdTest::SetupImpl() {
     CreateBaseDevice();
     CreateCowDevice();
 
@@ -672,26 +676,26 @@
     setup_ok_ = true;
 }
 
-bool SnapuserTest::Merge() {
+bool SnapuserdTest::Merge() {
     StartMerge();
     CheckMergeCompletion();
     merge_ok_ = true;
     return merge_ok_;
 }
 
-void SnapuserTest::StartMerge() {
+void SnapuserdTest::StartMerge() {
     bool ok = client_->InitiateMerge(system_device_ctrl_name_);
     ASSERT_TRUE(ok);
 }
 
-void SnapuserTest::ValidateMerge() {
+void SnapuserdTest::ValidateMerge() {
     merged_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
     ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, merged_buffer_.get(), total_base_size_, 0),
               true);
     ASSERT_EQ(memcmp(merged_buffer_.get(), orig_buffer_.get(), total_base_size_), 0);
 }
 
-void SnapuserTest::SimulateDaemonRestart() {
+void SnapuserdTest::SimulateDaemonRestart() {
     Shutdown();
     std::this_thread::sleep_for(500ms);
     SetDeviceControlName();
@@ -701,7 +705,7 @@
     InitDaemon();
 }
 
-void SnapuserTest::MergeInterruptRandomly(int max_duration) {
+void SnapuserdTest::MergeInterruptRandomly(int max_duration) {
     std::srand(std::time(nullptr));
     StartMerge();
 
@@ -716,7 +720,7 @@
     ASSERT_TRUE(Merge());
 }
 
-void SnapuserTest::MergeInterruptFixed(int duration) {
+void SnapuserdTest::MergeInterruptFixed(int duration) {
     StartMerge();
 
     for (int i = 0; i < 25; i++) {
@@ -729,7 +733,7 @@
     ASSERT_TRUE(Merge());
 }
 
-void SnapuserTest::MergeInterrupt() {
+void SnapuserdTest::MergeInterrupt() {
     // Interrupt merge at various intervals
     StartMerge();
     std::this_thread::sleep_for(250ms);
@@ -758,104 +762,93 @@
     ASSERT_TRUE(Merge());
 }
 
-TEST(Snapuserd_Test, Snapshot_IO_TEST) {
-    SnapuserTest harness;
-    ASSERT_TRUE(harness.Setup());
+TEST_F(SnapuserdTest, Snapshot_IO_TEST) {
+    ASSERT_TRUE(SetupDefault());
     // I/O before merge
-    harness.ReadSnapshotDeviceAndValidate();
-    ASSERT_TRUE(harness.Merge());
-    harness.ValidateMerge();
+    ReadSnapshotDeviceAndValidate();
+    ASSERT_TRUE(Merge());
+    ValidateMerge();
     // I/O after merge - daemon should read directly
     // from base device
-    harness.ReadSnapshotDeviceAndValidate();
-    harness.Shutdown();
+    ReadSnapshotDeviceAndValidate();
+    Shutdown();
 }
 
-TEST(Snapuserd_Test, Snapshot_MERGE_IO_TEST) {
-    SnapuserTest harness;
-    ASSERT_TRUE(harness.Setup());
+TEST_F(SnapuserdTest, Snapshot_MERGE_IO_TEST) {
+    ASSERT_TRUE(SetupDefault());
     // Issue I/O before merge begins
-    std::async(std::launch::async, &SnapuserTest::ReadSnapshotDeviceAndValidate, &harness);
+    std::async(std::launch::async, &SnapuserdTest::ReadSnapshotDeviceAndValidate, this);
     // Start the merge
-    ASSERT_TRUE(harness.Merge());
-    harness.ValidateMerge();
-    harness.Shutdown();
+    ASSERT_TRUE(Merge());
+    ValidateMerge();
+    Shutdown();
 }
 
-TEST(Snapuserd_Test, Snapshot_MERGE_IO_TEST_1) {
-    SnapuserTest harness;
-    ASSERT_TRUE(harness.Setup());
+TEST_F(SnapuserdTest, Snapshot_MERGE_IO_TEST_1) {
+    ASSERT_TRUE(SetupDefault());
     // Start the merge
-    harness.StartMerge();
+    StartMerge();
     // Issue I/O in parallel when merge is in-progress
-    std::async(std::launch::async, &SnapuserTest::ReadSnapshotDeviceAndValidate, &harness);
-    harness.CheckMergeCompletion();
-    harness.ValidateMerge();
-    harness.Shutdown();
+    std::async(std::launch::async, &SnapuserdTest::ReadSnapshotDeviceAndValidate, this);
+    CheckMergeCompletion();
+    ValidateMerge();
+    Shutdown();
 }
 
-TEST(Snapuserd_Test, Snapshot_Merge_Resume) {
-    SnapuserTest harness;
-    ASSERT_TRUE(harness.Setup());
-    harness.MergeInterrupt();
-    harness.ValidateMerge();
-    harness.Shutdown();
+TEST_F(SnapuserdTest, Snapshot_Merge_Resume) {
+    ASSERT_TRUE(SetupDefault());
+    MergeInterrupt();
+    ValidateMerge();
+    Shutdown();
 }
 
-TEST(Snapuserd_Test, Snapshot_COPY_Overlap_TEST_1) {
-    SnapuserTest harness;
-    ASSERT_TRUE(harness.SetupCopyOverlap_1());
-    ASSERT_TRUE(harness.Merge());
-    harness.ValidateMerge();
-    harness.Shutdown();
+TEST_F(SnapuserdTest, Snapshot_COPY_Overlap_TEST_1) {
+    ASSERT_TRUE(SetupCopyOverlap_1());
+    ASSERT_TRUE(Merge());
+    ValidateMerge();
+    Shutdown();
 }
 
-TEST(Snapuserd_Test, Snapshot_COPY_Overlap_TEST_2) {
-    SnapuserTest harness;
-    ASSERT_TRUE(harness.SetupCopyOverlap_2());
-    ASSERT_TRUE(harness.Merge());
-    harness.ValidateMerge();
-    harness.Shutdown();
+TEST_F(SnapuserdTest, Snapshot_COPY_Overlap_TEST_2) {
+    ASSERT_TRUE(SetupCopyOverlap_2());
+    ASSERT_TRUE(Merge());
+    ValidateMerge();
+    Shutdown();
 }
 
-TEST(Snapuserd_Test, Snapshot_COPY_Overlap_Merge_Resume_TEST) {
-    SnapuserTest harness;
-    ASSERT_TRUE(harness.SetupCopyOverlap_1());
-    harness.MergeInterrupt();
-    harness.ValidateMerge();
-    harness.Shutdown();
+TEST_F(SnapuserdTest, Snapshot_COPY_Overlap_Merge_Resume_TEST) {
+    ASSERT_TRUE(SetupCopyOverlap_1());
+    MergeInterrupt();
+    ValidateMerge();
+    Shutdown();
 }
 
-TEST(Snapuserd_Test, Snapshot_Merge_Crash_Fixed_Ordered) {
-    SnapuserTest harness;
-    ASSERT_TRUE(harness.SetupOrderedOps());
-    harness.MergeInterruptFixed(300);
-    harness.ValidateMerge();
-    harness.Shutdown();
+TEST_F(SnapuserdTest, Snapshot_Merge_Crash_Fixed_Ordered) {
+    ASSERT_TRUE(SetupOrderedOps());
+    MergeInterruptFixed(300);
+    ValidateMerge();
+    Shutdown();
 }
 
-TEST(Snapuserd_Test, Snapshot_Merge_Crash_Random_Ordered) {
-    SnapuserTest harness;
-    ASSERT_TRUE(harness.SetupOrderedOps());
-    harness.MergeInterruptRandomly(500);
-    harness.ValidateMerge();
-    harness.Shutdown();
+TEST_F(SnapuserdTest, Snapshot_Merge_Crash_Random_Ordered) {
+    ASSERT_TRUE(SetupOrderedOps());
+    MergeInterruptRandomly(500);
+    ValidateMerge();
+    Shutdown();
 }
 
-TEST(Snapuserd_Test, Snapshot_Merge_Crash_Fixed_Inverted) {
-    SnapuserTest harness;
-    ASSERT_TRUE(harness.SetupOrderedOpsInverted());
-    harness.MergeInterruptFixed(50);
-    harness.ValidateMerge();
-    harness.Shutdown();
+TEST_F(SnapuserdTest, Snapshot_Merge_Crash_Fixed_Inverted) {
+    ASSERT_TRUE(SetupOrderedOpsInverted());
+    MergeInterruptFixed(50);
+    ValidateMerge();
+    Shutdown();
 }
 
-TEST(Snapuserd_Test, Snapshot_Merge_Crash_Random_Inverted) {
-    SnapuserTest harness;
-    ASSERT_TRUE(harness.SetupOrderedOpsInverted());
-    harness.MergeInterruptRandomly(50);
-    harness.ValidateMerge();
-    harness.Shutdown();
+TEST_F(SnapuserdTest, Snapshot_Merge_Crash_Random_Inverted) {
+    ASSERT_TRUE(SetupOrderedOpsInverted());
+    MergeInterruptRandomly(50);
+    ValidateMerge();
+    Shutdown();
 }
 
 }  // namespace snapshot
diff --git a/init/init_test.cpp b/init/init_test.cpp
index 7bb5c90..305bf95 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <fstream>
 #include <functional>
 #include <string_view>
 #include <thread>
@@ -22,6 +23,7 @@
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/properties.h>
+#include <android-base/stringprintf.h>
 #include <android/api-level.h>
 #include <gtest/gtest.h>
 #include <selinux/selinux.h>
@@ -44,6 +46,7 @@
 using android::base::GetIntProperty;
 using android::base::GetProperty;
 using android::base::SetProperty;
+using android::base::StringPrintf;
 using android::base::StringReplace;
 using android::base::WaitForProperty;
 using namespace std::literals;
@@ -643,34 +646,32 @@
     ASSERT_LE(curr_limit.rlim_max, max_limit);
 }
 
-static std::vector<const char*> ConvertToArgv(const std::vector<std::string>& args) {
-    std::vector<const char*> argv;
-    argv.reserve(args.size() + 1);
-    for (const auto& arg : args) {
-        if (argv.empty()) {
-            LOG(DEBUG) << arg;
-        } else {
-            LOG(DEBUG) << "    " << arg;
+void CloseAllFds() {
+    DIR* dir;
+    struct dirent* ent;
+    int fd;
+
+    if ((dir = opendir("/proc/self/fd"))) {
+        while ((ent = readdir(dir))) {
+            if (sscanf(ent->d_name, "%d", &fd) == 1) {
+                close(fd);
+            }
         }
-        argv.emplace_back(arg.data());
+        closedir(dir);
     }
-    argv.emplace_back(nullptr);
-    return argv;
 }
 
-pid_t ForkExecvpAsync(const std::vector<std::string>& args) {
-    auto argv = ConvertToArgv(args);
-
+pid_t ForkExecvpAsync(const char* argv[]) {
     pid_t pid = fork();
     if (pid == 0) {
-        close(STDIN_FILENO);
-        close(STDOUT_FILENO);
-        close(STDERR_FILENO);
+        // Child process.
+        CloseAllFds();
 
-        execvp(argv[0], const_cast<char**>(argv.data()));
+        execvp(argv[0], const_cast<char**>(argv));
         PLOG(ERROR) << "exec in ForkExecvpAsync init test";
         _exit(EXIT_FAILURE);
     }
+    // Parent process.
     if (pid == -1) {
         PLOG(ERROR) << "fork in ForkExecvpAsync init test";
         return -1;
@@ -678,6 +679,18 @@
     return pid;
 }
 
+pid_t TracerPid(pid_t pid) {
+    static constexpr std::string_view prefix{"TracerPid:"};
+    std::ifstream is(StringPrintf("/proc/%d/status", pid));
+    std::string line;
+    while (std::getline(is, line)) {
+        if (line.find(prefix) == 0) {
+            return atoi(line.substr(prefix.length()).c_str());
+        }
+    }
+    return -1;
+}
+
 TEST(init, GentleKill) {
     if (getuid() != 0) {
         GTEST_SKIP() << "Must be run as root.";
@@ -709,18 +722,15 @@
     logfile.DoNotRemove();
     ASSERT_TRUE(logfile.fd != -1);
 
-    std::vector<std::string> cmd;
-    cmd.push_back("system/bin/strace");
-    cmd.push_back("-o");
-    cmd.push_back(logfile.path);
-    cmd.push_back("-e");
-    cmd.push_back("signal");
-    cmd.push_back("-p");
-    cmd.push_back(std::to_string(pid));
-    pid_t strace_pid = ForkExecvpAsync(cmd);
+    std::string pid_str = std::to_string(pid);
+    const char* argv[] = {"/system/bin/strace", "-o", logfile.path, "-e", "signal", "-p",
+                          pid_str.c_str(),      nullptr};
+    pid_t strace_pid = ForkExecvpAsync(argv);
 
-    // Give strace a moment to connect
-    std::this_thread::sleep_for(1s);
+    // Give strace the chance to connect
+    while (TracerPid(pid) == 0) {
+        std::this_thread::sleep_for(10ms);
+    }
     service->Stop();
 
     int status;
@@ -728,8 +738,7 @@
 
     std::string logs;
     android::base::ReadFdToString(logfile.fd, &logs);
-    int pos = logs.find("killed by SIGTERM");
-    ASSERT_NE(pos, (int)std::string::npos);
+    ASSERT_NE(logs.find("killed by SIGTERM"), std::string::npos);
 }
 
 class TestCaseLogger : public ::testing::EmptyTestEventListener {
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 86c6eaa..2929da4 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -993,6 +993,7 @@
     # Create directories for statsd
     mkdir /data/misc/stats-active-metric/ 0770 statsd system
     mkdir /data/misc/stats-data/ 0770 statsd system
+    mkdir /data/misc/stats-data/restricted-data 0770 statsd system
     mkdir /data/misc/stats-metadata/ 0770 statsd system
     mkdir /data/misc/stats-service/ 0770 statsd system
     mkdir /data/misc/train-info/ 0770 statsd system
diff --git a/trusty/libtrusty/tipc-test/tipc_test.c b/trusty/libtrusty/tipc-test/tipc_test.c
index eb0acb5..81c9881 100644
--- a/trusty/libtrusty/tipc-test/tipc_test.c
+++ b/trusty/libtrusty/tipc-test/tipc_test.c
@@ -596,6 +596,7 @@
         TEST_PASSED = 0,
         TEST_FAILED = 1,
         TEST_MESSAGE = 2,
+        TEST_TEXT = 3,
     };
 
     int fd;
@@ -625,7 +626,7 @@
             break;
         } else if (rx_buf[0] == TEST_FAILED) {
             break;
-        } else if (rx_buf[0] == TEST_MESSAGE) {
+        } else if (rx_buf[0] == TEST_MESSAGE || rx_buf[0] == TEST_TEXT) {
             write(STDOUT_FILENO, rx_buf + 1, ret - 1);
         } else {
             fprintf(stderr, "%s: Bad message header: %d\n", __func__, rx_buf[0]);
diff --git a/trusty/utils/trusty-ut-ctrl/ut-ctrl.c b/trusty/utils/trusty-ut-ctrl/ut-ctrl.c
index 9e72af3..6cc6670 100644
--- a/trusty/utils/trusty-ut-ctrl/ut-ctrl.c
+++ b/trusty/utils/trusty-ut-ctrl/ut-ctrl.c
@@ -94,6 +94,7 @@
     TEST_PASSED = 0,
     TEST_FAILED = 1,
     TEST_MESSAGE = 2,
+    TEST_TEXT = 3,
 };
 
 static int run_trusty_unitest(const char* utapp) {
@@ -121,7 +122,7 @@
             break;
         } else if (rx_buf[0] == TEST_FAILED) {
             break;
-        } else if (rx_buf[0] == TEST_MESSAGE) {
+        } else if (rx_buf[0] == TEST_MESSAGE || rx_buf[0] == TEST_TEXT) {
             write(STDOUT_FILENO, rx_buf + 1, rc - 1);
         } else {
             fprintf(stderr, "%s: Bad message header: %d\n", __func__, rx_buf[0]);