Merge "init: send property_set failures to the audit netlink socket"
diff --git a/fs_mgr/fs_mgr_dm_linear.cpp b/fs_mgr/fs_mgr_dm_linear.cpp
index 1b85b47..fa756a0 100644
--- a/fs_mgr/fs_mgr_dm_linear.cpp
+++ b/fs_mgr/fs_mgr_dm_linear.cpp
@@ -212,6 +212,17 @@
     return true;
 }
 
+std::string CreateLogicalPartitionParams::GetDeviceName() const {
+    if (!device_name.empty()) return device_name;
+    return GetPartitionName();
+}
+
+std::string CreateLogicalPartitionParams::GetPartitionName() const {
+    if (!partition_name.empty()) return partition_name;
+    if (partition) return android::fs_mgr::GetPartitionName(*partition);
+    return "<unknown partition>";
+}
+
 bool UnmapDevice(const std::string& name) {
     DeviceMapper& dm = DeviceMapper::Instance();
     if (!dm.DeleteDevice(name)) {
diff --git a/fs_mgr/include/fs_mgr_dm_linear.h b/fs_mgr/include/fs_mgr_dm_linear.h
index 8e2fdbb..2054fa1 100644
--- a/fs_mgr/include/fs_mgr_dm_linear.h
+++ b/fs_mgr/include/fs_mgr_dm_linear.h
@@ -77,6 +77,10 @@
     // If non-null, this will use the specified IPartitionOpener rather than
     // the default one.
     const IPartitionOpener* partition_opener = nullptr;
+
+    // Helpers for determining the effective partition and device name.
+    std::string GetPartitionName() const;
+    std::string GetDeviceName() const;
 };
 
 bool CreateLogicalPartition(const CreateLogicalPartitionParams& params, std::string* path);
diff --git a/fs_mgr/libdm/dm_target.cpp b/fs_mgr/libdm/dm_target.cpp
index 7c9804c..65f6e12 100644
--- a/fs_mgr/libdm/dm_target.cpp
+++ b/fs_mgr/libdm/dm_target.cpp
@@ -244,7 +244,8 @@
 }
 
 std::string DmTargetDefaultKey::GetParameterString() const {
-    return cipher_ + " " + key_ + " " + blockdev_ + " " + std::to_string(start_sector_);
+    return cipher_ + " " + key_ + " " + blockdev_ + " " + std::to_string(start_sector_) +
+           (set_dun_ ? " 1 set_dun" : "");
 }
 
 }  // namespace dm
diff --git a/fs_mgr/libdm/include/libdm/dm_target.h b/fs_mgr/libdm/include/libdm/dm_target.h
index a66ab7a..a78bc71 100644
--- a/fs_mgr/libdm/include/libdm/dm_target.h
+++ b/fs_mgr/libdm/include/libdm/dm_target.h
@@ -280,12 +280,14 @@
 class DmTargetDefaultKey final : public DmTarget {
   public:
     DmTargetDefaultKey(uint64_t start, uint64_t length, const std::string& cipher,
-                       const std::string& key, const std::string& blockdev, uint64_t start_sector)
+                       const std::string& key, const std::string& blockdev, uint64_t start_sector,
+                       bool set_dun = false)
         : DmTarget(start, length),
           cipher_(cipher),
           key_(key),
           blockdev_(blockdev),
-          start_sector_(start_sector) {}
+          start_sector_(start_sector),
+          set_dun_(set_dun) {}
 
     std::string name() const override { return "default-key"; }
     bool Valid() const override { return true; }
@@ -296,6 +298,7 @@
     std::string key_;
     std::string blockdev_;
     uint64_t start_sector_;
+    bool set_dun_;
 };
 
 }  // namespace dm
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 51f5c50..b320db8 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -28,6 +28,8 @@
     ],
     static_libs: [
         "libdm",
+        "libfs_mgr",
+        "liblp",
     ],
     whole_static_libs: [
         "libext2_uuid",
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 1630ee5..0c0355d 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -24,6 +24,7 @@
 #include <android-base/unique_fd.h>
 #include <libdm/dm.h>
 #include <libfiemap/image_manager.h>
+#include <liblp/liblp.h>
 
 #ifndef FRIEND_TEST
 #define FRIEND_TEST(test_set_name, individual_test) \
@@ -37,6 +38,11 @@
 class IImageManager;
 }  // namespace fiemap
 
+namespace fs_mgr {
+struct CreateLogicalPartitionParams;
+class IPartitionOpener;
+}  // namespace fs_mgr
+
 namespace snapshot {
 
 enum class UpdateState : unsigned int {
@@ -64,6 +70,10 @@
 };
 
 class SnapshotManager final {
+    using CreateLogicalPartitionParams = android::fs_mgr::CreateLogicalPartitionParams;
+    using LpMetadata = android::fs_mgr::LpMetadata;
+    using IPartitionOpener = android::fs_mgr::IPartitionOpener;
+
   public:
     // Dependency injection for testing.
     class IDeviceInfo {
@@ -72,6 +82,7 @@
         virtual std::string GetGsidDir() const = 0;
         virtual std::string GetMetadataDir() const = 0;
         virtual std::string GetSlotSuffix() const = 0;
+        virtual const IPartitionOpener& GetPartitionOpener() const = 0;
     };
 
     ~SnapshotManager();
@@ -81,6 +92,14 @@
     // instance will be created.
     static std::unique_ptr<SnapshotManager> New(IDeviceInfo* device = nullptr);
 
+    // This is similar to New(), except designed specifically for first-stage
+    // init.
+    static std::unique_ptr<SnapshotManager> NewForFirstStageMount(IDeviceInfo* device = nullptr);
+
+    // Helper function for first-stage init to check whether a SnapshotManager
+    // might be needed to perform first-stage mounts.
+    static bool IsSnapshotManagerNeeded();
+
     // Begin an update. This must be called before creating any snapshots. It
     // will fail if GetUpdateState() != None.
     bool BeginUpdate();
@@ -126,13 +145,24 @@
     //   Other: 0
     UpdateState GetUpdateState(double* progress = nullptr);
 
+    // If this returns true, first-stage mount must call
+    // CreateLogicalAndSnapshotPartitions rather than CreateLogicalPartitions.
+    bool NeedSnapshotsInFirstStageMount();
+
+    // Perform first-stage mapping of snapshot targets. This replaces init's
+    // call to CreateLogicalPartitions when snapshots are present.
+    bool CreateLogicalAndSnapshotPartitions(const std::string& super_device);
+
   private:
+    FRIEND_TEST(SnapshotTest, CleanFirstStageMount);
     FRIEND_TEST(SnapshotTest, CreateSnapshot);
-    FRIEND_TEST(SnapshotTest, MapSnapshot);
+    FRIEND_TEST(SnapshotTest, FirstStageMountAfterRollback);
+    FRIEND_TEST(SnapshotTest, FirstStageMountAndMerge);
     FRIEND_TEST(SnapshotTest, MapPartialSnapshot);
-    FRIEND_TEST(SnapshotTest, NoMergeBeforeReboot);
+    FRIEND_TEST(SnapshotTest, MapSnapshot);
     FRIEND_TEST(SnapshotTest, Merge);
     FRIEND_TEST(SnapshotTest, MergeCannotRemoveCow);
+    FRIEND_TEST(SnapshotTest, NoMergeBeforeReboot);
     friend class SnapshotTest;
 
     using DmTargetSnapshot = android::dm::DmTargetSnapshot;
@@ -141,9 +171,12 @@
 
     explicit SnapshotManager(IDeviceInfo* info);
 
-    // This is created lazily since it connects via binder.
+    // This is created lazily since it can connect via binder.
     bool EnsureImageManager();
 
+    // Helper for first-stage init.
+    bool ForceLocalImageManager();
+
     // Helper function for tests.
     IImageManager* image_manager() const { return images_.get(); }
 
@@ -278,6 +311,7 @@
     std::string metadata_dir_;
     std::unique_ptr<IDeviceInfo> device_;
     std::unique_ptr<IImageManager> images_;
+    bool has_local_image_manager_ = false;
 };
 
 }  // namespace snapshot
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index fef5c06..87170a7 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -20,6 +20,7 @@
 #include <sys/unistd.h>
 
 #include <thread>
+#include <unordered_set>
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
@@ -27,9 +28,11 @@
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <ext4_utils/ext4_utils.h>
+#include <fs_mgr_dm_linear.h>
 #include <fstab/fstab.h>
 #include <libdm/dm.h>
 #include <libfiemap/image_manager.h>
+#include <liblp/liblp.h>
 
 namespace android {
 namespace snapshot {
@@ -43,22 +46,30 @@
 using android::dm::kSectorSize;
 using android::dm::SnapshotStorageMode;
 using android::fiemap::IImageManager;
+using android::fs_mgr::CreateLogicalPartition;
+using android::fs_mgr::CreateLogicalPartitionParams;
+using android::fs_mgr::GetPartitionName;
+using android::fs_mgr::LpMetadata;
+using android::fs_mgr::SlotNumberForSlotSuffix;
 using namespace std::chrono_literals;
 using namespace std::string_literals;
 
 // Unit is sectors, this is a 4K chunk.
 static constexpr uint32_t kSnapshotChunkSize = 8;
-
-static constexpr char kSnapshotBootIndicatorFile[] = "snapshot-boot";
+static constexpr char kBootIndicatorPath[] = "/metadata/ota/snapshot-boot";
 
 class DeviceInfo final : public SnapshotManager::IDeviceInfo {
   public:
     std::string GetGsidDir() const override { return "ota"s; }
     std::string GetMetadataDir() const override { return "/metadata/ota"s; }
     std::string GetSlotSuffix() const override { return fs_mgr_get_slot_suffix(); }
+    const android::fs_mgr::IPartitionOpener& GetPartitionOpener() const { return opener_; }
+
+  private:
+    android::fs_mgr::PartitionOpener opener_;
 };
 
-// Note: IIMageManager is an incomplete type in the header, so the default
+// Note: IImageManager is an incomplete type in the header, so the default
 // destructor doesn't work.
 SnapshotManager::~SnapshotManager() {}
 
@@ -69,6 +80,14 @@
     return std::unique_ptr<SnapshotManager>(new SnapshotManager(info));
 }
 
+std::unique_ptr<SnapshotManager> SnapshotManager::NewForFirstStageMount(IDeviceInfo* info) {
+    auto sm = New(info);
+    if (!sm || !sm->ForceLocalImageManager()) {
+        return nullptr;
+    }
+    return sm;
+}
+
 SnapshotManager::SnapshotManager(IDeviceInfo* device) : device_(device) {
     gsid_dir_ = device_->GetGsidDir();
     metadata_dir_ = device_->GetMetadataDir();
@@ -78,6 +97,10 @@
     return snapshot_name + "-cow";
 }
 
+static std::string GetBaseDeviceName(const std::string& partition_name) {
+    return partition_name + "-base";
+}
+
 bool SnapshotManager::BeginUpdate() {
     auto file = LockExclusive();
     if (!file) return false;
@@ -197,8 +220,8 @@
     }
 
     // Validate the block device size, as well as the requested snapshot size.
-    // During this we also compute the linear sector region if any.
-    {
+    // Note that during first-stage init, we don't have the device paths.
+    if (android::base::StartsWith(base_device, "/")) {
         unique_fd fd(open(base_device.c_str(), O_RDONLY | O_CLOEXEC));
         if (fd < 0) {
             PLOG(ERROR) << "open failed: " << base_device;
@@ -228,8 +251,17 @@
 
     auto cow_name = GetCowName(name);
 
+    bool ok;
     std::string cow_dev;
-    if (!images_->MapImageDevice(cow_name, timeout_ms, &cow_dev)) {
+    if (has_local_image_manager_) {
+        // If we forced a local image manager, it means we don't have binder,
+        // which means first-stage init. We must use device-mapper.
+        const auto& opener = device_->GetPartitionOpener();
+        ok = images_->MapImageWithDeviceMapper(opener, cow_name, &cow_dev);
+    } else {
+        ok = images_->MapImageDevice(cow_name, timeout_ms, &cow_dev);
+    }
+    if (!ok) {
         LOG(ERROR) << "Could not map image device: " << cow_name;
         return false;
     }
@@ -305,7 +337,7 @@
     }
 
     auto& dm = DeviceMapper::Instance();
-    if (dm.GetState(name) != DmDeviceState::INVALID && !dm.DeleteDevice(name)) {
+    if (!dm.DeleteDeviceIfExists(name)) {
         LOG(ERROR) << "Could not delete snapshot device: " << name;
         return false;
     }
@@ -313,8 +345,7 @@
     // There may be an extra device, since the kernel doesn't let us have a
     // snapshot and linear target in the same table.
     auto dm_name = GetSnapshotDeviceName(name, status);
-    if (name != dm_name && dm.GetState(dm_name) != DmDeviceState::INVALID &&
-        !dm.DeleteDevice(dm_name)) {
+    if (name != dm_name && !dm.DeleteDeviceIfExists(dm_name)) {
         LOG(ERROR) << "Could not delete inner snapshot device: " << dm_name;
         return false;
     }
@@ -705,7 +736,7 @@
 }
 
 std::string SnapshotManager::GetSnapshotBootIndicatorPath() {
-    return metadata_dir_ + "/" + kSnapshotBootIndicatorFile;
+    return metadata_dir_ + "/" + android::base::Basename(kBootIndicatorPath);
 }
 
 void SnapshotManager::RemoveSnapshotBootIndicator() {
@@ -866,7 +897,7 @@
         // the device, and device-mapper should have flushed remaining I/O. We
         // could in theory replace with dm-zero (or re-use the table above), but
         // for now it's better to know why this would fail.
-        if (!dm.DeleteDevice(dm_name)) {
+        if (!dm.DeleteDeviceIfExists(dm_name)) {
             LOG(ERROR) << "Unable to delete snapshot device " << dm_name << ", COW cannot be "
                        << "reclaimed until after reboot.";
             return false;
@@ -931,6 +962,126 @@
     return true;
 }
 
+bool SnapshotManager::IsSnapshotManagerNeeded() {
+    return access(kBootIndicatorPath, F_OK) == 0;
+}
+
+bool SnapshotManager::NeedSnapshotsInFirstStageMount() {
+    // If we fail to read, we'll wind up using CreateLogicalPartitions, which
+    // will create devices that look like the old slot, except with extra
+    // content at the end of each device. This will confuse dm-verity, and
+    // ultimately we'll fail to boot. Why not make it a fatal error and have
+    // the reason be clearer? Because the indicator file still exists, and
+    // if this was FATAL, reverting to the old slot would be broken.
+    std::string old_slot;
+    auto boot_file = GetSnapshotBootIndicatorPath();
+    if (!android::base::ReadFileToString(boot_file, &old_slot)) {
+        PLOG(ERROR) << "Unable to read the snapshot indicator file: " << boot_file;
+        return false;
+    }
+    if (device_->GetSlotSuffix() == old_slot) {
+        LOG(INFO) << "Detected slot rollback, will not mount snapshots.";
+        return false;
+    }
+
+    // If we can't read the update state, it's unlikely anything else will
+    // succeed, so this is a fatal error. We'll eventually exhaust boot
+    // attempts and revert to the old slot.
+    auto lock = LockShared();
+    if (!lock) {
+        LOG(FATAL) << "Could not read update state to determine snapshot status";
+        return false;
+    }
+    switch (ReadUpdateState(lock.get())) {
+        case UpdateState::Unverified:
+        case UpdateState::Merging:
+        case UpdateState::MergeFailed:
+            return true;
+        default:
+            return false;
+    }
+}
+
+bool SnapshotManager::CreateLogicalAndSnapshotPartitions(const std::string& super_device) {
+    LOG(INFO) << "Creating logical partitions with snapshots as needed";
+
+    auto lock = LockExclusive();
+    if (!lock) return false;
+
+    std::vector<std::string> snapshot_list;
+    if (!ListSnapshots(lock.get(), &snapshot_list)) {
+        return false;
+    }
+
+    std::unordered_set<std::string> live_snapshots;
+    for (const auto& snapshot : snapshot_list) {
+        SnapshotStatus status;
+        if (!ReadSnapshotStatus(lock.get(), snapshot, &status)) {
+            return false;
+        }
+        if (status.state != SnapshotState::MergeCompleted) {
+            live_snapshots.emplace(snapshot);
+        }
+    }
+
+    const auto& opener = device_->GetPartitionOpener();
+    uint32_t slot = SlotNumberForSlotSuffix(device_->GetSlotSuffix());
+    auto metadata = android::fs_mgr::ReadMetadata(opener, super_device, slot);
+    if (!metadata) {
+        LOG(ERROR) << "Could not read dynamic partition metadata for device: " << super_device;
+        return false;
+    }
+
+    // Map logical partitions.
+    auto& dm = DeviceMapper::Instance();
+    for (const auto& partition : metadata->partitions) {
+        auto partition_name = GetPartitionName(partition);
+        if (!partition.num_extents) {
+            LOG(INFO) << "Skipping zero-length logical partition: " << partition_name;
+            continue;
+        }
+
+        CreateLogicalPartitionParams params = {
+                .block_device = super_device,
+                .metadata = metadata.get(),
+                .partition = &partition,
+                .partition_opener = &opener,
+        };
+
+        if (auto iter = live_snapshots.find(partition_name); iter != live_snapshots.end()) {
+            // If the device has a snapshot, it'll need to be writable, and
+            // we'll need to create the logical partition with a marked-up name
+            // (since the snapshot will use the partition name).
+            params.force_writable = true;
+            params.device_name = GetBaseDeviceName(partition_name);
+        }
+
+        std::string ignore_path;
+        if (!CreateLogicalPartition(params, &ignore_path)) {
+            LOG(ERROR) << "Could not create logical partition " << partition_name << " as device "
+                       << params.GetDeviceName();
+            return false;
+        }
+        if (!params.force_writable) {
+            // No snapshot.
+            continue;
+        }
+
+        // We don't have ueventd in first-stage init, so use device major:minor
+        // strings instead.
+        std::string base_device;
+        if (!dm.GetDeviceString(params.GetDeviceName(), &base_device)) {
+            LOG(ERROR) << "Could not determine major/minor for: " << params.GetDeviceName();
+            return false;
+        }
+        if (!MapSnapshot(lock.get(), partition_name, base_device, {}, &ignore_path)) {
+            LOG(ERROR) << "Could not map snapshot for partition: " << partition_name;
+            return false;
+        }
+    }
+    return true;
+}
+
 auto SnapshotManager::OpenFile(const std::string& file, int open_flags, int lock_flags)
         -> std::unique_ptr<LockedFile> {
     unique_fd fd(open(file.c_str(), open_flags | O_CLOEXEC | O_NOFOLLOW | O_SYNC, 0660));
@@ -1173,5 +1324,15 @@
     return true;
 }
 
+bool SnapshotManager::ForceLocalImageManager() {
+    images_ = android::fiemap::ImageManager::Open(gsid_dir_);
+    if (!images_) {
+        LOG(ERROR) << "Could not open ImageManager";
+        return false;
+    }
+    has_local_image_manager_ = true;
+    return true;
+}
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 518c619..f4eb1ac 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -55,33 +55,19 @@
 
 static constexpr uint64_t kSuperSize = 16 * 1024 * 1024;
 
-// Helper to remove stale partitions in fake super.
-void CleanupPartitions() {
-    // These are hardcoded since we might abort in the middle of a test, and
-    // can't recover the in-use list.
-    static std::vector<std::string> kPartitionNames = {
-            "base-device",
-    };
-
-    auto& dm = DeviceMapper::Instance();
-    for (const auto& partition : kPartitionNames) {
-        if (dm.GetState(partition) != DmDeviceState::INVALID) {
-            dm.DeleteDevice(partition);
-        }
-    }
-}
-
 class SnapshotTest : public ::testing::Test {
   public:
     SnapshotTest() : dm_(DeviceMapper::Instance()) {}
 
+    // This is exposed for main.
+    void Cleanup() {
+        InitializeState();
+        CleanupTestArtifacts();
+    }
+
   protected:
     void SetUp() override {
-        ASSERT_TRUE(sm->EnsureImageManager());
-        image_manager_ = sm->image_manager();
-
-        test_device->set_slot_suffix("_a");
-
+        InitializeState();
         CleanupTestArtifacts();
         FormatFakeSuper();
 
@@ -94,6 +80,13 @@
         CleanupTestArtifacts();
     }
 
+    void InitializeState() {
+        ASSERT_TRUE(sm->EnsureImageManager());
+        image_manager_ = sm->image_manager();
+
+        test_device->set_slot_suffix("_a");
+    }
+
     void CleanupTestArtifacts() {
         // Normally cancelling inside a merge is not allowed. Since these
         // are tests, we don't care, destroy everything that might exist.
@@ -102,7 +95,7 @@
         // get an accurate list to remove.
         lock_ = nullptr;
 
-        std::vector<std::string> snapshots = {"test-snapshot"};
+        std::vector<std::string> snapshots = {"test-snapshot", "test_partition_b"};
         for (const auto& snapshot : snapshots) {
             DeleteSnapshotDevice(snapshot);
             DeleteBackingImage(image_manager_, snapshot + "-cow");
@@ -111,7 +104,15 @@
             android::base::RemoveFileIfExists(status_file);
         }
 
-        CleanupPartitions();
+        // Remove stale partitions in fake super.
+        std::vector<std::string> partitions = {
+                "base-device",
+                "test_partition_b",
+                "test_partition_b-base",
+        };
+        for (const auto& partition : partitions) {
+            DeleteDevice(partition);
+        }
 
         if (sm->GetUpdateState() != UpdateState::None) {
             auto state_file = sm->GetStateFilePath();
@@ -124,6 +125,9 @@
         return !!lock_;
     }
 
+    // This is so main() can instantiate this to invoke Cleanup.
+    virtual void TestBody() override {}
+
     void FormatFakeSuper() {
         BlockDeviceInfo super_device("super", kSuperSize, 0, 0, 4096);
         std::vector<BlockDeviceInfo> devices = {super_device};
@@ -150,9 +154,11 @@
             return false;
         }
 
+        // Update both slots for convenience.
         auto metadata = builder->Export();
         if (!metadata) return false;
-        if (!UpdatePartitionTable(opener, "super", *metadata.get(), 0)) {
+        if (!UpdatePartitionTable(opener, "super", *metadata.get(), 0) ||
+            !UpdatePartitionTable(opener, "super", *metadata.get(), 1)) {
             return false;
         }
 
@@ -169,11 +175,12 @@
     }
 
     void DeleteSnapshotDevice(const std::string& snapshot) {
-        if (dm_.GetState(snapshot) != DmDeviceState::INVALID) {
-            ASSERT_TRUE(dm_.DeleteDevice(snapshot));
-        }
-        if (dm_.GetState(snapshot + "-inner") != DmDeviceState::INVALID) {
-            ASSERT_TRUE(dm_.DeleteDevice(snapshot + "-inner"));
+        DeleteDevice(snapshot);
+        DeleteDevice(snapshot + "-inner");
+    }
+    void DeleteDevice(const std::string& device) {
+        if (dm_.GetState(device) != DmDeviceState::INVALID) {
+            ASSERT_TRUE(dm_.DeleteDevice(device));
         }
     }
 
@@ -246,6 +253,25 @@
     ASSERT_FALSE(sm->InitiateMerge());
 }
 
+TEST_F(SnapshotTest, CleanFirstStageMount) {
+    // If there's no update in progress, there should be no first-stage mount
+    // needed.
+    TestDeviceInfo* info = new TestDeviceInfo(fake_super);
+    auto sm = SnapshotManager::NewForFirstStageMount(info);
+    ASSERT_NE(sm, nullptr);
+    ASSERT_FALSE(sm->NeedSnapshotsInFirstStageMount());
+}
+
+TEST_F(SnapshotTest, FirstStageMountAfterRollback) {
+    ASSERT_TRUE(sm->FinishedSnapshotWrites());
+
+    // We didn't change the slot, so we shouldn't need snapshots.
+    TestDeviceInfo* info = new TestDeviceInfo(fake_super);
+    auto sm = SnapshotManager::NewForFirstStageMount(info);
+    ASSERT_NE(sm, nullptr);
+    ASSERT_FALSE(sm->NeedSnapshotsInFirstStageMount());
+}
+
 TEST_F(SnapshotTest, Merge) {
     ASSERT_TRUE(AcquireLock());
 
@@ -270,12 +296,12 @@
     ASSERT_TRUE(sm->IsSnapshotDevice("test-snapshot", &target));
     ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "snapshot");
 
-    // Set the state to Unverified, as if we finished an update.
-    ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::Unverified));
-
     // Release the lock.
     lock_ = nullptr;
 
+    // Done updating.
+    ASSERT_TRUE(sm->FinishedSnapshotWrites());
+
     test_device->set_slot_suffix("_b");
     ASSERT_TRUE(sm->InitiateMerge());
 
@@ -343,6 +369,40 @@
     ASSERT_EQ(sm->WaitForMerge(), UpdateState::MergeCompleted);
 }
 
+TEST_F(SnapshotTest, FirstStageMountAndMerge) {
+    ASSERT_TRUE(AcquireLock());
+
+    static const uint64_t kDeviceSize = 1024 * 1024;
+
+    ASSERT_TRUE(CreatePartition("test_partition_b", kDeviceSize));
+    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b", kDeviceSize, kDeviceSize,
+                                   kDeviceSize));
+
+    // Simulate a reboot into the new slot.
+    lock_ = nullptr;
+    ASSERT_TRUE(sm->FinishedSnapshotWrites());
+
+    auto rebooted = new TestDeviceInfo(fake_super);
+    rebooted->set_slot_suffix("_b");
+
+    auto init = SnapshotManager::NewForFirstStageMount(rebooted);
+    ASSERT_NE(init, nullptr);
+    ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
+
+    ASSERT_TRUE(AcquireLock());
+
+    // Validate that we have a snapshot device.
+    SnapshotManager::SnapshotStatus status;
+    ASSERT_TRUE(init->ReadSnapshotStatus(lock_.get(), "test_partition_b", &status));
+    ASSERT_EQ(status.state, SnapshotManager::SnapshotState::Created);
+
+    DeviceMapper::TargetInfo target;
+    auto dm_name = init->GetSnapshotDeviceName("test_partition_b", status);
+    ASSERT_TRUE(init->IsSnapshotDevice(dm_name, &target));
+    ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "snapshot");
+}
+
 }  // namespace snapshot
 }  // namespace android
 
@@ -383,6 +443,9 @@
         return 1;
     }
 
+    // Clean up previous run.
+    SnapshotTest().Cleanup();
+
     // Use a separate image manager for our fake super partition.
     auto super_images = IImageManager::Open("ota/test/super", 10s);
     if (!super_images) {
@@ -390,8 +453,7 @@
         return 1;
     }
 
-    // Clean up previous run.
-    CleanupPartitions();
+    // Clean up any old copy.
     DeleteBackingImage(super_images.get(), "fake-super");
 
     // Create and map the fake super partition.
@@ -405,11 +467,10 @@
         std::cerr << "Could not map fake super partition\n";
         return 1;
     }
+    test_device->set_fake_super(fake_super);
 
     auto result = RUN_ALL_TESTS();
 
-    // Clean up again.
-    CleanupPartitions();
     DeleteBackingImage(super_images.get(), "fake-super");
 
     return result;
diff --git a/fs_mgr/libsnapshot/test_helpers.cpp b/fs_mgr/libsnapshot/test_helpers.cpp
index 17ffa4e..f67dd21 100644
--- a/fs_mgr/libsnapshot/test_helpers.cpp
+++ b/fs_mgr/libsnapshot/test_helpers.cpp
@@ -46,5 +46,12 @@
     return PartitionOpener::GetInfo(partition_name, info);
 }
 
+std::string TestPartitionOpener::GetDeviceString(const std::string& partition_name) const {
+    if (partition_name == "super") {
+        return fake_super_path_;
+    }
+    return PartitionOpener::GetDeviceString(partition_name);
+}
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/test_helpers.h b/fs_mgr/libsnapshot/test_helpers.h
index 9491be3..c87f118 100644
--- a/fs_mgr/libsnapshot/test_helpers.h
+++ b/fs_mgr/libsnapshot/test_helpers.h
@@ -25,18 +25,6 @@
 
 using namespace std::string_literals;
 
-class TestDeviceInfo : public SnapshotManager::IDeviceInfo {
-  public:
-    std::string GetGsidDir() const override { return "ota/test"s; }
-    std::string GetMetadataDir() const override { return "/metadata/ota/test"s; }
-    std::string GetSlotSuffix() const override { return slot_suffix_; }
-
-    void set_slot_suffix(const std::string& suffix) { slot_suffix_ = suffix; }
-
-  private:
-    std::string slot_suffix_ = "_a";
-};
-
 // Redirect requests for "super" to our fake super partition.
 class TestPartitionOpener final : public android::fs_mgr::PartitionOpener {
   public:
@@ -46,11 +34,33 @@
     android::base::unique_fd Open(const std::string& partition_name, int flags) const override;
     bool GetInfo(const std::string& partition_name,
                  android::fs_mgr::BlockDeviceInfo* info) const override;
+    std::string GetDeviceString(const std::string& partition_name) const override;
 
   private:
     std::string fake_super_path_;
 };
 
+class TestDeviceInfo : public SnapshotManager::IDeviceInfo {
+  public:
+    TestDeviceInfo() {}
+    explicit TestDeviceInfo(const std::string& fake_super) { set_fake_super(fake_super); }
+    std::string GetGsidDir() const override { return "ota/test"s; }
+    std::string GetMetadataDir() const override { return "/metadata/ota/test"s; }
+    std::string GetSlotSuffix() const override { return slot_suffix_; }
+    const android::fs_mgr::IPartitionOpener& GetPartitionOpener() const override {
+        return *opener_.get();
+    }
+
+    void set_slot_suffix(const std::string& suffix) { slot_suffix_ = suffix; }
+    void set_fake_super(const std::string& path) {
+        opener_ = std::make_unique<TestPartitionOpener>(path);
+    }
+
+  private:
+    std::string slot_suffix_ = "_a";
+    std::unique_ptr<TestPartitionOpener> opener_;
+};
+
 // Helper for error-spam-free cleanup.
 void DeleteBackingImage(android::fiemap::IImageManager* manager, const std::string& name);
 
diff --git a/healthd/api/charger_sysprop-current.txt b/healthd/api/charger_sysprop-current.txt
new file mode 100644
index 0000000..678c847
--- /dev/null
+++ b/healthd/api/charger_sysprop-current.txt
@@ -0,0 +1,29 @@
+props {
+  module: "android.sysprop.ChargerProperties"
+  prop {
+    api_name: "disable_init_blank"
+    scope: Internal
+    prop_name: "ro.charger.disable_init_blank"
+  }
+  prop {
+    api_name: "draw_split_offset"
+    type: Long
+    scope: Internal
+    prop_name: "ro.charger.draw_split_offset"
+  }
+  prop {
+    api_name: "draw_split_screen"
+    scope: Internal
+    prop_name: "ro.charger.draw_split_screen"
+  }
+  prop {
+    api_name: "enable_suspend"
+    scope: Internal
+    prop_name: "ro.charger.enable_suspend"
+  }
+  prop {
+    api_name: "no_ui"
+    scope: Internal
+    prop_name: "ro.charger.no_ui"
+  }
+}
diff --git a/healthd/api/charger_sysprop-latest.txt b/healthd/api/charger_sysprop-latest.txt
new file mode 100644
index 0000000..678c847
--- /dev/null
+++ b/healthd/api/charger_sysprop-latest.txt
@@ -0,0 +1,29 @@
+props {
+  module: "android.sysprop.ChargerProperties"
+  prop {
+    api_name: "disable_init_blank"
+    scope: Internal
+    prop_name: "ro.charger.disable_init_blank"
+  }
+  prop {
+    api_name: "draw_split_offset"
+    type: Long
+    scope: Internal
+    prop_name: "ro.charger.draw_split_offset"
+  }
+  prop {
+    api_name: "draw_split_screen"
+    scope: Internal
+    prop_name: "ro.charger.draw_split_screen"
+  }
+  prop {
+    api_name: "enable_suspend"
+    scope: Internal
+    prop_name: "ro.charger.enable_suspend"
+  }
+  prop {
+    api_name: "no_ui"
+    scope: Internal
+    prop_name: "ro.charger.no_ui"
+  }
+}
diff --git a/healthd/api/current.txt b/healthd/api/current.txt
deleted file mode 100644
index d802177..0000000
--- a/healthd/api/current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/healthd/api/removed.txt b/healthd/api/removed.txt
deleted file mode 100644
index d802177..0000000
--- a/healthd/api/removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/healthd/api/system-current.txt b/healthd/api/system-current.txt
deleted file mode 100644
index d802177..0000000
--- a/healthd/api/system-current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/healthd/api/system-removed.txt b/healthd/api/system-removed.txt
deleted file mode 100644
index d802177..0000000
--- a/healthd/api/system-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/healthd/api/test-current.txt b/healthd/api/test-current.txt
deleted file mode 100644
index d802177..0000000
--- a/healthd/api/test-current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/healthd/api/test-removed.txt b/healthd/api/test-removed.txt
deleted file mode 100644
index d802177..0000000
--- a/healthd/api/test-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/init/Android.bp b/init/Android.bp
index 285a6a4..37e359c 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -70,6 +70,7 @@
         "libprotobuf-cpp-lite",
         "libpropertyinfoserializer",
         "libpropertyinfoparser",
+        "libsnapshot_nobinder",
     ],
     shared_libs: [
         "libbacktrace",
@@ -117,6 +118,7 @@
         "firmware_handler.cpp",
         "first_stage_init.cpp",
         "first_stage_mount.cpp",
+        "fscrypt_init_extensions.cpp",
         "import_parser.cpp",
         "init.cpp",
         "interface_utils.cpp",
diff --git a/init/Android.mk b/init/Android.mk
index 006e1bf..d7258a7 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -114,6 +114,7 @@
     libbacktrace \
     libmodprobe \
     libext2_uuid \
+    libsnapshot_nobinder \
 
 LOCAL_SANITIZE := signed-integer-overflow
 # First stage init is weird: it may start without stdout/stderr, and no /proc.
diff --git a/init/builtins.cpp b/init/builtins.cpp
index e17e899..7c66de5 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -55,7 +55,6 @@
 #include <cutils/android_reboot.h>
 #include <fs_mgr.h>
 #include <fscrypt/fscrypt.h>
-#include <fscrypt/fscrypt_init_extensions.h>
 #include <libgsi/libgsi.h>
 #include <selinux/android.h>
 #include <selinux/label.h>
@@ -64,6 +63,7 @@
 
 #include "action_manager.h"
 #include "bootchart.h"
+#include "fscrypt_init_extensions.h"
 #include "init.h"
 #include "mount_namespace.h"
 #include "parser.h"
@@ -356,51 +356,64 @@
 // mkdir <path> [mode] [owner] [group]
 static Result<void> do_mkdir(const BuiltinArguments& args) {
     mode_t mode = 0755;
-    if (args.size() >= 3) {
-        mode = std::strtoul(args[2].c_str(), 0, 8);
-    }
+    Result<uid_t> uid = -1;
+    Result<gid_t> gid = -1;
 
-    if (!make_dir(args[1], mode)) {
-        /* chmod in case the directory already exists */
-        if (errno == EEXIST) {
-            if (fchmodat(AT_FDCWD, args[1].c_str(), mode, AT_SYMLINK_NOFOLLOW) == -1) {
-                return ErrnoError() << "fchmodat() failed";
-            }
-        } else {
-            return ErrnoErrorIgnoreEnoent() << "mkdir() failed";
-        }
-    }
-
-    if (args.size() >= 4) {
-        auto uid = DecodeUid(args[3]);
-        if (!uid) {
-            return Error() << "Unable to decode UID for '" << args[3] << "': " << uid.error();
-        }
-        Result<gid_t> gid = -1;
-
-        if (args.size() == 5) {
+    switch (args.size()) {
+        case 5:
             gid = DecodeUid(args[4]);
             if (!gid) {
                 return Error() << "Unable to decode GID for '" << args[4] << "': " << gid.error();
             }
-        }
-
-        if (lchown(args[1].c_str(), *uid, *gid) == -1) {
-            return ErrnoError() << "lchown failed";
-        }
-
-        /* chown may have cleared S_ISUID and S_ISGID, chmod again */
-        if (mode & (S_ISUID | S_ISGID)) {
-            if (fchmodat(AT_FDCWD, args[1].c_str(), mode, AT_SYMLINK_NOFOLLOW) == -1) {
-                return ErrnoError() << "fchmodat failed";
+            FALLTHROUGH_INTENDED;
+        case 4:
+            uid = DecodeUid(args[3]);
+            if (!uid) {
+                return Error() << "Unable to decode UID for '" << args[3] << "': " << uid.error();
             }
+            FALLTHROUGH_INTENDED;
+        case 3:
+            mode = std::strtoul(args[2].c_str(), 0, 8);
+            FALLTHROUGH_INTENDED;
+        case 2:
+            break;
+        default:
+            return Error() << "Unexpected argument count: " << args.size();
+    }
+    std::string target = args[1];
+    struct stat mstat;
+    if (lstat(target.c_str(), &mstat) != 0) {
+        if (errno != ENOENT) {
+            return ErrnoError() << "lstat() failed on " << target;
+        }
+        if (!make_dir(target, mode)) {
+            return ErrnoErrorIgnoreEnoent() << "mkdir() failed on " << target;
+        }
+        if (lstat(target.c_str(), &mstat) != 0) {
+            return ErrnoError() << "lstat() failed on new " << target;
         }
     }
-
+    if (!S_ISDIR(mstat.st_mode)) {
+        return Error() << "Not a directory on " << target;
+    }
+    bool needs_chmod = (mstat.st_mode & ~S_IFMT) != mode;
+    if ((*uid != static_cast<uid_t>(-1) && *uid != mstat.st_uid) ||
+        (*gid != static_cast<gid_t>(-1) && *gid != mstat.st_gid)) {
+        if (lchown(target.c_str(), *uid, *gid) == -1) {
+            return ErrnoError() << "lchown failed on " << target;
+        }
+        // chown may have cleared S_ISUID and S_ISGID, chmod again
+        needs_chmod = true;
+    }
+    if (needs_chmod) {
+        if (fchmodat(AT_FDCWD, target.c_str(), mode, AT_SYMLINK_NOFOLLOW) == -1) {
+            return ErrnoError() << "fchmodat() failed on " << target;
+        }
+    }
     if (fscrypt_is_native()) {
-        if (fscrypt_set_directory_policy(args[1].c_str())) {
+        if (fscrypt_set_directory_policy(target)) {
             return reboot_into_recovery(
-                {"--prompt_and_wipe_data", "--reason=set_policy_failed:"s + args[1]});
+                    {"--prompt_and_wipe_data", "--reason=set_policy_failed:"s + target});
         }
     }
     return {};
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index dffd6af..6b4216f 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -36,6 +36,7 @@
 #include <fs_mgr_overlayfs.h>
 #include <libgsi/libgsi.h>
 #include <liblp/liblp.h>
+#include <libsnapshot/snapshot.h>
 
 #include "devices.h"
 #include "switch_root.h"
@@ -55,6 +56,7 @@
 using android::fs_mgr::ReadDefaultFstab;
 using android::fs_mgr::ReadFstabFromDt;
 using android::fs_mgr::SkipMountingPartitions;
+using android::snapshot::SnapshotManager;
 
 using namespace std::literals;
 
@@ -244,8 +246,6 @@
 
     if (!InitDevices()) return false;
 
-    if (!CreateLogicalPartitions()) return false;
-
     if (!MountPartitions()) return false;
 
     return true;
@@ -366,6 +366,16 @@
         return false;
     }
 
+    if (SnapshotManager::IsSnapshotManagerNeeded()) {
+        auto sm = SnapshotManager::NewForFirstStageMount();
+        if (!sm) {
+            return false;
+        }
+        if (sm->NeedSnapshotsInFirstStageMount()) {
+            return sm->CreateLogicalAndSnapshotPartitions(lp_metadata_partition_);
+        }
+    }
+
     auto metadata = android::fs_mgr::ReadCurrentMetadata(lp_metadata_partition_);
     if (!metadata) {
         LOG(ERROR) << "Could not read logical partition metadata from " << lp_metadata_partition_;
@@ -493,14 +503,7 @@
 // this case, we mount system first then pivot to it.  From that point on,
 // we are effectively identical to a system-as-root device.
 bool FirstStageMount::TrySwitchSystemAsRoot() {
-    auto metadata_partition = std::find_if(fstab_.begin(), fstab_.end(), [](const auto& entry) {
-        return entry.mount_point == "/metadata";
-    });
-    if (metadata_partition != fstab_.end()) {
-        if (MountPartition(metadata_partition, true /* erase_same_mounts */)) {
-            UseGsiIfPresent();
-        }
-    }
+    UseGsiIfPresent();
 
     auto system_partition = std::find_if(fstab_.begin(), fstab_.end(), [](const auto& entry) {
         return entry.mount_point == "/system";
@@ -523,6 +526,17 @@
 }
 
 bool FirstStageMount::MountPartitions() {
+    // Mount /metadata before creating logical partitions, since we need to
+    // know whether a snapshot merge is in progress.
+    auto metadata_partition = std::find_if(fstab_.begin(), fstab_.end(), [](const auto& entry) {
+        return entry.mount_point == "/metadata";
+    });
+    if (metadata_partition != fstab_.end()) {
+        MountPartition(metadata_partition, true /* erase_same_mounts */);
+    }
+
+    if (!CreateLogicalPartitions()) return false;
+
     if (!TrySwitchSystemAsRoot()) return false;
 
     if (!SkipMountingPartitions(&fstab_)) return false;
diff --git a/init/fscrypt_init_extensions.cpp b/init/fscrypt_init_extensions.cpp
new file mode 100644
index 0000000..0f5a864
--- /dev/null
+++ b/init/fscrypt_init_extensions.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "fscrypt_init_extensions.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <fts.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <cutils/properties.h>
+#include <cutils/sockets.h>
+#include <fscrypt/fscrypt.h>
+#include <keyutils.h>
+#include <logwrap/logwrap.h>
+
+#define TAG "fscrypt"
+
+static int set_system_de_policy_on(const std::string& dir);
+
+int fscrypt_install_keyring() {
+    key_serial_t device_keyring = add_key("keyring", "fscrypt", 0, 0, KEY_SPEC_SESSION_KEYRING);
+
+    if (device_keyring == -1) {
+        PLOG(ERROR) << "Failed to create keyring";
+        return -1;
+    }
+
+    LOG(INFO) << "Keyring created with id " << device_keyring << " in process " << getpid();
+
+    return 0;
+}
+
+// TODO(b/139378601): use a single central implementation of this.
+static void delete_dir_contents(const std::string& dir) {
+    char* const paths[2] = {const_cast<char*>(dir.c_str()), nullptr};
+    FTS* fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr);
+    FTSENT* cur;
+    while ((cur = fts_read(fts)) != nullptr) {
+        if (cur->fts_info == FTS_ERR) {
+            PLOG(ERROR) << "fts_read";
+            break;
+        }
+        if (dir == cur->fts_path) {
+            continue;
+        }
+        switch (cur->fts_info) {
+            case FTS_D:
+                break;  // Ignore these
+            case FTS_DP:
+                if (rmdir(cur->fts_path) == -1) {
+                    PLOG(ERROR) << "rmdir " << cur->fts_path;
+                }
+                break;
+            default:
+                PLOG(ERROR) << "FTS unexpected type " << cur->fts_info << " at " << cur->fts_path;
+                if (rmdir(cur->fts_path) != -1) break;
+                // FALLTHRU (for gcc, lint, pcc, etc; and following for clang)
+                FALLTHROUGH_INTENDED;
+            case FTS_F:
+            case FTS_SL:
+            case FTS_SLNONE:
+                if (unlink(cur->fts_path) == -1) {
+                    PLOG(ERROR) << "unlink " << cur->fts_path;
+                }
+                break;
+        }
+    }
+
+    if (fts_close(fts) != 0) {
+        PLOG(ERROR) << "fts_close";
+    }
+}
+
+int fscrypt_set_directory_policy(const std::string& dir) {
+    const std::string prefix = "/data/";
+
+    if (!android::base::StartsWith(dir, prefix)) {
+        return 0;
+    }
+
+    // Special-case /data/media/obb per b/64566063
+    if (dir == "/data/media/obb") {
+        // Try to set policy on this directory, but if it is non-empty this may fail.
+        set_system_de_policy_on(dir);
+        return 0;
+    }
+
+    // Only set policy on first level /data directories
+    // To make this less restrictive, consider using a policy file.
+    // However this is overkill for as long as the policy is simply
+    // to apply a global policy to all /data folders created via makedir
+    if (dir.find_first_of('/', prefix.size()) != std::string::npos) {
+        return 0;
+    }
+
+    // Special case various directories that must not be encrypted,
+    // often because their subdirectories must be encrypted.
+    // This isn't a nice way to do this, see b/26641735
+    std::vector<std::string> directories_to_exclude = {
+        "lost+found",
+        "system_ce", "system_de",
+        "misc_ce", "misc_de",
+        "vendor_ce", "vendor_de",
+        "media",
+        "data", "user", "user_de",
+        "apex", "preloads", "app-staging",
+        "gsi",
+    };
+    for (const auto& d : directories_to_exclude) {
+        if ((prefix + d) == dir) {
+            LOG(INFO) << "Not setting policy on " << dir;
+            return 0;
+        }
+    }
+    int err = set_system_de_policy_on(dir);
+    if (err == 0) {
+        return 0;
+    }
+    // Empty these directories if policy setting fails.
+    std::vector<std::string> wipe_on_failure = {
+            "rollback", "rollback-observer",  // b/139193659
+    };
+    for (const auto& d : wipe_on_failure) {
+        if ((prefix + d) == dir) {
+            LOG(ERROR) << "Setting policy failed, deleting: " << dir;
+            delete_dir_contents(dir);
+            err = set_system_de_policy_on(dir);
+            break;
+        }
+    }
+    return err;
+}
+
+static int set_system_de_policy_on(const std::string& dir) {
+    std::string ref_filename = std::string("/data") + fscrypt_key_ref;
+    std::string policy;
+    if (!android::base::ReadFileToString(ref_filename, &policy)) {
+        LOG(ERROR) << "Unable to read system policy to set on " << dir;
+        return -1;
+    }
+
+    auto type_filename = std::string("/data") + fscrypt_key_mode;
+    std::string modestring;
+    if (!android::base::ReadFileToString(type_filename, &modestring)) {
+        LOG(ERROR) << "Cannot read mode";
+    }
+
+    std::vector<std::string> modes = android::base::Split(modestring, ":");
+
+    if (modes.size() < 1 || modes.size() > 2) {
+        LOG(ERROR) << "Invalid encryption mode string: " << modestring;
+        return -1;
+    }
+
+    LOG(INFO) << "Setting policy on " << dir;
+    int result =
+            fscrypt_policy_ensure(dir.c_str(), policy.c_str(), policy.length(), modes[0].c_str(),
+                                  modes.size() >= 2 ? modes[1].c_str() : "aes-256-cts");
+    if (result) {
+        LOG(ERROR) << android::base::StringPrintf("Setting %02x%02x%02x%02x policy on %s failed!",
+                                                  policy[0], policy[1], policy[2], policy[3],
+                                                  dir.c_str());
+        return -1;
+    }
+
+    return 0;
+}
diff --git a/init/fscrypt_init_extensions.h b/init/fscrypt_init_extensions.h
new file mode 100644
index 0000000..2163ef6
--- /dev/null
+++ b/init/fscrypt_init_extensions.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+
+int fscrypt_install_keyring();
+int fscrypt_set_directory_policy(const std::string& dir);
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 53d3ab3..c38d8cd 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -15,7 +15,6 @@
 //
 
 liblog_sources = [
-    "config_read.cpp",
     "config_write.cpp",
     "log_event_list.cpp",
     "log_event_write.cpp",
diff --git a/liblog/config_read.cpp b/liblog/config_read.cpp
deleted file mode 100644
index 3139f78..0000000
--- a/liblog/config_read.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <log/log_transport.h>
-
-#include "config_read.h"
-#include "logger.h"
-
-struct listnode __android_log_transport_read = {&__android_log_transport_read,
-                                                &__android_log_transport_read};
-struct listnode __android_log_persist_read = {&__android_log_persist_read,
-                                              &__android_log_persist_read};
-
-static void __android_log_add_transport(struct listnode* list,
-                                        struct android_log_transport_read* transport) {
-  uint32_t i;
-
-  /* Try to keep one functioning transport for each log buffer id */
-  for (i = LOG_ID_MIN; i < LOG_ID_MAX; i++) {
-    struct android_log_transport_read* transp;
-
-    if (list_empty(list)) {
-      if (!transport->available || ((*transport->available)(static_cast<log_id_t>(i)) >= 0)) {
-        list_add_tail(list, &transport->node);
-        return;
-      }
-    } else {
-      read_transport_for_each(transp, list) {
-        if (!transp->available) {
-          return;
-        }
-        if (((*transp->available)(static_cast<log_id_t>(i)) < 0) &&
-            (!transport->available || ((*transport->available)(static_cast<log_id_t>(i)) >= 0))) {
-          list_add_tail(list, &transport->node);
-          return;
-        }
-      }
-    }
-  }
-}
-
-void __android_log_config_read() {
-#if (FAKE_LOG_DEVICE == 0)
-  if ((__android_log_transport == LOGGER_DEFAULT) || (__android_log_transport & LOGGER_LOGD)) {
-    extern struct android_log_transport_read logdLoggerRead;
-    extern struct android_log_transport_read pmsgLoggerRead;
-
-    __android_log_add_transport(&__android_log_transport_read, &logdLoggerRead);
-    __android_log_add_transport(&__android_log_persist_read, &pmsgLoggerRead);
-  }
-#endif
-}
-
-void __android_log_config_read_close() {
-  struct android_log_transport_read* transport;
-  struct listnode* n;
-
-  read_transport_for_each_safe(transport, n, &__android_log_transport_read) {
-    list_remove(&transport->node);
-  }
-  read_transport_for_each_safe(transport, n, &__android_log_persist_read) {
-    list_remove(&transport->node);
-  }
-}
diff --git a/liblog/config_read.h b/liblog/config_read.h
deleted file mode 100644
index 212b8a0..0000000
--- a/liblog/config_read.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <cutils/list.h>
-
-#include "log_portability.h"
-
-__BEGIN_DECLS
-
-extern struct listnode __android_log_transport_read;
-extern struct listnode __android_log_persist_read;
-
-#define read_transport_for_each(transp, transports)                           \
-  for ((transp) = node_to_item((transports)->next,                            \
-                               struct android_log_transport_read, node);      \
-       ((transp) != node_to_item((transports),                                \
-                                 struct android_log_transport_read, node)) && \
-       ((transp) != node_to_item((transp)->node.next,                         \
-                                 struct android_log_transport_read, node));   \
-       (transp) = node_to_item((transp)->node.next,                           \
-                               struct android_log_transport_read, node))
-
-#define read_transport_for_each_safe(transp, n, transports)                   \
-  for ((transp) = node_to_item((transports)->next,                            \
-                               struct android_log_transport_read, node),      \
-      (n) = (transp)->node.next;                                              \
-       ((transp) != node_to_item((transports),                                \
-                                 struct android_log_transport_read, node)) && \
-       ((transp) !=                                                           \
-        node_to_item((n), struct android_log_transport_read, node));          \
-       (transp) = node_to_item((n), struct android_log_transport_read, node), \
-      (n) = (transp)->node.next)
-
-void __android_log_config_read();
-void __android_log_config_read_close();
-
-__END_DECLS
diff --git a/liblog/logd_reader.cpp b/liblog/logd_reader.cpp
index b7ba782..eba305f 100644
--- a/liblog/logd_reader.cpp
+++ b/liblog/logd_reader.cpp
@@ -35,7 +35,6 @@
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
-#include "config_read.h"
 #include "log_portability.h"
 #include "logd_reader.h"
 #include "logger.h"
diff --git a/liblog/logger.h b/liblog/logger.h
index accb6e7..4b4ef5f 100644
--- a/liblog/logger.h
+++ b/liblog/logger.h
@@ -95,9 +95,19 @@
                       size_t len);
 };
 
+struct android_log_transport_context {
+  union android_log_context_union context; /* zero init per-transport context */
+
+  struct android_log_transport_read* transport;
+  unsigned logMask;      /* mask of requested log buffers */
+  int ret;               /* return value associated with following data */
+  struct log_msg logMsg; /* peek at upcoming data, valid if logMsg.len != 0 */
+};
+
 struct android_log_logger_list {
   struct listnode logger;
-  struct listnode transport;
+  android_log_transport_context transport_context;
+  bool transport_initialized;
   int mode;
   unsigned int tail;
   log_time start;
@@ -111,27 +121,7 @@
   log_id_t logId;
 };
 
-struct android_log_transport_context {
-  struct listnode node;
-  union android_log_context_union context; /* zero init per-transport context */
-  struct android_log_logger_list* parent;
-
-  struct android_log_transport_read* transport;
-  unsigned logMask;      /* mask of requested log buffers */
-  int ret;               /* return value associated with following data */
-  struct log_msg logMsg; /* peek at upcoming data, valid if logMsg.len != 0 */
-};
-
 /* assumes caller has structures read-locked, single threaded, or fenced */
-#define transport_context_for_each(transp, logger_list)                          \
-  for ((transp) = node_to_item((logger_list)->transport.next,                    \
-                               struct android_log_transport_context, node);      \
-       ((transp) != node_to_item(&(logger_list)->transport,                      \
-                                 struct android_log_transport_context, node)) && \
-       ((transp)->parent == (logger_list));                                      \
-       (transp) = node_to_item((transp)->node.next,                              \
-                               struct android_log_transport_context, node))
-
 #define logger_for_each(logp, logger_list)                          \
   for ((logp) = node_to_item((logger_list)->logger.next,            \
                              struct android_log_logger, node);      \
diff --git a/liblog/logger_read.cpp b/liblog/logger_read.cpp
index 4cf0846..ff816b7 100644
--- a/liblog/logger_read.cpp
+++ b/liblog/logger_read.cpp
@@ -29,7 +29,6 @@
 #include <cutils/list.h>
 #include <private/android_filesystem_config.h>
 
-#include "config_read.h"
 #include "log_portability.h"
 #include "logger.h"
 
@@ -55,9 +54,6 @@
 }
 
 static int init_transport_context(struct android_log_logger_list* logger_list) {
-  struct android_log_transport_read* transport;
-  struct listnode* node;
-
   if (!logger_list) {
     return -EINVAL;
   }
@@ -66,77 +62,63 @@
     return -EINVAL;
   }
 
-  if (!list_empty(&logger_list->transport)) {
+  if (logger_list->transport_initialized) {
     return 0;
   }
 
-  __android_log_lock();
-  /* mini __write_to_log_initialize() to populate transports */
-  if (list_empty(&__android_log_transport_read) && list_empty(&__android_log_persist_read)) {
-    __android_log_config_read();
-  }
-  __android_log_unlock();
+#if (FAKE_LOG_DEVICE == 0)
+  extern struct android_log_transport_read logdLoggerRead;
+  extern struct android_log_transport_read pmsgLoggerRead;
 
-  node = (logger_list->mode & ANDROID_LOG_PSTORE) ? &__android_log_persist_read
-                                                  : &__android_log_transport_read;
+  struct android_log_transport_read* transport;
+  transport = (logger_list->mode & ANDROID_LOG_PSTORE) ? &pmsgLoggerRead : &logdLoggerRead;
 
-  read_transport_for_each(transport, node) {
-    struct android_log_transport_context* transp;
-    struct android_log_logger* logger;
-    unsigned logMask = 0;
+  struct android_log_logger* logger;
+  unsigned logMask = 0;
 
-    logger_for_each(logger, logger_list) {
-      log_id_t logId = logger->logId;
+  logger_for_each(logger, logger_list) {
+    log_id_t logId = logger->logId;
 
-      if ((logId == LOG_ID_SECURITY) && (__android_log_uid() != AID_SYSTEM)) {
-        continue;
-      }
-      if (transport->read && (!transport->available || (transport->available(logId) >= 0))) {
-        logMask |= 1 << logId;
-      }
-    }
-    if (!logMask) {
+    if (logId == LOG_ID_SECURITY && __android_log_uid() != AID_SYSTEM) {
       continue;
     }
-    transp = static_cast<android_log_transport_context*>(calloc(1, sizeof(*transp)));
-    if (!transp) {
-      return -ENOMEM;
+    if (transport->read && (!transport->available || transport->available(logId) >= 0)) {
+      logMask |= 1 << logId;
     }
-    transp->parent = logger_list;
-    transp->transport = transport;
-    transp->logMask = logMask;
-    transp->ret = 1;
-    list_add_tail(&logger_list->transport, &transp->node);
   }
-  if (list_empty(&logger_list->transport)) {
+  if (!logMask) {
     return -ENODEV;
   }
+
+  logger_list->transport_context.transport = transport;
+  logger_list->transport_context.logMask = logMask;
+  logger_list->transport_context.ret = 1;
+#endif
   return 0;
 }
 
-#define LOGGER_FUNCTION(logger, def, func, args...)                                  \
-  ssize_t ret = -EINVAL;                                                             \
-  struct android_log_transport_context* transp;                                      \
-  struct android_log_logger* logger_internal = (struct android_log_logger*)(logger); \
-                                                                                     \
-  if (!logger_internal) {                                                            \
-    return ret;                                                                      \
-  }                                                                                  \
-  ret = init_transport_context(logger_internal->parent);                             \
-  if (ret < 0) {                                                                     \
-    return ret;                                                                      \
-  }                                                                                  \
-                                                                                     \
-  ret = (def);                                                                       \
-  transport_context_for_each(transp, logger_internal->parent) {                      \
-    if ((transp->logMask & (1 << logger_internal->logId)) && transp->transport &&    \
-        transp->transport->func) {                                                   \
-      ssize_t retval = (transp->transport->func)(logger_internal, transp, ##args);   \
-      if ((ret >= 0) || (ret == (def))) {                                            \
-        ret = retval;                                                                \
-      }                                                                              \
-    }                                                                                \
-  }                                                                                  \
+#define LOGGER_FUNCTION(logger, def, func, args...)                                               \
+  ssize_t ret = -EINVAL;                                                                          \
+  android_log_logger* logger_internal = reinterpret_cast<android_log_logger*>(logger);            \
+                                                                                                  \
+  if (!logger_internal) {                                                                         \
+    return ret;                                                                                   \
+  }                                                                                               \
+  ret = init_transport_context(logger_internal->parent);                                          \
+  if (ret < 0) {                                                                                  \
+    return ret;                                                                                   \
+  }                                                                                               \
+                                                                                                  \
+  ret = (def);                                                                                    \
+  android_log_transport_context* transport_context = &logger_internal->parent->transport_context; \
+  if (transport_context->logMask & (1 << logger_internal->logId) &&                               \
+      transport_context->transport && transport_context->transport->func) {                       \
+    ssize_t retval =                                                                              \
+        (transport_context->transport->func)(logger_internal, transport_context, ##args);         \
+    if (ret >= 0 || ret == (def)) {                                                               \
+      ret = retval;                                                                               \
+    }                                                                                             \
+  }                                                                                               \
   return ret
 
 int android_logger_clear(struct logger* logger) {
@@ -167,25 +149,24 @@
   LOGGER_FUNCTION(logger, 4, version);
 }
 
-#define LOGGER_LIST_FUNCTION(logger_list, def, func, args...)                           \
-  struct android_log_transport_context* transp;                                         \
-  struct android_log_logger_list* logger_list_internal =                                \
-      (struct android_log_logger_list*)(logger_list);                                   \
-                                                                                        \
-  ssize_t ret = init_transport_context(logger_list_internal);                           \
-  if (ret < 0) {                                                                        \
-    return ret;                                                                         \
-  }                                                                                     \
-                                                                                        \
-  ret = (def);                                                                          \
-  transport_context_for_each(transp, logger_list_internal) {                            \
-    if (transp->transport && (transp->transport->func)) {                               \
-      ssize_t retval = (transp->transport->func)(logger_list_internal, transp, ##args); \
-      if ((ret >= 0) || (ret == (def))) {                                               \
-        ret = retval;                                                                   \
-      }                                                                                 \
-    }                                                                                   \
-  }                                                                                     \
+#define LOGGER_LIST_FUNCTION(logger_list, def, func, args...)                                  \
+  android_log_logger_list* logger_list_internal =                                              \
+      reinterpret_cast<android_log_logger_list*>(logger_list);                                 \
+                                                                                               \
+  ssize_t ret = init_transport_context(logger_list_internal);                                  \
+  if (ret < 0) {                                                                               \
+    return ret;                                                                                \
+  }                                                                                            \
+                                                                                               \
+  ret = (def);                                                                                 \
+  android_log_transport_context* transport_context = &logger_list_internal->transport_context; \
+  if (transport_context->transport && transport_context->transport->func) {                    \
+    ssize_t retval =                                                                           \
+        (transport_context->transport->func)(logger_list_internal, transport_context, ##args); \
+    if (ret >= 0 || ret == (def)) {                                                            \
+      ret = retval;                                                                            \
+    }                                                                                          \
+  }                                                                                            \
   return ret
 
 /*
@@ -212,7 +193,6 @@
   }
 
   list_init(&logger_list->logger);
-  list_init(&logger_list->transport);
   logger_list->mode = mode;
   logger_list->tail = tail;
   logger_list->pid = pid;
@@ -229,7 +209,6 @@
   }
 
   list_init(&logger_list->logger);
-  list_init(&logger_list->transport);
   logger_list->mode = mode;
   logger_list->start = start;
   logger_list->pid = pid;
@@ -247,38 +226,27 @@
   struct android_log_logger* logger;
 
   if (!logger_list_internal || (logId >= LOG_ID_MAX)) {
-    goto err;
+    return nullptr;
   }
 
   logger_for_each(logger, logger_list_internal) {
     if (logger->logId == logId) {
-      goto ok;
+      return reinterpret_cast<struct logger*>(logger);
     }
   }
 
   logger = static_cast<android_log_logger*>(calloc(1, sizeof(*logger)));
   if (!logger) {
-    goto err;
+    return nullptr;
   }
 
   logger->logId = logId;
   list_add_tail(&logger_list_internal->logger, &logger->node);
   logger->parent = logger_list_internal;
 
-  /* Reset known transports to re-evaluate, we just added one */
-  while (!list_empty(&logger_list_internal->transport)) {
-    struct listnode* node = list_head(&logger_list_internal->transport);
-    struct android_log_transport_context* transp =
-        node_to_item(node, struct android_log_transport_context, node);
+  // Reset known transport to re-evaluate, since we added a new logger.
+  logger_list_internal->transport_initialized = false;
 
-    list_remove(&transp->node);
-    free(transp);
-  }
-  goto ok;
-
-err:
-  logger = NULL;
-ok:
   return (struct logger*)logger;
 }
 
@@ -340,7 +308,6 @@
 
 /* Read from the selected logs */
 int android_logger_list_read(struct logger_list* logger_list, struct log_msg* log_msg) {
-  struct android_log_transport_context* transp;
   struct android_log_logger_list* logger_list_internal =
       (struct android_log_logger_list*)logger_list;
 
@@ -349,84 +316,8 @@
     return ret;
   }
 
-  /* at least one transport */
-  transp = node_to_item(logger_list_internal->transport.next, struct android_log_transport_context,
-                        node);
-
-  /* more than one transport? */
-  if (transp->node.next != &logger_list_internal->transport) {
-    /* Poll and merge sort the entries if from multiple transports */
-    struct android_log_transport_context* oldest = NULL;
-    int ret;
-    int polled = 0;
-    do {
-      if (polled) {
-        sched_yield();
-      }
-      ret = -1000;
-      polled = 0;
-      do {
-        int retval = transp->ret;
-        if ((retval > 0) && !transp->logMsg.entry.len) {
-          if (!transp->transport->read) {
-            retval = transp->ret = 0;
-          } else if ((logger_list_internal->mode & ANDROID_LOG_NONBLOCK) ||
-                     !transp->transport->poll) {
-            retval = android_transport_read(logger_list_internal, transp, &transp->logMsg);
-          } else {
-            int pollval = (*transp->transport->poll)(logger_list_internal, transp);
-            if (pollval <= 0) {
-              sched_yield();
-              pollval = (*transp->transport->poll)(logger_list_internal, transp);
-            }
-            polled = 1;
-            if (pollval < 0) {
-              if ((pollval == -EINTR) || (pollval == -EAGAIN)) {
-                return -EAGAIN;
-              }
-              retval = transp->ret = pollval;
-            } else if (pollval > 0) {
-              retval = android_transport_read(logger_list_internal, transp, &transp->logMsg);
-            }
-          }
-        }
-        if (ret < retval) {
-          ret = retval;
-        }
-        if ((transp->ret > 0) && transp->logMsg.entry.len &&
-            (!oldest || (oldest->logMsg.entry.sec > transp->logMsg.entry.sec) ||
-             ((oldest->logMsg.entry.sec == transp->logMsg.entry.sec) &&
-              (oldest->logMsg.entry.nsec > transp->logMsg.entry.nsec)))) {
-          oldest = transp;
-        }
-        transp = node_to_item(transp->node.next, struct android_log_transport_context, node);
-      } while (transp != node_to_item(&logger_list_internal->transport,
-                                      struct android_log_transport_context, node));
-      if (!oldest && (logger_list_internal->mode & ANDROID_LOG_NONBLOCK)) {
-        return (ret < 0) ? ret : -EAGAIN;
-      }
-      transp = node_to_item(logger_list_internal->transport.next,
-                            struct android_log_transport_context, node);
-    } while (!oldest && (ret > 0));
-    if (!oldest) {
-      return ret;
-    }
-    // ret is a positive value less than sizeof(struct log_msg)
-    ret = oldest->ret;
-    if (ret < oldest->logMsg.entry.hdr_size) {
-      // zero truncated header fields.
-      memset(
-          log_msg, 0,
-          (oldest->logMsg.entry.hdr_size > sizeof(oldest->logMsg) ? sizeof(oldest->logMsg)
-                                                                  : oldest->logMsg.entry.hdr_size));
-    }
-    memcpy(log_msg, &oldest->logMsg, ret);
-    oldest->logMsg.entry.len = 0; /* Mark it as copied */
-    return ret;
-  }
-
-  /* if only one, no need to copy into transport_context and merge-sort */
-  return android_transport_read(logger_list_internal, transp, log_msg);
+  android_log_transport_context* transport_context = &logger_list_internal->transport_context;
+  return android_transport_read(logger_list_internal, transport_context, log_msg);
 }
 
 /* Close all the logs */
@@ -438,16 +329,10 @@
     return;
   }
 
-  while (!list_empty(&logger_list_internal->transport)) {
-    struct listnode* node = list_head(&logger_list_internal->transport);
-    struct android_log_transport_context* transp =
-        node_to_item(node, struct android_log_transport_context, node);
+  android_log_transport_context* transport_context = &logger_list_internal->transport_context;
 
-    if (transp->transport && transp->transport->close) {
-      (*transp->transport->close)(logger_list_internal, transp);
-    }
-    list_remove(&transp->node);
-    free(transp);
+  if (transport_context->transport && transport_context->transport->close) {
+    (*transport_context->transport->close)(logger_list_internal, transport_context);
   }
 
   while (!list_empty(&logger_list_internal->logger)) {
diff --git a/liblog/logger_write.cpp b/liblog/logger_write.cpp
index a4b3cd7..4fbab4b 100644
--- a/liblog/logger_write.cpp
+++ b/liblog/logger_write.cpp
@@ -29,7 +29,6 @@
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
-#include "config_read.h" /* __android_log_config_read_close() definition */
 #include "config_write.h"
 #include "log_portability.h"
 #include "logger.h"
@@ -624,7 +623,6 @@
   if (__android_log_transport != transport_flag) {
     __android_log_transport = transport_flag;
     __android_log_config_write_close();
-    __android_log_config_read_close();
 
     write_to_log = __write_to_log_init;
     /* generically we only expect these two values for write_to_log */
diff --git a/liblog/pmsg_reader.cpp b/liblog/pmsg_reader.cpp
index eaac97f..81563bc 100644
--- a/liblog/pmsg_reader.cpp
+++ b/liblog/pmsg_reader.cpp
@@ -24,7 +24,6 @@
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
-#include "config_read.h"
 #include "logger.h"
 
 static int pmsgAvailable(log_id_t logId);
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index d931ed1..45a9bc9 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -1062,6 +1062,7 @@
 when you depart from me, sorrow abides and happiness\n\
 takes his leave.";
 
+#ifdef USING_LOGGER_DEFAULT
 TEST(liblog, max_payload) {
 #ifdef TEST_PREFIX
   TEST_PREFIX
@@ -1130,6 +1131,7 @@
   GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif
 }
+#endif
 
 TEST(liblog, __android_log_buf_print__maxtag) {
 #ifdef TEST_PREFIX
@@ -1271,6 +1273,7 @@
 #endif
 }
 
+#ifdef USING_LOGGER_DEFAULT
 TEST(liblog, dual_reader) {
 #ifdef TEST_PREFIX
   TEST_PREFIX
@@ -1334,6 +1337,7 @@
   GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif
 }
+#endif
 
 #ifdef USING_LOGGER_DEFAULT  // Do not retest logprint
 static bool checkPriForTag(AndroidLogFormat* p_format, const char* tag,
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 9b0075d..0f61a61 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -618,6 +618,9 @@
     mkdir /data/cache/backup_stage 0700 system system
     mkdir /data/cache/backup 0700 system system
 
+    mkdir /data/rollback 0700 system system
+    mkdir /data/rollback-observer 0700 system system
+
     # Wait for apexd to finish activating APEXes before starting more processes.
     wait_for_prop apexd.status ready
     parse_apex_configs