Merge "Move debugfs mount/unmount to init-debug.rc"
diff --git a/fastboot/device/flashing.cpp b/fastboot/device/flashing.cpp
index 333ca50..ee0aa58 100644
--- a/fastboot/device/flashing.cpp
+++ b/fastboot/device/flashing.cpp
@@ -27,6 +27,7 @@
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android-base/strings.h>
 #include <ext4_utils/ext4_utils.h>
 #include <fs_mgr_overlayfs.h>
@@ -162,7 +163,9 @@
                 partition_name == "boot_b")) {
         CopyAVBFooter(&data, block_device_size);
     }
-    WipeOverlayfsForPartition(device, partition_name);
+    if (android::base::GetProperty("ro.system.build.type", "") != "user") {
+        WipeOverlayfsForPartition(device, partition_name);
+    }
     int result = FlashBlockDevice(handle.fd(), data);
     sync();
     return result;
diff --git a/fs_mgr/libsnapshot/cow_api_test.cpp b/fs_mgr/libsnapshot/cow_api_test.cpp
index 5d63220..b75b154 100644
--- a/fs_mgr/libsnapshot/cow_api_test.cpp
+++ b/fs_mgr/libsnapshot/cow_api_test.cpp
@@ -25,6 +25,10 @@
 #include <libsnapshot/cow_reader.h>
 #include <libsnapshot/cow_writer.h>
 
+using testing::AssertionFailure;
+using testing::AssertionResult;
+using testing::AssertionSuccess;
+
 namespace android {
 namespace snapshot {
 
@@ -781,6 +785,202 @@
     ASSERT_TRUE(reader.Parse(cow_->fd));
 }
 
+AssertionResult WriteDataBlock(CowWriter* writer, uint64_t new_block, std::string data) {
+    data.resize(writer->options().block_size, '\0');
+    if (!writer->AddRawBlocks(new_block, data.data(), data.size())) {
+        return AssertionFailure() << "Failed to add raw block";
+    }
+    return AssertionSuccess();
+}
+
+AssertionResult CompareDataBlock(CowReader* reader, const CowOperation& op,
+                                 const std::string& data) {
+    CowHeader header;
+    reader->GetHeader(&header);
+
+    std::string cmp = data;
+    cmp.resize(header.block_size, '\0');
+
+    StringSink sink;
+    if (!reader->ReadData(op, &sink)) {
+        return AssertionFailure() << "Failed to read data block";
+    }
+    if (cmp != sink.stream()) {
+        return AssertionFailure() << "Data blocks did not match, expected " << cmp << ", got "
+                                  << sink.stream();
+    }
+
+    return AssertionSuccess();
+}
+
+TEST_F(CowTest, ResumeMidCluster) {
+    CowOptions options;
+    options.cluster_ops = 7;
+    auto writer = std::make_unique<CowWriter>(options);
+    ASSERT_TRUE(writer->Initialize(cow_->fd));
+
+    ASSERT_TRUE(WriteDataBlock(writer.get(), 1, "Block 1"));
+    ASSERT_TRUE(WriteDataBlock(writer.get(), 2, "Block 2"));
+    ASSERT_TRUE(WriteDataBlock(writer.get(), 3, "Block 3"));
+    ASSERT_TRUE(writer->AddLabel(1));
+    ASSERT_TRUE(writer->Finalize());
+    ASSERT_TRUE(WriteDataBlock(writer.get(), 4, "Block 4"));
+    ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+    writer = std::make_unique<CowWriter>(options);
+    ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 1));
+    ASSERT_TRUE(WriteDataBlock(writer.get(), 4, "Block 4"));
+    ASSERT_TRUE(WriteDataBlock(writer.get(), 5, "Block 5"));
+    ASSERT_TRUE(WriteDataBlock(writer.get(), 6, "Block 6"));
+    ASSERT_TRUE(WriteDataBlock(writer.get(), 7, "Block 7"));
+    ASSERT_TRUE(WriteDataBlock(writer.get(), 8, "Block 8"));
+    ASSERT_TRUE(writer->AddLabel(2));
+    ASSERT_TRUE(writer->Finalize());
+    ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+    CowReader reader;
+    ASSERT_TRUE(reader.Parse(cow_->fd));
+
+    auto iter = reader.GetOpIter();
+    size_t num_replace = 0;
+    size_t max_in_cluster = 0;
+    size_t num_in_cluster = 0;
+    size_t num_clusters = 0;
+    while (!iter->Done()) {
+        const auto& op = iter->Get();
+
+        num_in_cluster++;
+        max_in_cluster = std::max(max_in_cluster, num_in_cluster);
+
+        if (op.type == kCowReplaceOp) {
+            num_replace++;
+
+            ASSERT_EQ(op.new_block, num_replace);
+            ASSERT_TRUE(CompareDataBlock(&reader, op, "Block " + std::to_string(num_replace)));
+        } else if (op.type == kCowClusterOp) {
+            num_in_cluster = 0;
+            num_clusters++;
+        }
+
+        iter->Next();
+    }
+    ASSERT_EQ(num_replace, 8);
+    ASSERT_EQ(max_in_cluster, 7);
+    ASSERT_EQ(num_clusters, 2);
+}
+
+TEST_F(CowTest, ResumeEndCluster) {
+    CowOptions options;
+    int cluster_ops = 5;
+    options.cluster_ops = cluster_ops;
+    auto writer = std::make_unique<CowWriter>(options);
+    ASSERT_TRUE(writer->Initialize(cow_->fd));
+
+    ASSERT_TRUE(WriteDataBlock(writer.get(), 1, "Block 1"));
+    ASSERT_TRUE(WriteDataBlock(writer.get(), 2, "Block 2"));
+    ASSERT_TRUE(WriteDataBlock(writer.get(), 3, "Block 3"));
+    ASSERT_TRUE(writer->AddLabel(1));
+    ASSERT_TRUE(writer->Finalize());
+    ASSERT_TRUE(WriteDataBlock(writer.get(), 4, "Block 4"));
+    ASSERT_TRUE(WriteDataBlock(writer.get(), 5, "Block 5"));
+    ASSERT_TRUE(WriteDataBlock(writer.get(), 6, "Block 6"));
+    ASSERT_TRUE(WriteDataBlock(writer.get(), 7, "Block 7"));
+    ASSERT_TRUE(WriteDataBlock(writer.get(), 8, "Block 8"));
+    ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+    writer = std::make_unique<CowWriter>(options);
+    ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 1));
+    ASSERT_TRUE(WriteDataBlock(writer.get(), 4, "Block 4"));
+    ASSERT_TRUE(WriteDataBlock(writer.get(), 5, "Block 5"));
+    ASSERT_TRUE(WriteDataBlock(writer.get(), 6, "Block 6"));
+    ASSERT_TRUE(WriteDataBlock(writer.get(), 7, "Block 7"));
+    ASSERT_TRUE(WriteDataBlock(writer.get(), 8, "Block 8"));
+    ASSERT_TRUE(writer->AddLabel(2));
+    ASSERT_TRUE(writer->Finalize());
+    ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+    CowReader reader;
+    ASSERT_TRUE(reader.Parse(cow_->fd));
+
+    auto iter = reader.GetOpIter();
+    size_t num_replace = 0;
+    size_t max_in_cluster = 0;
+    size_t num_in_cluster = 0;
+    size_t num_clusters = 0;
+    while (!iter->Done()) {
+        const auto& op = iter->Get();
+
+        num_in_cluster++;
+        max_in_cluster = std::max(max_in_cluster, num_in_cluster);
+
+        if (op.type == kCowReplaceOp) {
+            num_replace++;
+
+            ASSERT_EQ(op.new_block, num_replace);
+            ASSERT_TRUE(CompareDataBlock(&reader, op, "Block " + std::to_string(num_replace)));
+        } else if (op.type == kCowClusterOp) {
+            num_in_cluster = 0;
+            num_clusters++;
+        }
+
+        iter->Next();
+    }
+    ASSERT_EQ(num_replace, 8);
+    ASSERT_EQ(max_in_cluster, cluster_ops);
+    ASSERT_EQ(num_clusters, 3);
+}
+
+TEST_F(CowTest, DeleteMidCluster) {
+    CowOptions options;
+    options.cluster_ops = 7;
+    auto writer = std::make_unique<CowWriter>(options);
+    ASSERT_TRUE(writer->Initialize(cow_->fd));
+
+    ASSERT_TRUE(WriteDataBlock(writer.get(), 1, "Block 1"));
+    ASSERT_TRUE(WriteDataBlock(writer.get(), 2, "Block 2"));
+    ASSERT_TRUE(WriteDataBlock(writer.get(), 3, "Block 3"));
+    ASSERT_TRUE(writer->AddLabel(1));
+    ASSERT_TRUE(writer->Finalize());
+    ASSERT_TRUE(WriteDataBlock(writer.get(), 4, "Block 4"));
+    ASSERT_TRUE(WriteDataBlock(writer.get(), 5, "Block 5"));
+    ASSERT_TRUE(WriteDataBlock(writer.get(), 6, "Block 6"));
+    ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+    writer = std::make_unique<CowWriter>(options);
+    ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 1));
+    ASSERT_TRUE(writer->Finalize());
+    ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+    CowReader reader;
+    ASSERT_TRUE(reader.Parse(cow_->fd));
+
+    auto iter = reader.GetOpIter();
+    size_t num_replace = 0;
+    size_t max_in_cluster = 0;
+    size_t num_in_cluster = 0;
+    size_t num_clusters = 0;
+    while (!iter->Done()) {
+        const auto& op = iter->Get();
+
+        num_in_cluster++;
+        max_in_cluster = std::max(max_in_cluster, num_in_cluster);
+        if (op.type == kCowReplaceOp) {
+            num_replace++;
+
+            ASSERT_EQ(op.new_block, num_replace);
+            ASSERT_TRUE(CompareDataBlock(&reader, op, "Block " + std::to_string(num_replace)));
+        } else if (op.type == kCowClusterOp) {
+            num_in_cluster = 0;
+            num_clusters++;
+        }
+
+        iter->Next();
+    }
+    ASSERT_EQ(num_replace, 3);
+    ASSERT_EQ(max_in_cluster, 5);  // 3 data, 1 label, 1 cluster op
+    ASSERT_EQ(num_clusters, 1);
+}
+
 }  // namespace snapshot
 }  // namespace android
 
diff --git a/fs_mgr/libsnapshot/cow_writer.cpp b/fs_mgr/libsnapshot/cow_writer.cpp
index 59f6d6f..645ae9d 100644
--- a/fs_mgr/libsnapshot/cow_writer.cpp
+++ b/fs_mgr/libsnapshot/cow_writer.cpp
@@ -232,15 +232,11 @@
     // Free reader so we own the descriptor position again.
     reader = nullptr;
 
-    // Remove excess data
-    if (!Truncate(next_op_pos_)) {
-        return false;
-    }
     if (lseek(fd_.get(), next_op_pos_, SEEK_SET) < 0) {
         PLOG(ERROR) << "lseek failed";
         return false;
     }
-    return true;
+    return EmitClusterIfNeeded();
 }
 
 bool CowWriter::EmitCopy(uint64_t new_block, uint64_t old_block) {
@@ -319,6 +315,14 @@
     return WriteOperation(op);
 }
 
+bool CowWriter::EmitClusterIfNeeded() {
+    // If there isn't room for another op and the cluster end op, end the current cluster
+    if (cluster_size_ && cluster_size_ < current_cluster_size_ + 2 * sizeof(CowOperation)) {
+        if (!EmitCluster()) return false;
+    }
+    return true;
+}
+
 std::basic_string<uint8_t> CowWriter::Compress(const void* data, size_t length) {
     switch (compression_) {
         case kCowCompressGz: {
@@ -379,6 +383,21 @@
     auto continue_num_ops = footer_.op.num_ops;
     bool extra_cluster = false;
 
+    // Blank out extra ops, in case we're in append mode and dropped ops.
+    if (cluster_size_) {
+        auto unused_cluster_space = cluster_size_ - current_cluster_size_;
+        std::string clr;
+        clr.resize(unused_cluster_space, '\0');
+        if (lseek(fd_.get(), next_op_pos_, SEEK_SET) < 0) {
+            PLOG(ERROR) << "Failed to seek to footer position.";
+            return false;
+        }
+        if (!android::base::WriteFully(fd_, clr.data(), clr.size())) {
+            PLOG(ERROR) << "clearing unused cluster area failed";
+            return false;
+        }
+    }
+
     // Footer should be at the end of a file, so if there is data after the current block, end it
     // and start a new cluster.
     if (cluster_size_ && current_data_size_ > 0) {
@@ -403,6 +422,17 @@
         return false;
     }
 
+    // Remove excess data, if we're in append mode and threw away more data
+    // than we wrote before.
+    off_t offs = lseek(fd_.get(), 0, SEEK_CUR);
+    if (offs < 0) {
+        PLOG(ERROR) << "Failed to lseek to find current position";
+        return false;
+    }
+    if (!Truncate(offs)) {
+        return false;
+    }
+
     // Reposition for additional Writing
     if (extra_cluster) {
         current_cluster_size_ = continue_cluster_size;
@@ -445,12 +475,7 @@
         if (!WriteRawData(data, size)) return false;
     }
     AddOperation(op);
-    // If there isn't room for another op and the cluster end op, end the current cluster
-    if (cluster_size_ && op.type != kCowClusterOp &&
-        cluster_size_ < current_cluster_size_ + 2 * sizeof(op)) {
-        if (!EmitCluster()) return false;
-    }
-    return true;
+    return EmitClusterIfNeeded();
 }
 
 void CowWriter::AddOperation(const CowOperation& op) {
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
index 6ffd5d8..a9efad8 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
@@ -115,6 +115,7 @@
 
   private:
     bool EmitCluster();
+    bool EmitClusterIfNeeded();
     void SetupHeaders();
     bool ParseOptions();
     bool OpenForWrite();
diff --git a/init/property_service.cpp b/init/property_service.cpp
index c2eb73c..17c36bb 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -1187,8 +1187,6 @@
         if (StartsWith(key, ANDROIDBOOT_PREFIX)) {
             InitPropertySet("ro.boot." + key.substr(ANDROIDBOOT_PREFIX.size()), value);
         } else if (StartsWith(key, qemu_prefix)) {
-            InitPropertySet("ro.kernel." + key, value);  // emulator specific, deprecated
-
             // emulator specific, should be retired once emulator migrates to
             // androidboot.
             const auto new_name =
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 2d3e06e..35a96f9 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -372,6 +372,12 @@
         system_ext_mapping_file.clear();
     }
 
+    std::string system_ext_compat_cil_file("/system_ext/etc/selinux/mapping/" + vend_plat_vers +
+                                           ".compat.cil");
+    if (access(system_ext_compat_cil_file.c_str(), F_OK) == -1) {
+        system_ext_compat_cil_file.clear();
+    }
+
     std::string product_policy_cil_file("/product/etc/selinux/product_sepolicy.cil");
     if (access(product_policy_cil_file.c_str(), F_OK) == -1) {
         product_policy_cil_file.clear();
@@ -426,6 +432,9 @@
     if (!system_ext_mapping_file.empty()) {
         compile_args.push_back(system_ext_mapping_file.c_str());
     }
+    if (!system_ext_compat_cil_file.empty()) {
+        compile_args.push_back(system_ext_compat_cil_file.c_str());
+    }
     if (!product_policy_cil_file.empty()) {
         compile_args.push_back(product_policy_cil_file.c_str());
     }
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index fad130b..2974aa3 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -426,19 +426,6 @@
     unlockBuffer(length);
 }
 
-void String8::toUpper()
-{
-    const size_t length = size();
-    if (length == 0) return;
-
-    char* buf = lockBuffer(length);
-    for (size_t i = length; i > 0; --i) {
-        *buf = static_cast<char>(toupper(*buf));
-        buf++;
-    }
-    unlockBuffer(length);
-}
-
 // ---------------------------------------------------------------------------
 // Path functions
 
diff --git a/libutils/String8_fuzz.cpp b/libutils/String8_fuzz.cpp
index b02683c..a45d675 100644
--- a/libutils/String8_fuzz.cpp
+++ b/libutils/String8_fuzz.cpp
@@ -42,9 +42,6 @@
 
                 // Casing
                 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
-                    str1->toUpper();
-                },
-                [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
                     str1->toLower();
                 },
                 [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void {
diff --git a/libutils/include/utils/RefBase.h b/libutils/include/utils/RefBase.h
index 7148949..e07f574 100644
--- a/libutils/include/utils/RefBase.h
+++ b/libutils/include/utils/RefBase.h
@@ -416,13 +416,16 @@
     wp(std::nullptr_t) : wp() {}
 #else
     wp(T* other);  // NOLINT(implicit)
+    template <typename U>
+    wp(U* other);  // NOLINT(implicit)
+    wp& operator=(T* other);
+    template <typename U>
+    wp& operator=(U* other);
 #endif
+
     wp(const wp<T>& other);
     explicit wp(const sp<T>& other);
 
-#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
-    template<typename U> wp(U* other);  // NOLINT(implicit)
-#endif
     template<typename U> wp(const sp<U>& other);  // NOLINT(implicit)
     template<typename U> wp(const wp<U>& other);  // NOLINT(implicit)
 
@@ -430,15 +433,9 @@
 
     // Assignment
 
-#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
-    wp& operator = (T* other);
-#endif
     wp& operator = (const wp<T>& other);
     wp& operator = (const sp<T>& other);
 
-#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
-    template<typename U> wp& operator = (U* other);
-#endif
     template<typename U> wp& operator = (const wp<U>& other);
     template<typename U> wp& operator = (const sp<U>& other);
 
@@ -559,6 +556,31 @@
 {
     m_refs = other ? m_refs = other->createWeak(this) : nullptr;
 }
+
+template <typename T>
+template <typename U>
+wp<T>::wp(U* other) : m_ptr(other) {
+    m_refs = other ? other->createWeak(this) : nullptr;
+}
+
+template <typename T>
+wp<T>& wp<T>::operator=(T* other) {
+    weakref_type* newRefs = other ? other->createWeak(this) : nullptr;
+    if (m_ptr) m_refs->decWeak(this);
+    m_ptr = other;
+    m_refs = newRefs;
+    return *this;
+}
+
+template <typename T>
+template <typename U>
+wp<T>& wp<T>::operator=(U* other) {
+    weakref_type* newRefs = other ? other->createWeak(this) : 0;
+    if (m_ptr) m_refs->decWeak(this);
+    m_ptr = other;
+    m_refs = newRefs;
+    return *this;
+}
 #endif
 
 template<typename T>
@@ -575,15 +597,6 @@
     m_refs = m_ptr ? m_ptr->createWeak(this) : nullptr;
 }
 
-#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
-template<typename T> template<typename U>
-wp<T>::wp(U* other)
-    : m_ptr(other)
-{
-    m_refs = other ? other->createWeak(this) : nullptr;
-}
-#endif
-
 template<typename T> template<typename U>
 wp<T>::wp(const wp<U>& other)
     : m_ptr(other.m_ptr)
@@ -609,19 +622,6 @@
     if (m_ptr) m_refs->decWeak(this);
 }
 
-#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
-template<typename T>
-wp<T>& wp<T>::operator = (T* other)
-{
-    weakref_type* newRefs =
-        other ? other->createWeak(this) : nullptr;
-    if (m_ptr) m_refs->decWeak(this);
-    m_ptr = other;
-    m_refs = newRefs;
-    return *this;
-}
-#endif
-
 template<typename T>
 wp<T>& wp<T>::operator = (const wp<T>& other)
 {
@@ -646,19 +646,6 @@
     return *this;
 }
 
-#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
-template<typename T> template<typename U>
-wp<T>& wp<T>::operator = (U* other)
-{
-    weakref_type* newRefs =
-        other ? other->createWeak(this) : 0;
-    if (m_ptr) m_refs->decWeak(this);
-    m_ptr = other;
-    m_refs = newRefs;
-    return *this;
-}
-#endif
-
 template<typename T> template<typename U>
 wp<T>& wp<T>::operator = (const wp<U>& other)
 {
diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h
index 84f14d0..cee5dc6 100644
--- a/libutils/include/utils/String8.h
+++ b/libutils/include/utils/String8.h
@@ -130,7 +130,6 @@
             bool                removeAll(const char* other);
 
             void                toLower();
-            void                toUpper();
 
 
     /*
diff --git a/libutils/include/utils/StrongPointer.h b/libutils/include/utils/StrongPointer.h
index dd53b9e..bb1941b 100644
--- a/libutils/include/utils/StrongPointer.h
+++ b/libutils/include/utils/StrongPointer.h
@@ -62,13 +62,16 @@
     sp(std::nullptr_t) : sp() {}
 #else
     sp(T* other);  // NOLINT(implicit)
+    template <typename U>
+    sp(U* other);  // NOLINT(implicit)
+    sp& operator=(T* other);
+    template <typename U>
+    sp& operator=(U* other);
 #endif
+
     sp(const sp<T>& other);
     sp(sp<T>&& other) noexcept;
 
-#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
-    template<typename U> sp(U* other);  // NOLINT(implicit)
-#endif
     template<typename U> sp(const sp<U>& other);  // NOLINT(implicit)
     template<typename U> sp(sp<U>&& other);  // NOLINT(implicit)
 
@@ -82,17 +85,11 @@
 
     // Assignment
 
-#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
-    sp& operator = (T* other);
-#endif
     sp& operator = (const sp<T>& other);
     sp& operator=(sp<T>&& other) noexcept;
 
     template<typename U> sp& operator = (const sp<U>& other);
     template<typename U> sp& operator = (sp<U>&& other);
-#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
-    template<typename U> sp& operator = (U* other);
-#endif
 
     //! Special optimization for use by ProcessState (and nobody else).
     void force_set(T* other);
@@ -247,6 +244,28 @@
         other->incStrong(this);
     }
 }
+
+template <typename T>
+template <typename U>
+sp<T>::sp(U* other) : m_ptr(other) {
+    if (other) {
+        check_not_on_stack(other);
+        (static_cast<T*>(other))->incStrong(this);
+    }
+}
+
+template <typename T>
+sp<T>& sp<T>::operator=(T* other) {
+    T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
+    if (other) {
+        check_not_on_stack(other);
+        other->incStrong(this);
+    }
+    if (oldPtr) oldPtr->decStrong(this);
+    if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
+    m_ptr = other;
+    return *this;
+}
 #endif
 
 template<typename T>
@@ -261,17 +280,6 @@
     other.m_ptr = nullptr;
 }
 
-#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
-template<typename T> template<typename U>
-sp<T>::sp(U* other)
-        : m_ptr(other) {
-    if (other) {
-        check_not_on_stack(other);
-        (static_cast<T*>(other))->incStrong(this);
-    }
-}
-#endif
-
 template<typename T> template<typename U>
 sp<T>::sp(const sp<U>& other)
         : m_ptr(other.m_ptr) {
@@ -319,21 +327,6 @@
     return *this;
 }
 
-#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
-template<typename T>
-sp<T>& sp<T>::operator =(T* other) {
-    T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
-    if (other) {
-        check_not_on_stack(other);
-        other->incStrong(this);
-    }
-    if (oldPtr) oldPtr->decStrong(this);
-    if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
-    m_ptr = other;
-    return *this;
-}
-#endif
-
 template<typename T> template<typename U>
 sp<T>& sp<T>::operator =(const sp<U>& other) {
     T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
diff --git a/rootdir/Android.bp b/rootdir/Android.bp
index 6a80808..ae21633 100644
--- a/rootdir/Android.bp
+++ b/rootdir/Android.bp
@@ -20,7 +20,10 @@
     name: "init.rc",
     src: "init.rc",
     sub_dir: "init/hw",
-    required: ["fsverity_init"],
+    required: [
+        "fsverity_init",
+        "platform-bootclasspath",
+    ],
 }
 
 prebuilt_etc {
@@ -35,3 +38,11 @@
     src: "etc/linker.config.json",
     installable: false,
 }
+
+// TODO(b/185211376) Scope the native APIs that microdroid will provide to the app payload
+prebuilt_etc {
+    name: "public.libraries.android.txt",
+    src: "etc/public.libraries.android.txt",
+    filename: "public.libraries.txt",
+    installable: false,
+}
\ No newline at end of file
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 5fbdcd6..4a58f8e 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -755,6 +755,8 @@
     mkdir /data/misc/snapshotctl_log 0755 root root
     # create location to store pre-reboot information
     mkdir /data/misc/prereboot 0700 system system
+    # directory used for on-device refresh metrics file.
+    mkdir /data/misc/odrefresh 0777 system system
     # directory used for on-device signing key blob
     mkdir /data/misc/odsign 0700 root root
 
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index 65e29c1..56e774b 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -67,6 +67,10 @@
 # CDMA radio interface MUX
 /dev/ppp                  0660   radio      vpn
 
+# Virtualisation is managed by Virt Manager
+/dev/kvm                  0600   virtmanager root
+/dev/vhost-vsock          0600   virtmanager root
+
 # sysfs properties
 /sys/devices/platform/trusty.*      trusty_version        0440  root   log
 /sys/devices/virtual/input/input*   enable      0660  root   input
diff --git a/trusty/fuzz/include/trusty/fuzz/utils.h b/trusty/fuzz/include/trusty/fuzz/utils.h
index bca84e9..c906412 100644
--- a/trusty/fuzz/include/trusty/fuzz/utils.h
+++ b/trusty/fuzz/include/trusty/fuzz/utils.h
@@ -34,6 +34,7 @@
     android::base::Result<void> Connect();
     android::base::Result<void> Read(void* buf, size_t len);
     android::base::Result<void> Write(const void* buf, size_t len);
+    void Disconnect();
 
     android::base::Result<int> GetRawFd();
 
diff --git a/trusty/fuzz/tipc_fuzzer.cpp b/trusty/fuzz/tipc_fuzzer.cpp
index 3258944..f265ced 100644
--- a/trusty/fuzz/tipc_fuzzer.cpp
+++ b/trusty/fuzz/tipc_fuzzer.cpp
@@ -41,6 +41,7 @@
 #error "Binary file name must be parameterized using -DTRUSTY_APP_FILENAME."
 #endif
 
+static TrustyApp kTrustyApp(TIPC_DEV, TRUSTY_APP_PORT);
 static std::unique_ptr<CoverageRecord> record;
 
 extern "C" int LLVMFuzzerInitialize(int* /* argc */, char*** /* argv */) {
@@ -52,8 +53,7 @@
     }
 
     /* Make sure lazy-loaded TAs have started and connected to coverage service. */
-    TrustyApp ta(TIPC_DEV, TRUSTY_APP_PORT);
-    auto ret = ta.Connect();
+    auto ret = kTrustyApp.Connect();
     if (!ret.ok()) {
         std::cerr << ret.error() << std::endl;
         exit(-1);
@@ -79,22 +79,18 @@
     ExtraCounters counters(record.get());
     counters.Reset();
 
-    TrustyApp ta(TIPC_DEV, TRUSTY_APP_PORT);
-    auto ret = ta.Connect();
+    auto ret = kTrustyApp.Write(data, size);
+    if (ret.ok()) {
+        ret = kTrustyApp.Read(&buf, sizeof(buf));
+    }
+
+    // Reconnect to ensure that the service is still up
+    kTrustyApp.Disconnect();
+    ret = kTrustyApp.Connect();
     if (!ret.ok()) {
         std::cerr << ret.error() << std::endl;
         android::trusty::fuzz::Abort();
     }
 
-    ret = ta.Write(data, size);
-    if (!ret.ok()) {
-        return -1;
-    }
-
-    ret = ta.Read(&buf, sizeof(buf));
-    if (!ret.ok()) {
-        return -1;
-    }
-
-    return 0;
+    return ret.ok() ? 0 : -1;
 }
diff --git a/trusty/fuzz/utils.cpp b/trusty/fuzz/utils.cpp
index 3526337..bb096be 100644
--- a/trusty/fuzz/utils.cpp
+++ b/trusty/fuzz/utils.cpp
@@ -127,6 +127,10 @@
     return ta_fd_;
 }
 
+void TrustyApp::Disconnect() {
+    ta_fd_.reset();
+}
+
 void Abort() {
     PrintTrustyLog();
     exit(-1);